見出し画像

Ansibleを使ってdockerコンテナを立ち上げる

Dockerのイメージ作成からコンテナ起動までをAnsibleを用いてできるかの検証日記です。

やったこと

①ansible-benderでコンテナイメージを作成
②podmanで作成したイメージからコンテナを起動

手順詳細

まずansible-benderについての説明です。

かつてAnsibleにはDockerコンテナを管理するものとしてansible-containerがありました。

ですが2020年現在、ansible-containerは公式のメンテナンスが終了し、非推奨となっております。AnsibleでDockerのコンテナを管理する方法としては、提供されているモジュールを活用して、dockerイメージのビルドやコンテナ起動を行うようです。

上記のドキュメントにansible-benderを使ってコンテナのイメージをビルドする手順がありましたので、これを使ってイメージのビルドを行おうと思います。

マシン環境情報

検証に使用したローカルマシンとツールのバージョンは以下の通りです。
・CentOS 8.1.1911
・ansible 2.9.9
・ansible-bender 0.8.1
・docker 19.03.10
・python 3.6.8
・podman 1.6.4
・buildah 1.11.6

ansible-benderはpython3.6系以上とのことでしたので、標準で3系を搭載されているCentOS 8を使用しました。podmanとbuildahは今回の検証で初めて存在を知ったので、簡単に説明します。

Podman

PodmanはRedHat社が開発したコンテナ管理ツールであり、↑のドキュメントでもdocker=podmanと説明されています。dockerとの違いは以下の記事が分かりやすく説明してくれました。

Buildah

Buildahも同じくRedHat社が開発したイメージビルドツールです。Dockerfileではなく、シェルスクリプトでコンテナを生成でき、より柔軟な管理を行うことができます。

各種ツールインストール

大体はdnfからインストールできましたが、dockerだけまだCentOS8に正式に対応していなかったので、それだけ注記します。

$ sudo yum install -y yum-utils
$ sudo yum-config-manager \
   --add-repo \
   https://download.docker.com/linux/centos/docker-ce.repo
 #docker関連ツールのインストール 
$ sudo dnf install docker-ce docker-ce-cli containerd.io
ELRepo.org Community Enterprise Linux Repository - el8          2.3 kB/s | 2.9 kB     00:01
Extra Packages for Enterprise Linux 8 - x86_64                  5.6 kB/s | 5.3 kB     00:00
Safe Remi's RPM repository for Enterprise Linux 8 - x86_64      2.1 kB/s | 3.0 kB     00:01
CentOS-8 - AppStream                                            5.3 kB/s | 4.3 kB     00:00
CentOS-8 - Base                                                 3.8 kB/s | 3.9 kB     00:01
CentOS-8 - Extras                                               1.9 kB/s | 1.5 kB     00:00
Docker CE Stable - x86_64                                        18 kB/s |  23 kB     00:01
Extra Packages for Enterprise Linux Modular 8 - x86_64           11 kB/s | 8.2 kB     00:00
Remi's Modular repository for Enterprise Linux 8 - x86_64       2.7 kB/s | 3.5 kB     00:01
エラー:
問題: package docker-ce-3:19.03.9-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of the providers can be installed
 - cannot install the best candidate for the job
 - package containerd.io-1.2.10-3.2.el7.x86_64 is excluded
 - package containerd.io-1.2.13-3.1.el7.x86_64 is excluded
 - package containerd.io-1.2.13-3.2.el7.x86_64 is excluded
 - package containerd.io-1.2.2-3.3.el7.x86_64 is excluded
 - package containerd.io-1.2.2-3.el7.x86_64 is excluded
 - package containerd.io-1.2.4-3.1.el7.x86_64 is excluded
 - package containerd.io-1.2.5-3.1.el7.x86_64 is excluded
 - package containerd.io-1.2.6-3.3.el7.x86_64 is excluded
(インストール不可のパッケージをスキップするには、'--skip-broken' を追加してみてください または、'--nobest' を追加して、最適候補のパッケージのみを使用しないでください)

公式サイト参照の手順でインストール作業を進めましたが、containerd.ioがインストール失敗し、依存関係のあるdocker-ceでエラーを起こしたようです。直接RPMパッケージをダウンロードしたらひとまず解決しました。

$ wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.2-3.3.el7.x86_64.rpm
$ dnf install containerd.io-1.2.2-3.3.el7.x86_64.rpm
$ sudo dnf install docker-ce docker-ce-cli
$ sudo systemctl start docker
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
   (amd64)
3. The Docker daemon created a new container from that image which runs the
   executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
   to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

dockerのインストールが無事にでき、hello-worldコンテナを起動することができました。

イメージビルド

使用したPlaybookはサイトからそのまま引っ張ってきました。

# simple-playbook.yml
---
- name: Demonstration of ansible-bender functionality
 hosts: all
 vars:
   ansible_bender:
     base_image: python:3-alpine

     working_container:
       volumes:
         - '{{ playbook_dir }}:/src'

     target_image:
       name: a-very-nice-image
       working_dir: /src
       labels:
         built-by: '{{ ansible_user }}'
       environment:
         FILE_TO_PROCESS: README.md
 tasks:
 - name: Run a sample command
   command: 'ls -lha /src'
 - name: Stat a file
   stat:
     path: "{{ lookup('env','FILE_TO_PROCESS') }}"

これを実行します。

$ ansible-bender build ./simple-playbook.yml
09:44:00.041 utils.py          ERROR  Getting image source signatures
09:44:01.108 utils.py          ERROR  Copying blob sha256:cbdbe7a5bc2a134ca8ec91be58565ec07d037386d1f1d8385412d224deafca08
09:44:01.251 utils.py          ERROR  Copying blob sha256:26ebcd19a4e3221ee54d309346df0869af0d74a25920287f70b0ee1da1bf75de
09:44:01.454 utils.py          ERROR  Copying blob sha256:979dbbcf63e040129349367e745db1b372a14883fc106b1355b934eda6795ed0
09:44:01.548 utils.py          ERROR  Copying blob sha256:30beed04940cb5afa7986dd5ffe0a0a022a56ad57a081f9db889a77d799b9af3
09:44:01.654 utils.py          ERROR  Copying blob sha256:a29d43ca1bb44ea27c7b0843b49cc454778069dc33caf9d4133f7ecb7df5c75d
09:44:05.083 utils.py          ERROR  Copying config sha256:f4df7f234e59bfe3955833a161ad63f334675d4705c09fe4629a02b3e8ff6006
09:44:05.443 utils.py          ERROR  Writing manifest to image destination
09:44:05.443 utils.py          ERROR  Storing signatures

PLAY [Demonstration of ansible-bender functionality] **********************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************
ok: [a-very-nice-image-20200529-094345068992-cont]

TASK [Run a sample command] ***********************************************************************************************************
changed: [a-very-nice-image-20200529-094345068992-cont]

TASK [Stat a file] ********************************************************************************************************************
ok: [a-very-nice-image-20200529-094345068992-cont]

PLAY RECAP ****************************************************************************************************************************
a-very-nice-image-20200529-094345068992-cont : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Getting image source signatures
Copying blob sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a
Copying blob sha256:a539b76feca4479232b3e15c29bf441c080441900384376dac2b0d7ca210fb1f
Copying blob sha256:df897d49f46cc96875fd5670f5484d2468b4a19fbd10b209c9cc00d2c4c19eba
Copying blob sha256:7a82840eb6822b6ad44e46166f1dc8ff9b78ebb3ddd66f5a6e3e592390673511
Copying blob sha256:a7d85ab87af885b3483663ce57d25c1ece4fc9ff8145008d5f0f40b03b2e83b6
Copying blob sha256:a116b75f5d8dfe6bd27fc91047b3ae1db543587d7e070c8f0c71e8e5e2e6da7c
Copying config sha256:0ea9c34b2c73ccd67052a47b9c7e1cec8d429419f89b95c85a7c167a15009448
Writing manifest to image destination
Storing signatures
0ea9c34b2c73ccd67052a47b9c7e1cec8d429419f89b95c85a7c167a15009448
Image 'a-very-nice-image' was built successfully \o/
$ ansible-bender list-builds
 BUILD ID  IMAGE NAME         STATUS    DATE                        BUILD TIME
----------  -----------------  --------  --------------------------  ------------
        1  a-very-nice-image  done      2020-05-29 09:46:20.316866  2 minutes

コンテナのイメージが作成できました。また二回目以降はキャッシュを活用するので、ビルドタイムが短くなります。

$ ansible-bender build simple-playbook.yml

PLAY [Demonstration of ansible-bender functionality] ********************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************
ok: [a-very-nice-image-20200531-182331829535-cont]

TASK [Run a sample command] *********************************************************************************************************************
loaded from cache: 'cbc283964012aafbd9251f15f7c954339ce289dde808265f336ac09ab226e937'
skipping: [a-very-nice-image-20200531-182331829535-cont]

TASK [Stat a file] ******************************************************************************************************************************
loaded from cache: '5f30e72716c28ea2d6297e8fc71a632da71d0e2b9b0aac58f8f79ea8ed27e362'
skipping: [a-very-nice-image-20200531-182331829535-cont]

PLAY RECAP **************************************************************************************************************************************
a-very-nice-image-20200531-182331829535-cont : ok=1    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Getting image source signatures
Copying blob sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a
Copying blob sha256:a539b76feca4479232b3e15c29bf441c080441900384376dac2b0d7ca210fb1f
Copying blob sha256:df897d49f46cc96875fd5670f5484d2468b4a19fbd10b209c9cc00d2c4c19eba
Copying blob sha256:7a82840eb6822b6ad44e46166f1dc8ff9b78ebb3ddd66f5a6e3e592390673511
Copying blob sha256:a7d85ab87af885b3483663ce57d25c1ece4fc9ff8145008d5f0f40b03b2e83b6
Copying blob sha256:95dc83d8eba38b46334a1d21be17cd531c8add79d91a57cbe3026b8cc4fe8d2d
Copying blob sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef
Copying config sha256:2552c6b34ca82a87183a00a92766a3d0897b6aff7bea757585bdd8102e4cd80d
Writing manifest to image destination
Storing signatures
2552c6b34ca82a87183a00a92766a3d0897b6aff7bea757585bdd8102e4cd80d
Image 'a-very-nice-image' was built successfully \o/
$ ansible-bender list-builds
 BUILD ID  IMAGE NAME         STATUS    DATE                        BUILD TIME
----------  -----------------  --------  --------------------------  ------------
        1  a-very-nice-image  done      2020-05-29 09:46:20.316866  2 minutes 
        2  a-very-nice-image  done      2020-05-31 13:50:15.650395  27 seconds #キャッシュを活用したので速い 
$ podman inspect a-very-nice-image
[
   {
       "Id": "75e8125f9be9ca7ded485d82fa1964dd159b3e9f8b8887e4d3e82aebf6e99cd4",
       "Digest": "sha256:22a2b0db5f20c9198e472f625bc1a79c823e4333f1d624205ab7759026d452dc",
       "RepoTags": [
           "localhost/a-very-nice-image:latest"
       ],
       "RepoDigests": [
           "localhost/a-very-nice-image@sha256:22a2b0db5f20c9198e472f625bc1a79c823e4333f1d624205ab7759026d452dc"
       ],
       "Parent": "",
       "Comment": "",
       "Created": "2020-05-31T06:58:53.058020928Z",
       "Config": {
           "Env": [
               "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
               "LANG=C.UTF-8",
               "GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568",
               "PYTHON_VERSION=3.8.3",
               "PYTHON_PIP_VERSION=20.1.1",
               "PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/eff16c878c7fd6b688b9b4c4267695cf1a0bf01b/get-pip.py",
               "PYTHON_GET_PIP_SHA256=b3153ec0cf7b7bbf9556932aa37e4981c35dc2a2c501d70d91d2795aa532be79",
               "FILE_TO_PROCESS=README.md"
           ],
           "Cmd": [
               "python3"
           ],
           "WorkingDir": "/src",
           "Labels": {
               "built-by": "root",
               "io.buildah.version": "1.11.6"
           }
       },
       "Version": "",
       "Author": "",
       "Architecture": "amd64",
       "Os": "linux",
       "Size": 82159774,
       "VirtualSize": 82159774,
       "GraphDriver": {
           "Name": "overlay",
           "Data": {
               "LowerDir": "/var/lib/containers/storage/overlay/d7bfe34a99628c934ad2457cdf3dd2c0f32a6701ade8f36b18446f2aef6e1c73/diff:/var/lib/containers/storage/overlay/9af63da640069b1ca4a4a2bd693e663d7cbf05562b7417df006189d4f1b36c87/diff:/var/lib/containers/storage/overlay/8062057bfdad20f7265a70821a53458140e98898dd495e4b352fe33d600653ad/diff:/var/lib/containers/storage/overlay/0da203282182723b28dd974fd445316641ba4f803cb7260fd1bf43d1e2a60746/diff:/var/lib/containers/storage/overlay/3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a/diff",
               "UpperDir": "/var/lib/containers/storage/overlay/2d5608ff6e439f2f14caee219a5daf5dbd4e2a6c7f3ead8db9bf5d8a47f600c7/diff",
               "WorkDir": "/var/lib/containers/storage/overlay/2d5608ff6e439f2f14caee219a5daf5dbd4e2a6c7f3ead8db9bf5d8a47f600c7/work"
           }
       },
       "RootFS": {
           "Type": "layers",
           "Layers": [
               "sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a",
               "sha256:a539b76feca4479232b3e15c29bf441c080441900384376dac2b0d7ca210fb1f",
               "sha256:df897d49f46cc96875fd5670f5484d2468b4a19fbd10b209c9cc00d2c4c19eba",
               "sha256:7a82840eb6822b6ad44e46166f1dc8ff9b78ebb3ddd66f5a6e3e592390673511",
               "sha256:a7d85ab87af885b3483663ce57d25c1ece4fc9ff8145008d5f0f40b03b2e83b6",
               "sha256:acfdc39909b5751f21b841f96b9cea7a895579e25b69077cd3cfe3a8c134dd69"
           ]
       },
       "Labels": {
           "built-by": "root",
           "io.buildah.version": "1.11.6"
       },
       "Annotations": {},
       "ManifestType": "application/vnd.oci.image.manifest.v1+json",
       "User": "",
       "History": [
           {
               "created": "2020-04-24T01:05:03.608058404Z",
               "created_by": "/bin/sh -c #(nop) ADD file:b91adb67b670d3a6ff9463e48b7def903ed516be66fc4282d22c53e41512be49 in / "
           },
           {
               "created": "2020-04-24T01:05:03.92860976Z",
               "created_by": "/bin/sh -c #(nop)  CMD [\"/bin/sh\"]",
               "empty_layer": true
           },
           {
               "created": "2020-04-24T01:10:55.083286077Z",
               "created_by": "/bin/sh -c #(nop)  ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
               "empty_layer": true
           },
           {
               "created": "2020-04-24T01:10:55.427735488Z",
               "created_by": "/bin/sh -c #(nop)  ENV LANG=C.UTF-8",
               "empty_layer": true
           },
           {
               "created": "2020-04-24T01:10:57.756639958Z",
               "created_by": "/bin/sh -c apk add --no-cache ca-certificates"
           },
           {
               "created": "2020-04-24T01:10:58.12224421Z",
               "created_by": "/bin/sh -c #(nop)  ENV GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568",
               "empty_layer": true
           },
           {
               "created": "2020-05-14T22:57:13.939248972Z",
               "created_by": "/bin/sh -c #(nop)  ENV PYTHON_VERSION=3.8.3",
               "empty_layer": true
           },
           {
               "created": "2020-05-20T20:47:57.950736738Z",
               "created_by": "/bin/sh -c set -ex \t&& apk add --no-cache --virtual .fetch-deps \t\tgnupg \t\ttar \t\txz \t\t&& wget -O python.tar.xz \"https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz\" \t&& wget -O python.tar.xz.asc \"https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc\" \t&& export GNUPGHOME=\"$(mktemp -d)\" \t&& gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys \"$GPG_KEY\" \t&& gpg --batch --verify python.tar.xz.asc python.tar.xz \t&& { command -v gpgconf > /dev/null && gpgconf --kill all || :; } \t&& rm -rf \"$GNUPGHOME\" python.tar.xz.asc \t&& mkdir -p /usr/src/python \t&& tar -xJC /usr/src/python --strip-components=1 -f python.tar.xz \t&& rm python.tar.xz \t\t&& apk add --no-cache --virtual .build-deps  \t\tbluez-dev \t\tbzip2-dev \t\tcoreutils \t\tdpkg-dev dpkg \t\texpat-dev \t\tfindutils \t\tgcc \t\tgdbm-dev \t\tlibc-dev \t\tlibffi-dev \t\tlibnsl-dev \t\tlibtirpc-dev \t\tlinux-headers \t\tmake \t\tncurses-dev \t\topenssl-dev \t\tpax-utils \t\treadline-dev \t\tsqlite-dev \t\ttcl-dev \t\ttk \t\ttk-dev \t\tutil-linux-dev \t\txz-dev \t\tzlib-dev \t&& apk del --no-network .fetch-deps \t\t&& cd /usr/src/python \t&& gnuArch=\"$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)\" \t&& ./configure \t\t--build=\"$gnuArch\" \t\t--enable-loadable-sqlite-extensions \t\t--enable-optimizations \t\t--enable-option-checking=fatal \t\t--enable-shared \t\t--with-system-expat \t\t--with-system-ffi \t\t--without-ensurepip \t&& make -j \"$(nproc)\" \t\tEXTRA_CFLAGS=\"-DTHREAD_STACK_SIZE=0x100000\" \t\tLDFLAGS=\"-Wl,--strip-all\" \t&& make install \t\t&& find /usr/local -type f -executable -not \\( -name '*tkinter*' \\) -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \t\t| tr ',' '\\n' \t\t| sort -u \t\t| awk 'system(\"[ -e /usr/local/lib/\" $1 \" ]\") == 0 { next } { print \"so:\" $1 }' \t\t| xargs -rt apk add --no-cache --virtual .python-rundeps \t&& apk del --no-network .build-deps \t\t&& find /usr/local -depth \t\t\\( \t\t\t\\( -type d -a \\( -name test -o -name tests -o -name idle_test \\) \\) \t\t\t-o \t\t\t\\( -type f -a \\( -name '*.pyc' -o -name '*.pyo' \\) \\) \t\t\\) -exec rm -rf '{}' + \t&& rm -rf /usr/src/python \t\t&& python3 --version"
           },
           {
               "created": "2020-05-20T20:47:59.34420132Z",
               "created_by": "/bin/sh -c cd /usr/local/bin \t&& ln -s idle3 idle \t&& ln -s pydoc3 pydoc \t&& ln -s python3 python \t&& ln -s python3-config python-config"
           },
           {
               "created": "2020-05-20T20:47:59.66397567Z",
               "created_by": "/bin/sh -c #(nop)  ENV PYTHON_PIP_VERSION=20.1.1",
               "empty_layer": true
           },
           {
               "created": "2020-05-20T20:47:59.941547311Z",
               "created_by": "/bin/sh -c #(nop)  ENV PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/eff16c878c7fd6b688b9b4c4267695cf1a0bf01b/get-pip.py",
               "empty_layer": true
           },
           {
               "created": "2020-05-20T20:48:00.301101335Z",
               "created_by": "/bin/sh -c #(nop)  ENV PYTHON_GET_PIP_SHA256=b3153ec0cf7b7bbf9556932aa37e4981c35dc2a2c501d70d91d2795aa532be79",
               "empty_layer": true
           },
           {
               "created": "2020-05-20T20:48:10.421167178Z",
               "created_by": "/bin/sh -c set -ex; \t\twget -O get-pip.py \"$PYTHON_GET_PIP_URL\"; \techo \"$PYTHON_GET_PIP_SHA256 *get-pip.py\" | sha256sum -c -; \t\tpython get-pip.py \t\t--disable-pip-version-check \t\t--no-cache-dir \t\t\"pip==$PYTHON_PIP_VERSION\" \t; \tpip --version; \t\tfind /usr/local -depth \t\t\\( \t\t\t\\( -type d -a \\( -name test -o -name tests -o -name idle_test \\) \\) \t\t\t-o \t\t\t\\( -type f -a \\( -name '*.pyc' -o -name '*.pyo' \\) \\) \t\t\\) -exec rm -rf '{}' +; \trm -f get-pip.py"
           },
           {
               "created": "2020-05-20T20:48:10.768591954Z",
               "created_by": "/bin/sh -c #(nop)  CMD [\"python3\"]",
               "empty_layer": true
           },
           {
               "created": "2020-05-31T06:58:53.058020928Z",
               "created_by": "/bin/sh"
           }
       ]
   }
]

コンテナ起動

イメージがビルドされたことを確認できましたので、podmanを使ってコンテナを起動します。

 #podmanはrootユーザーで起動する
$ su -
# podman run a-very-nice-image
# podman ps -a
CONTAINER ID  IMAGE                               COMMAND  CREATED        STATUS                    PORTS  NAMES
e4ed565b97f0  localhost/a-very-nice-image:latest  python3  9 minutes ago  Exited (0) 9 minutes ago         clever_goldstine

ビルドされたイメージからコンテナが起動されたことを確認できました。

反省点

これらの情報はほとんど日本語サイトが存在せず、英語の公式サイトから必死に解読して行いました。
また、playbook内のTask実行が上手くいっているかの確認方法が分からずコンテナが起動できていたの確認にとどまってしまった事が個人的に悔しかったです。
Ansibleの公式ドキュメントに、「Still using Dockerfile to build images? Check out ansible-bender, and start building images from your Ansible playbooks.」(訳:まだDockerfileでイメージビルドしてるの?ansible-benderを使ってplaybookからビルドを始めようよ。)
と煽られてましたので、そこからこの検証を始めてみたわけですが、ansibleにはdockerのモジュールが豊富にあり、どちらが良いのか次はモジュールからイメージのビルドからコンテナの起動までを行っていきたいと思います。

この記事が気に入ったらサポートをしてみませんか?