Ansible での provisioning を継続的にインテグレーションしたいので circleci で Docker を使う
あらすじ
Provisioning を継続インテグレーションしたくなったのですが、そんな時は CircleCI で Docker を使えばいいんじゃないかと思いました。
コンテナ内で ServerSpec を実行する方法などがあると思いますが、ここではコンテナ内に SSHD を使って外部からプロビジョンします。
テストに関しては Serverspec などがあると思いますが、ここではシンプルに 外部から SSH でコマンドを実行して結果の確認をするだけにします。
ソースコード
ここで紹介しているソースコードは下記の置いてあります。
準備
mkdir circleci-docker-provisioning && cd $_ mkdir -p keys provisioning/inventory provisioning/roles/nodejs/tasks touch .gitignore Makefile Dockerfile circle.yml touch provisioning/playbook.yml provisioning/inventory/docker provisioning/roles/nodejs/tasks/main.yml keys/.gitkeep
keys/* に公開鍵と秘密鍵を保存します。あくまで CI 用の鍵なので git で管理しても問題無いのですが、万が一これを見て秘密鍵を github.com で公開している事を心配する人がいるかもしれないので一応このようにします。
create .gitignore
keys/* !.gitkeep
とりあえず commit します。
git init && git add . && git commit -m "initial commit"
秘密鍵と公開鍵を作成
パスワード無しで作成します。keys/docker_id_rsa と keys/docker_id_rsa.pub が生成されます。
ssh-keygen -P "" -f keys/docker_id_rsa
Dockerfile
通常は Docker コンテナーに SSHD を入れないのですがここでは SSHD でのプロビジョニングを行いたいのでこのようにしています。
Docker に ansible をマウントして Ansible を local connection してテストする方法もありますが今回はこのようにしています。
create Dockerfile
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y sudo openssh-server python RUN mkdir -p /var/run/sshd RUN useradd -m -d /home/docker -s /bin/bash docker RUN echo "docker:docker" | chpasswd RUN mkdir /home/docker/.ssh RUN chmod 700 /home/docker/.ssh COPY ./keys/docker_id_rsa.pub /home/docker/.ssh/authorized_keys RUN chmod 600 /home/docker/.ssh/authorized_keys RUN chown -R docker:docker /home/docker/.ssh RUN echo "docker ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers EXPOSE 22 CMD ["/usr/sbin/sshd", "-D"]
Build
docker build -t provisioning_sshd .
Run
docker run -d -p 40122:22 --name test_sshd provisioning_sshd
ssh で接続確認をします。
ssh docker@localhost -p 40122 -i keys/docker_id_rsa
Ansible
とりあえず Node.js をインストールしてみます。
create provisioning/inventory/docker
docker ansible_user=docker ansible_port=40122 ansible_host=localhost ansible_ssh_private_key_file=./keys/docker_id_rsa
create provisioning/roles/nodejs/tasks/main.yml
---
- name: install Node.js
become: yes
apt: name={{ item }} state=installed
with_items:
- nodejs
- npm
- name: nmp cache clean
command: npm cache clean
- name: install n command
become: yes
command: npm install n -g
- name: install node v6.10.0
become: yes
command: n 6.10.0
create provisioning/playbook.yml
---
- hosts: docker
become: true
roles:
- nodejs
provision 開始
ansible-playbook ./provisioning/playbook.yml -i ./provisioning/inventory/docker
動作確認
ssh docker@localhost -p 40122 -i keys/docker_id_rsa 'node -v' v6.10.0
これを以下のコマンドでテストします。status code を echo $? で確認します。
0であればOKです。
test `ssh docker@localhost -p 40122 -i keys/docker_id_rsa 'node -v'` = "v6.10.0" echo $?
Makefile
以下のような Makefile を作っておきます。
docker.keygen:
ssh-keygen -P "" -f keys/docker_id_rsa
docker.build:
docker build -t provisioning_sshd .
docker.start:
docker run -d -p 40122:22 --name test_sshd provisioning_sshd
docker.stop:
ssh-keygen -R "[localhost]:40122"
docker rm -f `docker ps -aq`
docker.provision:
ansible-playbook ./provisioning/playbook.yml -i ./provisioning/inventory/docker
docker.provision.ci:
ansible-playbook ./provisioning/playbook.yml -i ./provisioning/inventory/docker --private-key=./keys/docker_id_rsa
docker.test:
test `ssh docker@localhost -p 40122 -i keys/docker_id_rsa 'node -v'` = "v6.10.0"
@echo "It looks like optimal"
CircleCI
CircleCI 上ではホストOS上で Docker を使います。Circle CI のホストOS上で Python と Ansible を install して、コンテナに対して SSH 接続を行います。
create circle.yml
machine:
python:
version: 2.7.10
services:
- docker
dependencies:
pre:
- pip install ansible
override:
- docker info
- make docker.keygen
- docker build -t provisioning_sshd .
test:
override:
- docker run -d -p 40122:22 provisioning_sshd
- make docker.provision.ci
- make docker.test
最終チェック
これらをコミットして実際に Circle Ci が動作する事を確認します。
まとめ
というわけで無事 CircleCI 上で Docker のコンテナに対して provisioning を行う事ができました。
サーバーサイドエンジニアがインフラエンジニアに代わってどれだけ作業すべきなのかは良く分からないのですが、インフラエンジニアにソースコード渡す場合はきちんと動作チェックをするのが礼儀だと思うのでこういうやり方があるという事は覚えておいたほうがいいなあと思いました。おしまい。