Docker で Ansible の実行環境を作る(Ubuntu 18.04)
Ansible を何度も本番環境に流すのは、インスタンスの作り直しがその度に発生し大変です。
そこで Docker を利用し、簡単に使い捨てが出来る、Ansible の開発用実行環境にしてみようと思いました。
なお、本番環境は DigitalOcean の Ubuntu 18.04 環境を利用しようと思っているので、
Ubuntu 18.04 の Docker イメージを使用します。
1. Python がない!
最初は ubuntu:18.04
イメージをそのまま使って Ansible を流せると思ったんですけど、
fatal: [ansible-test01]: FAILED! => {"changed": false, "module_stderr": "/bin/sh: 1: /usr/bin/python: not found\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 127}
のエラーが……。
わかりやすく太文字にしましたが、そうです、 python が ubuntu:18.04 イメージには入っていなかったのです!
これでは Ansible を実行できません。というわけで、しぶしぶ Dockerfile を書くことにしたのでした。
2. Dockerfile はこんな感じ
FROM ubuntu:18.04 RUN \ apt-get update && \ apt-get install -y \ sudo \ python \ python3 ENTRYPOINT ["/bin/bash"]
シンプルにこんな感じにしました。
python3 を入れているのは、DigitalOcean の Ubuntu イメージが python3 しか入っていないことを考慮してです。
Ansible では sudo を付けてコマンドが実行されることが多いので、
sudo パッケージも入れています。
3. Makefile で楽をしよう
Dockerfile が出来ましたので、これをビルドして Docker イメージを作りましょう。
ただ、修正を加えるたびにコマンドを書くのも大変なので、Makefile で定義しておきます。
CONTAINER_NAME := ansible-test01 .PHONY: build build: docker build ./ -t ubuntu18_ansible:latest .PHONY: run run: docker run -itd --rm \ --name $(CONTAINER_NAME) \ --cap-add NET_ADMIN \ ubuntu18_ansible:latest .PHONY: login login: docker exec -it $(CONTAINER_NAME) /bin/bash .PHONY: stop stop: docker stop $(CONTAINER_NAME)
Dockerイメージ内でDockerを呼び出す場合は、
docker run のコマンドに -v /var/run/docker.sock:/var/run/docker.sock
のオプションを付けておいてください。
(ただし、セキュリティ上のリスクが大きいので、このオプションを付けるのは必ず開発用Dockerに留めてください*1)
この Makefile で、
make build
で Docker イメージの作成make run
で Docker コンテナの開始make login
で Docker コンテナ内部の確認make stop
で Docker コンテナの終了と廃棄
という一連のことが出来るようになります。
docker run コマンドに d オプション(デタッチド・モード)を使いバックグラウンドで動作させているのと、
rm オプションを使い、コンテナ停止時にコンテナが削除されるように設定しているのがポイントですね。
--cap-add NET_ADMIN
オプションを付けているのは、
Docker内で iptables
を実行可能にするため です。(参考: https://github.com/moby/moby/issues/18230 )
これがないと
fatal: [ansible-test01]: FAILED! => {"changed": false, "msg": "ERROR: initcaps\n[Errno 2] iptables v1.6.1: can't initialize iptables table `filter': Permission denied (you must be root)\nPerhaps iptables or your kernel needs to be upgraded.\n\n"}
とエラーが出て、 ufw などの設定がおこなえません。(ここめっちゃハマりました)
--privileged
オプションを使うのもアリですが、セキュリティ上のリスクはあります。
CONTAINER_NAME を変数にしているので、
make run CONTAINER_NAME=test02
のように、別名のコンテナを建てることも出来ます。
4. hosts ファイルにコンテナ名
Ansible の実行時に指定する i オプション(インベントリ)で指定する hosts ファイルには、
コンテナの名前を記載します。
今回は Makefile で ansible-test01 という名前をデフォルトにしているので、例えば以下のように書きます。
[ubuntu] ansible-test01 [ubuntu:vars] ansible_python_interpreter=/usr/bin/python3
今回は DigitalOcean の Ubuntu 18.04 環境に python3 しか入っていないことを考慮し、
ansible_python_interpreter を指定し、開発環境でも python3 を使用するようにしています。
5. connection オプションが大事
Docker コンテナに Ansible を流すには、Ansible の connection オプション を使います。
https://docs.ansible.com/ansible/latest/plugins/connection.html#using-connection
playbook 内に connection: docker
と書く方法もありますが、
本番環境と同じ playbook を使う場合には、Ansible 実行時に、例えば以下のように指定することになります。
(3. で扱った hosts ファイルの場所や、playbook 名に合わせて、適宜変更してください)
ansible-playbook -i hosts/development -c docker -e ansible_user=root site.yml
c オプションがポイントですね!
--connection docker
と指定することももちろん可能です。
また、Docker の場合は root ログインになるでしょうから、
-e ansible_user=root
を指定しています。(デフォルト値なので、ansible_user の値をどこかで設定していない場合は不要です)
6. 留意点
DigitalOcean, ConoHa, AWS などの VPS サービスから提供されるOSは扱いやすいように多少カスタマイズされているのですが、
Docker イメージはそのようなカスタマイズがありません。
ゆえに、/etc/ssh/sshd_config の設定をしようとするもファイルが存在しなく、
openssh-server のインストールが先に必要だったりと、インストールしないといけないものが色々あります。
少し面倒ですが、しっかり書いていくことで、環境依存が少ないしっかりした playbook になるでしょう。