CentOS
docker
Ansible
ansible-playbook

Ansible controller/target を Docker コンテナで構築する

はじめまして。食べログの DevOps / データサイエンスチームの爲岡 (ためおか) です。
Twitter やら GitHub やら、たいてい @zettaittenani というアカウント名で活動しています。
どうでもいいですが今のところかぶったことはないです。

今回は DevOps にフォーカスして、Ansible の実行環境を Docker を使って構築した話をします。

背景

食べログの開発環境構築には Ansible を利用していますが、諸々の事情で開発環境構築用の Ansible playbook を整理するタスクが発生しました。

Ansible は基本的には冪等性を担保していますが、command モジュールなどはその限りではなく、新しい開発環境のための Ansible playbook を冪等性が担保される、されないを意識しながら書いていくのは面倒な作業です。
そのため、下記のような requirements を満たすテスト環境を構築しよう、という話になりました。

  1. 開発中の playbook がバグを含んでいて、それによって冪等性が担保できない状態に陥った場合、playbook の実行対象となる新しい環境を簡単に立ち上げられる。
  2. まっさらな環境に対して初めて playbook を実行した際の結果を簡単に確認できる。

そこで、検証用の Ansible target 環境を Docker コンテナで構築し、環境を壊してしまったらまたコンテナを作り直せばよい状態ができれば、上記2つを満たすことができ、ハッピーなのでは? と考えました。
で、手元の環境を汚すのも嫌なので、どうせなら Ansible controller も含めて Docker で作ってしまおう! というのが今回の話です。

前提

手元のホストに Docker がインストールされていることを確認します。
無ければインストールします。

$ docker -v
Docker version 18.09.0, ...

controller 構築

Ansible は ssh 経由で実行されますが、official に配布されているまっさらなcentosにはopenssh-server, openssh-clientsいずれもインストールされていないため、下記のようなDockerfileを用意します。

controller に関しては、openssh-clientsがインストールされたcentosベースの image を用意します。
Ansible は、ホストが CentOS であれば EPEL リポジトリからもインストールできるそうですが、公式ではpipでインストールしているのでそちらに合わせました。

/some_dir/controller/Dockerfile
FROM centos:7.5.1804
MAINTAINER "zettaittenani"

# infra settings
RUN yum check
RUN yum -y update
RUN yum -y install openssh-clients

# application settings
RUN curl -L https://bootstrap.pypa.io/get-pip.py | python
RUN pip install ansible

target 構築

target にはopenssh-serverがインストールされたcentosベースの image を用意します。
今回は開発環境での playbook の実行検証が目的なので、UsePAM は no にして root login を許可しています。
また、EXPOSE 22で controller からの ssh アクセスを受けられるよう設定しています。

/some_dir/target/Dockerfile
FROM centos:7.5.1804
MAINTAINER "zettaittenani"

# infra settings
RUN yum check
RUN yum -y update
RUN yum -y install openssh-server
RUN sed -ri 's/^#PermitEmptyPasswords no/PermitEmptyPasswords yes/' /etc/ssh/sshd_config
RUN sed -ri 's/^#PermitRootLogin yes/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN sed -ri 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config
RUN passwd -d root

# start sshd when booting
RUN /bin/systemctl enable sshd
EXPOSE 22

CMD /sbin/init

docker-compose にまとめる

2つの image の build からコンテナ立ち上げまでを一挙に行いたいので、
そのためのdocker-compose.ymlを用意します。

まず、テスト実行用の簡素な Ansible playbook を用意します。
hostsに関しては、docker-composeでコンテナを立ち上げる際に名前解決できるように自動で設定してくれるようで、下記のようにtargetと書くだけでOKです。
なんて楽なんだ…。

/some_dir/ansible_dir/hosts
[managed_node]
target
/some_dir/ansible_dir/setup.yml
---
- name: Test
  hosts: managed_node
  user: root

  tasks:
    - name: Hello
      shell: date >> now.txt

次に下記のようなdocker-compose.ymlを用意して、この Ansible playbook を controller にマウントするよう設定します。

/some_dir/docker-compose.yml
version: '3'

services:
  controller:
    build: ./controller
    privileged: true
    volumes:
      - "./ansible_dir:/ansible"
  target:
    build: ./target
    privileged: true

コンテナを立ち上げる

ホストで下記コマンドを実行して Docker コンテナを立ち上げます。

$ pwd
/some_dir
$ docker-compose up -d --build

これで controller と target、どちらのコンテナも立ち上がったはずです。
別々の shell からdocker-composeコマンドで各コンテナが立ち上がったことを確認します。

# @shell 1 (controller 用)
$ docker-compose exec controller /bin/bash
$ [root@xxxxxxxxxxxx ~]#

# @shell 2 (target 用)
$ docker-compose exec target /bin/bash
$ [root@xxxxxxxxxxxx ~]#

疎通確認

コンテナは用意できたので最後に疎通確認です。
controller のコンテナから target に対して playbook をテスト実行します。

# @shell 1 (controller 用)
[root@xxxxxxxxxxxx ~]# cd ansible
[root@xxxxxxxxxxxx ~]# ansible-playbook -k ./setup.yml -vvv -i ./hosts
...

PLAY RECAP *********************************************************************************************************************************************************************************************************************************************************************
xxx.xxx.xxx.xxx               : ok=2    changed=1    unreachable=0    failed=0

実行できました。
次に target の Docker コンテナでテスト結果を確認してみます。

# @shell 2 (target 用)
[root@xxxxxxxxxxxx ~]# cat now.txt
xxxx年 xx月 xx日 x曜日 xx時xx分xx秒 JST

はい、確かに controller から target に対して playbook が実行できていますね。

playbook 自体はマウントしているものなので、手元のホストの shell 上で編集するなりなんなりできますし、実行する際は controller のコンテナでansible-playbookコマンドを叩けば良いです。
実行結果は target のコンテナ上で確認できますし、target が壊れたらdocker-compose down/upするだけでOK。
これはかなり幸せな環境ではないでしょうか!



本内容を GitHub リポジトリ (ansible_tester) として公開しておりますので、
コピペが面倒な方はぜひご利用ください。

最後までお読みいただきありがとうございました。
Happy Ansible Life!!