使用 CircleCI 的 Orbs 进行并行处理
本文是CircleCI Advent Calendar 2018第三天的文章。
上一篇文章是由@yasuhiroki撰写的,题为「即使将CircleCI的Only build pull requests关闭,我仍然想要在创建Pull Request时执行Job」。
首先
在这篇文章中进行解释的事情
-
- CircleCIの並列処理の基本的なやり方
- CI/CDの処理時間を短縮する方法
在这篇文章中不要解释的事情
-
- Ansibleの使い方
-
- CircleCIの使い方
-
- Dockerの使い方
- Orbsの解説、導入方法
这篇文章想要表达的意思是
-
- Orbsを利用してパイプラインの再利用性を高めましょう
-
- Orbsに定義出来ない処理、もしくはOrbsで定義すると再利用が難しくなる処理は「.circleci/config.yml」へ書きましょう
-
- CircleCIで処理する必要がないものはあらかじめDockerイメージ化しレジストリへ登録しておきましょう(スナップショットの作成)
- CircleCIで利用する独自のDockerイメージはcron等を用いて頻繁にアップデートしましょう(スナップショットのリフレッシュ)
Ansible是什么?
Ansible(安得泊)是一款由红帽公司开发的开源配置管理工具。在启动服务器时,可以根据预先准备好的配置文件自动执行软件的安装和设置。特别适用于构建大规模计算机集群,有助于缩短时间并减少错误。除了配置管理外,还具备编排和软件部署功能。
引用自Ansible(软件)- 维基百科
关于Ansible需要注意的事项
Ansible通常被用于操作系统和网络设备。如果像本文所述在Docker中使用,无法百分百发挥Ansible的性能。
这篇文章只是拿CircleCI作为并行处理的例子来进行解释。
请确保在使用Ansible时使用操作系统环境而不是Docker。
场景
1. 目标
使用多个不同的发行版以及多个不同版本的Ansible来进行编程安装操作的持续集成。
为了加快CI/CD的速度,利用操作系统镜像的“快照”,并进行“并行处理”。
处理的流程
-
- 获取Playbook
-
- 进行静态解析(运行lint)
- 执行Playbook
希望选择发行版本
-
- CentOS7
- Ubuntu18
使用 Ansible 的版本
-
- 2.7系(aptもしくはyumコマンドでインストールされるAnsible)
-
- 2.7系(pipコマンドでインストールされるAnsible)
- 2.8系
我们将进行6个并行处理,其中包括2个分发系统和3个Ansible系统。
安装程序
- cowsay – Wikipedia
使用Ansible编排剧本。
- TomonoriMatsumura/ansible_joke-programs_cowsay | GitHub
准备工作是将Docker镜像注册到注册服务中。
为了加快CI/CD的速度,我们会先创建一个操作系统镜像的快照。
创建Dockerfile
预先安装了「CentOS7」和「Ubuntu18」。
或者:
事先在「CentOS7」和「Ubuntu18」上安装了。
-
- Ansible
-
- Ansible-lint
- Git
创建并注册包含已安装Docker镜像的仓库。
以下是安装Ansible、Ansible-lint、Git到CentOS7的Dockerfile示例:
从 centos:latest 派生RUN set -x && \
rm -f /etc/rpm/macros.image-language-conf && \
sed -i ‘/^override_install_langs=/d’ /etc/yum.conf && \
yum -y reinstall glibc-common && \
yum clean all && \
yum update -y && \
yum install -y epel-release git && \
yum -y install ansible && \
yum -y install expect python-devel python-pip && \
pip install –upgrade pip && pip install –upgrade setuptools && \
pip install ansible-lint
ENV LANG=”ja_JP.UTF-8″ \
LANGUAGE=”ja_JP:ja” \
LC_ALL=”ja_JP.UTF-8″
以下是一份安装Ansible、Ansible-lint和Git到Ubuntu18的Dockerfile示例。
从ubuntu:latest镜像中构建运行apt update -y命令,并安装language-pack-ja-base和language-pack-ja语言包
运行apt install -y software-properties-common命令
运行apt-add-repository -y ppa:ansible/ansible命令
运行apt update -y命令,并安装ansible
运行apt install -y curl python-dev git命令
从”https://bootstrap.pypa.io/get-pip.py”网址下载到”/tmp/get-pip.py”路径下
运行python /tmp/get-pip.py命令
运行pip install –upgrade pip命令并升级pip
运行pip install –upgrade setuptools命令并升级setuptools
运行pip install ansible-lint命令
设置环境变量LANG为”ja_JP.UTF-8″
设置环境变量LANGUAGE为”ja_JP:ja”
设置环境变量LC_ALL为”ja_JP.UTF-8″
将Docker镜像注册到Docker Hub。
在这篇文章中,我们将使用Docker Hub来管理注册表。
Docker Hub 提供了将 Dockerfile 推送到 GitHub 后自动构建 Docker 镜像的服务。
因此
-
- 記事等で利用する
- OSSの活動で利用する
如果你想要披露所创建的Docker镜像的内容,这将是一个有用的工具。
使用Docker镜像
-
- tomonorimatsumura/centos7-ansible – Docker Hub
- tomonorimatsumura/ubuntu18-ansible – Docker Hub
创建Ansible Playbook
我将使用这本Playbook。
Ansible Playbook 中定义了以下操作。
-
- 获取执行Playbook的Docker容器的发行版信息。
- 根据发行版选择并执行适当的处理。
- hosts: all
tasks:
- name: Install cowsay with yum
include_role:
name: centos7
when: ansible_distribution == "CentOS"
- name: Install cowsay with apt
include_role:
name: ubuntu18
when: ansible_distribution == "Ubuntu"
- name: Install cowsay with yum
become: yes
yum:
name: cowsay
state: present
- name: Install cowsay with apt
become: yes
apt:
name: cowsay
state: present
- name: Copy cowsay execution file to '/usr/local/bin/'
become: yes
copy:
src: /usr/games/cowsay
dest: /usr/local/bin/cowsay
owner: root
group: root
mode: 0755
创建一个orb
在这篇文章中,我们将使用 CircleCI 2.1 引入的 Orbs,这将全面可用。
有关 orb 的处理
version: 2.1
commands:
show-os-version:
description: "Show OS version information"
steps:
- run:
name: Show OS version
command: |
if [ -e /etc/os-release ]; then
cat /etc/os-release
elif [ -e /etc/redhat-release ]; then
cat /etc/redhat-release
else
echo 'Invalid Image' 1>&2
exit 1
fi
ansible-lint:
description: "Execute ansible-lint command"
steps:
- run:
name: Show ansible-lint version
command: ansible-lint --version
- run:
name: Retrieve Ansible lint rules file
command: |
cd /tmp
git clone https://github.com/TomonoriMatsumura/ansible_joke-programs_lint-rules
- run:
name: Execute ansible-lint
command: |
cd $CIRCLE_WORKING_DIRECTORY
find . -type f -name '*.yml' | xargs ansible-lint -c /tmp/ansible_joke-programs_lint-rules/.ansible-lint-rules
ansible-playbook:
description: "Execute ansible-playbook command"
steps:
- run:
name: Show Ansible version
command: ansible --version
- run:
name: Execute Ansible Playbook
command: |
cd $CIRCLE_WORKING_DIRECTORY
ansible-playbook -i localhost install.yml
- run:
name: Execute Ansible Playbook again, checking to make sure it's idempotent.
command: |
cd $CIRCLE_WORKING_DIRECTORY
ansible-playbook -i localhost install.yml
executors:
centos7-ansible-yum:
docker:
- image: tomonorimatsumura/centos7-ansible:yum
centos7-ansible-stable:
docker:
- image: tomonorimatsumura/centos7-ansible:stable
centos7-ansible-devel:
docker:
- image: tomonorimatsumura/centos7-ansible:devel
ubuntu18-ansible-apt:
docker:
- image: tomonorimatsumura/ubuntu18-ansible:apt
ubuntu18-ansible-stable:
docker:
- image: tomonorimatsumura/ubuntu18-ansible:stable
ubuntu18-ansible-devel:
docker:
- image: tomonorimatsumura/ubuntu18-ansible:devel
我们将在orb中定义以下处理程序。
-
- 显示所使用Docker镜像的发布信息
-
- 使用Ansible-lint检查Playbook的语法
- 执行Playbook
这是”commands”部分的内容。
-
- 显示操作系统版本
-
- 检查ansible配置的问题
- 运行ansible剧本
每个都有对应的解决办法。
在executor部分定义了Docker镜像。
创建.circleci/config.yml文件
show-os-version-steps: &show-os-version-steps
steps:
- ansible/show-os-version
lint-steps: &lint-steps
steps:
- checkout
- ansible/ansible-lint
playbook-steps: &playbook-steps
steps:
- checkout
- ansible/ansible-playbook
- run:
name: Execute cowsay
command: |
export TERM=xterm
cowsay "hello world!"
version: 2.1
orbs:
ansible: orbss/ansible@volatile
jobs:
Ce7-yum_os-version:
executor:
name: ansible/centos7-ansible-yum
<<: *show-os-version-steps
Ce7-yum_lint:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-yum
<<: *lint-steps
Ce7-yum_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-yum
<<: *playbook-steps
Ce7-stable_os-version:
executor:
name: ansible/centos7-ansible-stable
<<: *show-os-version-steps
Ce7-stable_lint:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-stable
<<: *lint-steps
Ce7-stable_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-stable
<<: *playbook-steps
Ce7-devel_os-version:
executor:
name: ansible/centos7-ansible-devel
<<: *show-os-version-steps
Ce7-devel_lint:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-devel
<<: *lint-steps
Ce7-devel_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/centos7-ansible-devel
<<: *playbook-steps
Ub18-apt_os-version:
executor:
name: ansible/ubuntu18-ansible-apt
<<: *show-os-version-steps
Ub18-apt_lint:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-apt
<<: *lint-steps
Ub18-apt_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-apt
<<: *playbook-steps
Ub18-stable_os-version:
executor:
name: ansible/ubuntu18-ansible-stable
<<: *show-os-version-steps
Ub18-stable_lint:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-stable
<<: *lint-steps
Ub18-stable_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-stable
<<: *playbook-steps
Ub18-devel_os-version:
executor:
name: ansible/ubuntu18-ansible-devel
<<: *show-os-version-steps
Ub18-devel_lint:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-devel
<<: *lint-steps
Ub18-devel_playbook:
working_directory: /tmp/ansible
executor:
name: ansible/ubuntu18-ansible-devel
<<: *playbook-steps
workflows:
version: 2
ansible-playbook:
jobs:
- Ce7-yum_os-version
- Ce7-yum_lint:
requires:
- Ce7-yum_os-version
- Ce7-yum_playbook:
requires:
- Ce7-yum_lint
- Ce7-stable_os-version
- Ce7-stable_lint:
requires:
- Ce7-stable_os-version
- Ce7-stable_playbook:
requires:
- Ce7-stable_lint
- Ce7-devel_os-version
- Ce7-devel_lint:
requires:
- Ce7-devel_os-version
- Ce7-devel_playbook:
requires:
- Ce7-devel_lint
- Ub18-apt_os-version
- Ub18-apt_lint:
requires:
- Ub18-apt_os-version
- Ub18-apt_playbook:
requires:
- Ub18-apt_lint
- Ub18-stable_os-version
- Ub18-stable_lint:
requires:
- Ub18-stable_os-version
- Ub18-stable_playbook:
requires:
- Ub18-stable_lint
- Ub18-devel_os-version
- Ub18-devel_lint:
requires:
- Ub18-devel_os-version
- Ub18-devel_playbook:
requires:
- Ub18-devel_lint
关于锚点和别名
表上的描述是指「.circleci/config.yml」中可用的Anchors & Aliases功能。您可以在定义锚点后将别名指定到特定位置。
请参考这个链接了解更详细的情况。
在工作流中并行执行作业
在工作流程(workflows)部分,我们编写处理代码以使每个作业(Job)并行执行。有关在CircleCI中定义作业执行顺序的详细方法,请参考此链接。
关于使用的ORB版本
在Orbs中,可以通过”circleci/config.yml”来指定orb的版本。然而,在这篇文章中,我们始终使用”volatile”来获取最新版本。
在实际使用Orbs时,有时候指定特定版本号而不是最新版本可能更好。对于版本的指定描述,最好根据需要灵活使用。
总结
我介绍了在CircleCI中并行运行CI的方法。通过使用这种方法,您可以使用不同版本的Ruby + Rails或者PHP + Laravel并行处理验证,这样就可以进行验证了。
也许可以考虑开发能够兼容框架和语言版本的选项。
CircleCI的并发处理要点。
-
- Orbsを利用してパイプラインの再利用性を高める
-
- Orbsに定義出来ない処理、もしくはOrbsで定義すると再利用が難しくなる処理は「.circleci/config.yml」へ書く
-
- CircleCIで処理する必要がないものはあらかじめDockerイメージ化しレジストリへ登録する(スナップショットの作成)
- CircleCIで利用する独自のDockerイメージはcron等を用いて頻繁にアップデートする(スナップショットのリフレッシュ)
我认为您应该意识到这一点。特别是包含容器的操作系统镜像快照会对CI/CD的速度产生重大影响,仅次于并行处理。快照应该有意识地采用。
未来的挑战
並列處理報告的問題
这次使用的「.circleci/config.yml」有一个问题。问题是并行处理时无法指定执行Job的顺序。
理想的的流程线路
实际的管道
我想将流水线以线性方式显示,但是 CircleCI 似乎会按照处理顺序显示作业?因此会输出与我期望的不同的内容。
希望能够改善这种行为,但目前不知道方法。
请参考以下链接
安装
-
- Ansible (ソフトウェア) – Wikipedia
-
- Ansible is Simple IT Automation
- TomonoriMatsumura/ansible_joke-programs_cowsay | GitHub
CircleCI 循环CI
关于Orbs
- Creating Orbs – CircleCI
关于 Anchor & Aliases
- YAML – config.yml | CircleCI
关于并行处理
- Using Workflows to Schedule Jobs – CircleCI
新闻报道的验证
- この記事のレポート
牛说
- cowsay – Wikipedia
Docker 镜像仓库
-
- Docker Hub
-
- Docker HubでDockerfileを公開する AUTOMATED BUILD – Qiita
-
- tomonorimatsumura/centos7-ansible – Docker Hub
- tomonorimatsumura/ubuntu18-ansible – Docker Hub
结果
明天的 CircleCI 年度日历2018文章将由 @ganta 先生负责。