Ansible Container を久しぶりに使って Docker をドナドナしようとしてはまった話

# Ansible Container のはまり処

ただいま、`Fri Dec 21 17:18:43 UTC 2018` です。JST では 21日じゃないですけど、Linux は基本 UTC ですしね（とｲｲﾜｹ）
[Ansible Container](https://www.ansible.com/integrations/containers/ansible-container) を CentOS7 で使おうとしたらハマりどころ満載だったお話です。

Ansible には Docker を操作するモジュールがあるのですが、専用のツールがあるので、それを使ってみたいと思います。
あれ？このアドベントカレンダーってモジュールの話でしたよね？？
Ansible の Docker モジュールを便利にしたものってことで。。。

## ゼロスタート

とりあえず、GCP で `CentOS7` を `f1-micro` で上げました。
OS のリビジョンは `CentOS Linux release 7.6.1810 (Core) ` でした。

とりあえず、、、

```
> yum update
> yum install -y python-pip docker
> systemctl start docker.service
> pip install --upgrade setuptools
> pip install "ansible-container[docker]"
```

で、基本準備はできたはずです。

## 初期化

作業ディレクトリ作って初期化してきます。

```
> mkdir ansible-container-test
> cd ansible-container-test
> ansible-container init
> ls -la
-rw-r--r--. 1 root root  144 Dec 21 16:19 ansible.cfg
-rw-r--r--. 1 root root  130 Dec 21 16:19 ansible-requirements.txt
-rw-r--r--. 1 root root 2507 Dec 21 16:19 container.yml
-rw-r--r--. 1 root root 1181 Dec 21 16:19 meta.yml
-rw-r--r--. 1 root root  298 Dec 21 16:19 requirements.yml
```

ここまでは何事もなくきました。

## 定義ファイル作成

`container.yml` を作成していきましょう。
`init` で作成されたものから、`services` の中だけ別途参照してます。

```container.yml
version: "2"
settings:
  conductor:
    base: centos:7
  project_name: ansible-container-test
services:
  httpd:
    from: "httpd:2.4"
    ports:
      - "80:80"
    environment:
      PATH: "/usr/local/apache2/bin:/bin:/usr/bin:/usr/local/bin"
    command: ["httpd-foreground"]
registries: {}
```

## ビルドしましょう

```
> ansible-container build
Building Docker Engine context...
Starting Docker build of Ansible Container Conductor image (please be patient)...
ERROR   Unknown exception
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/container/cli.py", line 299, in __call__    getattr(core, u'hostcmd_{}'.format(args.subcommand))(**vars(args))
  File "/usr/lib/python2.7/site-packages/container/__init__.py", line 28, in __wrapped__    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/core.py", line 181, in hostcmd_build    environment=env_vars
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 105, in __wrapped__    return fn(self, *args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/__init__.py", line 28, in __wrapped__    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 1070, in build_conductor_image    return image.id
AttributeError: 'tuple' object has no attribute 'id'
```

あらま、エラーですね・・・

## 原因は・・・

神様・仏様・Google先生ってことで、ググります。
そうすると、こんなものが。。。

https://github.com/ansible/ansible-container/issues/884

要は、`pip install docker==2.7.0` しろということですかね。
pip の docker バージョンがデフォルトじゃダメってことのようですね。。。

## 再チャレンジ

```
> pip install docker==2.7.0
> ansible-container build
Building Docker Engine context...
Starting Docker build of Ansible Container Conductor image (please be patient)...
ERROR   Unknown exception
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/container/cli.py", line 299, in __call__    getattr(core, u'hostcmd_{}'.format(args.subcommand))(**vars(args))
  File "/usr/lib/python2.7/site-packages/container/__init__.py", line 28, in __wrapped__    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/core.py", line 201, in hostcmd_build    'build', dict(config), base_path, kwargs, save_container=save_container)
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 454, in await_conductor_command    conductor_id = self.run_conductor(command, config, base_path, params)
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 105, in __wrapped__    return fn(self, *args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/__init__.py", line 28, in __wrapped__    return fn(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 446, in run_conductor    reraise(*sys.exc_info())
  File "/usr/lib/python2.7/site-packages/container/docker/engine.py", line 439, in run_conductor    **run_kwargs
  File "/usr/lib/python2.7/site-packages/docker/models/containers.py", line 725, in run    container.start()
  File "/usr/lib/python2.7/site-packages/docker/models/containers.py", line 337, in start    return self.client.api.start(self.id, **kwargs)
  File "/usr/lib/python2.7/site-packages/docker/utils/decorators.py", line 19, in wrapped    return f(self, resource_id, *args, **kwargs)
  File "/usr/lib/python2.7/site-packages/docker/api/container.py", line 1086, in start    self._raise_for_status(res)
  File "/usr/lib/python2.7/site-packages/docker/api/client.py", line 224, in _raise_for_status    raise create_api_error_from_http_exception(e)
  File "/usr/lib/python2.7/site-packages/docker/errors.py", line 31, in create_api_error_from_http_exception    raise cls(e, response=response, explanation=explanation)
APIError: 500 Server Error: Internal Server Error ("linux mounts: Duplicate mount point '/run/secrets'")
```

エラーアゲインっすよ・・・

## 原因は・・・

Google先生お願いっ！

https://www.bountysource.com/issues/50235092-duplicate-mounting-of-run-secrets-not-handled

`/run/secrets` がぶつかってるから、パス変えろって話みたいですね。

## 再々チャレンジ

```/usr/lib/python2.7/site-packages/container/docker/engine.py
<         return os.path.join(os.sep, 'run', 'secrets')
>         return os.path.join(os.sep, 'docker', 'secrets')
```

ファイルを修正して、再々チャレンジしてみます。

```
> ansible-container build
Building Docker Engine context...
Starting Docker build of Ansible Container Conductor image (please be patient)...
Parsing conductor CLI args.
Docker™ daemon integration engine loaded. Build starting.       project=ansible-container-test
Building service...     project=ansible-container-test service=httpd
Service had no roles specified. Nothing to do.  service=httpd
All images successfully built.
Conductor terminated. Cleaning up.      command_rc=0 conductor_id=cb7af895bc2eff27abc51e6f1b9fde38bb626196a641ea1f3e1e992d6080d377 save_container=False
```

お、できたっぽいですね。

## 立ち上げてみる

```
> ansible-container run
Parsing conductor CLI args.
Engine integration loaded. Preparing run.       engine=Docker™ daemon
PLAY [Deploy ansible-container-test] *******************************************
TASK [docker_service] **********************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0
All services running.   playbook_rc=0
Conductor terminated. Cleaning up.      command_rc=0 conductor_id=8b2b7791ce3e6a5371afc66b55053418e916e238111a09341cab06b29a739048 save_container=False
```

立ち上がったぽいですね。

```
> curl localhost
<html><body><h1>It works!</h1></body></html>
```

動いてます。
ブラウザから見ても大丈夫そうです。

## では停止

```
> ansible-container stop
Parsing conductor CLI args.
Engine integration loaded. Preparing to stop all containers.    engine=Docker™ daemon
PLAY [Deploy ansible-container-test] *******************************************
TASK [docker_service] **********************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0
All services stopped.   playbook_rc=0
Conductor terminated. Cleaning up.      command_rc=0 conductor_id=1c270d0838d207319aabd07dbf45b760966a541656b09f750cdfd6326a734c35 save_container=False
```

止まったようですね。

```
> curl localhost
curl: (7) Failed connect to localhost:80; Connection refused
```

止まってます。

## ですとろい

```
> ansible-container destroy
Parsing conductor CLI args.
Engine integration loaded. Preparing to stop+delete all containers and built images.    engine=Docker™ daemon
PLAY [Deploy ansible-container-test] *******************************************
TASK [docker_service] **********************************************************
changed: [localhost]
TASK [docker_image] ************************************************************
changed: [localhost]
TASK [docker_image] ************************************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=3    unreachable=0    failed=0
All services destroyed. playbook_rc=0
Conductor terminated. Cleaning up.      command_rc=0 conductor_id=b3ae291d1dffc607613f6d3e24a658173ab9b6bd7eba2d305f9dac0366fd2b3e save_container=False
```

破壊されましたね。

```
> docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS      
        PORTS               NAMES
```

何もいません。

```
> docker images
REPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
<none>                                           <none>              b483f45dcd11        8 minutes ago       445 MB
docker.io/centos                                 7                   1e1148e4cc2c        2 weeks ago         202 MB
docker.io/ansible/container-conductor-centos-7   0.9.2               3d2f4f23dbd5        15 months ago       445 MB
```

なんだか、イメージは破壊され尽くすのではなく、`<none>` になってますね・・・なんか中途半端的な・・・
ま、まぁ、そこは置いといて・・・

## まとめ

Terraform みたいにワンパッケージで動くものと違って、依存関係があるものって結構難しいですよね。
環境によっても違うので色々と調整必要なところがあります。
Google先生いないと生きていけません。。。

## 参照

https://docs.ansible.com/ansible-container/getting_started.html
https://knowledge.sakura.ad.jp/9473/
https://github.com/ansible/ansible-container/issues/884
https://www.bountysource.com/issues/50235092-duplicate-mounting-of-run-secrets-not-handled