AnsibleでDockerコンテナを作成する

世の中、猫も杓子もAnsibleなので、そろそろ勉強をしないとまずい…ということで、重い腰を上げてAnsibleをしてみました。
とはいえ、自宅環境はサーバ1台のみなので、今回はDockerでWordpressコンテナを立ち上げることを最終目標にしていきます。
環境はこんな感じです。

```
# python3.6 -V
Python 3.6.2
# pip3.6 -V
pip 9.0.1 from /usr/local/python362/lib/python3.6/site-packages (python 3.6)
# cat /etc/redhat-release 
CentOS Linux release 7.3.1611 (Core) 
# docker -v
Docker version 17.03.1-ce, build c6d412e
```

執筆時点でAnsible歴二日くらいなので、間違いがあったらご指摘頂けますと幸いです。

# Ansibleとは

[先生](https://www.ansible.com/how-ansible-works)曰く、「Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.」だそうです。
ITにまつわる色々な作業をシンプルに自動化するエンジン、とのことですが、wikiには構成管理ツールって書いてありました。
習うより慣れろ、ということで、実践します。

# Ansibleの準備
pipします。dockerも入れます。

```
# pip3.6 install ansible docker
(略)
# ansible --version
ansible 2.4.0.0
```

# ファイル置き場の作成
ファイル置き場については、Ansibleのページに[ベストプラクティス](http://docs.ansible.com/ansible/latest/playbooks_best_practices.html)とかありますが、これは自宅程度の規模ではやりすぎだろう…ということで取りあえず

```
# mkdir -p /labo/ansible/inventory
# mkdir /labo/ansible/playbook
```

という感じで作りました。

# inventoryを作る
Ansibleを実行するにあたり、どのシステムを対象とするのか、その対象をまとめたものがinventoryファイルとなります。
ファイルはINI形式を模したものとなっており、書き方は(作りこまなければ)シンプルです。

```/labo/ansible/inventory/hosts
[mother]
localhost
[containers]
wordpress
```

尚、[]の部分はグループとなります。グループ名で指定した場合、そのグループ配下のすべてのシステムが対象となります。
グループに所属しないシステムも書けますが、何となくlocalhostもグループに入れました。

# playbookを作る
Ansibleに自動で構成とかを色々させるにはplaybook(=脚本)が必要になります。
playbookにああしようこうしようという手順を書いたら、それをAnsibleが実行してくれるイメージです。

では、wordpressをコンテナで起動すべく、まず軽く書いてみます。YAMLです。
wordpress:latestのイメージをpullしてきて、`docker container run -d --name=wordpress --hostname=wordpress --rm wordpress:latest`を実行する、というのをplaybookで表現すると以下です。

```wordpress.yml
     1  - name: Wordpress Container Maker
     2    hosts: localhost
     3    connection: local
     4 
     5    vars:
     6      hostname: wordpress
     7 
     8    tasks:
     9    - name: Create a wordpress container
    10      docker_container:
    11        name: wordpress
    12        hostname: "{{ hostname }}"
    13        image: wordpress:latest
    14        detach: yes
    15        auto_remove: yes
```

上記の1~3行目がTarget Sectionと呼ばれるもので、実行対象のホストなどを指定するセクションです。

- 1 [name] 後から見てわかりやすいコメントを記載してます。
- 2 [hosts] タスク実行対象です。コンテナを起動するのはlocalhostに対してなので、そのように記載しています。
- 3 [connection] localとすることで、ssh接続をせずにlocalhostに接続します。

上記5~6がVariable Sectionです。
ここでは、変数を設定することができます。変数の書き方はTask Sectionで。

- 6 [hostname] Task Sectionでコンテナのホスト名を指定するのですが、これが後々変わる可能性もありますので、変数化しておきます。

上記の8~最終行がTask Sectionと呼ばれるものでAnsibleが実行するタスクを記載していきます。
タスクというのは、モジュールとそれに対する引数で構成されます。モジュールとは、ある処理をするための機能を提供するもの(スクリプト)です。

- 8 [tasks] Task Sectionの始まりの部分です。
- 9 [name] コメントのようなものです。
- 10 [docker_container] このモジュールを使うことにより、コンテナの設定や操作を実施します。
- 11 [name] ここは従前のnameとは違い、コンテナ名の指定となります。
- 12 [hostname] コンテナのホスト名を指定します。ここではVarsで設定した変数を使ってます。
- 13 [image] コンテナを起動するためのイメージを指定します。DockerfileのFROMに書くものと同じです。
- 14 [detach] docker container runの-dに相当します。
- 15 [auto_remove] docker container runの--rmに相当します。

12行目の変数ですが、通常は{{ 変数 }}という形で書きます。
ただし、変数が引数の先頭に来てしまう場合は、"{{ 変数 }}"のように、ダブルクォートで括ってやる必要があります。

# 起動
playbookが完成したので、起動します。
インベントリは通常/etc/ansible/hostsを探しますが、今回は-iにてインベントリを絶対パスで指定してます。

```
# ansible-playbook -i /labo/ansible/inventory/hosts wordpress.yml

PLAY [Wordpress Container Maker] ********************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************
ok: [localhost]

TASK [Create a wordpress container] *****************************************************************************************************
changed: [localhost]

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

#
```

failedがなければOKです。

# Wordpressコンテナ内をいじる
さらに、完成したWordpressコンテナをいじ…りたいのですが、残念ながらwordpressのimageには、pythonが含まれていないため、Ansibleで制御ができません…。
従って、wordpressコンテナにpythonをインストールしてやる必要があります。

```wordpress.yml
     1  - name: Create a wordpress Container
     2    hosts: localhost
     3    connection: local
     4 
     5    vars:
     6      hostname: wordpress
     7 
     8    tasks:
     9      - name: Create a wordpress container
    10        docker_container:
    11          name: wordpress
    12          hostname: "{{ hostname }}"
    13          image: wordpress:latest
    14          detach: yes
    15          auto_remove: yes
    16 
    17  - name: Configure the wordpress container
    18    hosts: wordpress
    19    connection: docker
    20    gather_facts: False
    21 
    22    tasks:
    23      - name: install python
    24        raw: apt-get update && apt-get -y install python
    25      - name: Copy a file
    26        copy: src=poipoi dest=/. 
```

一応、上記のようにgather_facts(20行目)をFalseで抑止(Python使うので)し、rawでaptコマンドを直で流し込みすればいけますが、
特にauto_remove: yesな環境の場合、毎回毎回起動するたびにpythonのインストールが走って、時間がかかります。
尚、copyの部分(26行目)は、pythonをインストールしていないとできません。

もう一つのアプローチとしては、そもそものimageを準備するということになります。
docker image buildで作った独自のカスタムimageをplaybook内で呼んでやれば、
上記の力技より起動時の時間は短縮されます。
ただ、ansible内で設定が閉じないので、管理対象物は増えます。

どちらが良いかというと、一長一短ですが、基本的には餅は餅屋の精神で後者かなぁ…という気はします。
なんでも出来るからと言って、それそっちで無理やりやる必要ある？ってことまでやらせてしまうのはいまいち気が進みませんね。

　
---
ということでimageを別途準備したのちのコンテナ内ガサゴソは別途記事立てます。