AnsibleでDockerコンテナの管理をしてみた
概要
こちらの内容は以前noteで書いた記事のリメイク的なものになります。
今見直すと色々と粗があるように感じましたので、少し手直してよりインフラのコード化を実現しました。
実施すること
AnsibleのPlaybookで以下のことを実施します。
- Dockerイメージ取得
- JSフレームワーク、Nuxt.jsコンテナを構築
- Docker Hubへのイメージpush
使用したツールおよびAnsibleモジュール
- Ansible 2.9.10
- Docker 19.03.11
- Docker API 1.40
- Python 3.8.2
- Docker SDK Python 1.80
- docker_image
- docker_container
docker_imageとdocker_containerを使用するには、Docker APIのバージョンが1.20以上、Docker SDK Pythonのバージョンが1.80以上という必要条件がありますので、事前にバージョンを上げておきます。
事前準備
まず初めに、Nodeイメージを取得し、簡単にNuxt.jsのプロジェクト構築ができるツールcreate-nuxt-appを事前に使用してappディレクトリをホームディレクトリとするDockerfileを作成します。
FROM node:latest
WORKDIR /app
このDockerfileをビルドして、Nodeイメージ作成後コンテナへアタッチしNuxt.jsプロジェクトのひな型を構築します。
docker run -it <コンテナID> bash
yarn create nuxt-app
nuxt-app
コマンドを実行しますと、対話形式にNuxtの設定を行なえることができ、簡単にNuxtのプロジェクトを作成できます。質問の詳しい内容はこちらのサイトを参考にして、各自の好みに合わしたプロジェクトのひな型を作成します。
ひな型の作成が完了しましたら、コンテナ内から抜けてローカルマシン上へ作成したひな型をコピーします。
docker cp <コンテナID>:/app .
これで準備は整いましたので、DockerfileとPlaybookを作成していきます。
ディレクトリ構成
ディレクトリ構成は以下の通りです。]
$ tree
├── dockerFile
│ ├── Dockerfile
│ └── app/(Nuxt.jsのひな型)
└── build_image.yml
└── create_container.yml
DockerFile作成
Nodeコンテナから持ってきたローカル上のNuxt.jsのひな型をコンテナへ配置してNuxt.jsのイメージが作成されるDockerfileを作成します。
FROM node:latest
ENV NUXT_HOST=0.0.0.0
ENV NUXT_TELEMETRY_DISABLED=1
WORKDIR /app
COPY ./app/package.json ./app/yarn.lock ./
RUN yarn install
COPY ./app .
CMD ["yarn", "run", "dev"]
Playbook作成
次に作成したDockerfileをビルドするためのPlaybookを作成します。
- name: Build Nuxt.js image
hosts: localhost
tasks:
- name: build nuxt.js
docker_image:
build:
path: ./dockerFile
name: yuta28/ansible-test
tag: Nuxtimage
push: yes #イメージビルド後自動的にDockerHubへpushする
source: build
register: build_result
- debug: var=build_result
docker_image内のbuildオプションでDockerfileのカレントディレクトリを指定します。
nameオプションは出来上がったDockerイメージの名前を付けています。
sourceオプションでbuildを指定することで、DockerFileからイメージをビルドするようにします。
最後にイメージを基にコンテナを起動するためのPlaybook、create_container.ymlを作成します。
- name: Create and run container
hosts: localhost
tasks:
- name: Nuxt container
docker_container:
name: NuxtContaier
image: yuta28/ansible-test:Nuxtimage
state: started
ports:
- "127.0.0.1:8080:3000" #コンテナ内のポート3000にNuxt.jsが構築されるのでローカルのポート8080から参照できるようにマッピング
tty: true
detach: true
register: contaier_result
- debug: var=contaier_result
Ansible実行
準備が完了しましたので、Ansibleを実行します。
$ ansible-playbook build_image.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Build Nuxt.js image] ***************************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [localhost]
TASK [build nuxt.js] *********************************************************************************************************************************************************************************
[WARNING]: The default for build.pull is currently 'yes', but will be changed to 'no' in Ansible 2.12. Please set build.pull explicitly to the value you need.
changed: [localhost]
TASK [debug] *****************************************************************************************************************************************************************************************
ok: [localhost] => {
"build_result": {
"actions": [
"Built image yuta28/ansible-test:Nuxtimage from ./dockerFile",
"Pushed image yuta28/ansible-test to docker.io/yuta28/ansible-test:Nuxtimage"
],
"changed": true,
"failed": false,
"image": {
"Architecture": "amd64",
"Author": "",
"Comment": "",
"Config": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"yarn",
"run",
"dev"
],
"Domainname": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_VERSION=14.8.0",
"YARN_VERSION=1.22.4",
"NUXT_HOST=0.0.0.0",
"NUXT_TELEMETRY_DISABLED=1"
],
"Hostname": "",
"Image": "sha256:fe9a213a2bb59321425eb62ddcb54c9388e673b3f588ed4108b0b0c0c8ba78bb",
"Labels": null,
"OnBuild": null,
"OpenStdin": false,
"StdinOnce": false,
"Tty": false,
"User": "",
"Volumes": null,
"WorkingDir": "/app"
},
"Container": "50e3089197639ba613f1ae439d90142668cc5f0c360967fe8099c0093987695e",
"ContainerConfig": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"yarn\" \"run\" \"dev\"]"
],
"Domainname": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜中略〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
},
"Size": 1430378578,
"VirtualSize": 1430378578,
"push_status": null
},
"warnings": [
"The default for build.pull is currently 'yes', but will be changed to 'no' in Ansible 2.12. Please set build.pull explicitly to the value you need."
]
}
}
PLAY RECAP *******************************************************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook create_container.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Create and run container] *********************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [localhost]
TASK [Nuxt container] ********************************************************************************************************************************************************************************
changed: [localhost]
TASK [debug] *****************************************************************************************************************************************************************************************
ok: [localhost] => {
"contaier_result": {
"ansible_facts": {
"docker_container": {
"AppArmorProfile": "docker-default",
"Args": [
"yarn",
"run",
"dev"
],
"Config": {
"AttachStderr": false,
"AttachStdin": false,
"AttachStdout": false,
"Cmd": [
"yarn",
"run",
"dev"
],
"Domainname": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_VERSION=14.8.0",
"YARN_VERSION=1.22.4",
"NUXT_HOST=0.0.0.0",
"NUXT_TELEMETRY_DISABLED=1"
],
"ExposedPorts": {
"3000/tcp": {}
},
"Hostname": "f5597614f5d5",
"Image": "yuta28/ansible-test:Nuxtimage",
"Labels": {},
"OnBuild": null,
"OpenStdin": false,
"StdinOnce": false,
"Tty": true,
"User": "",
"Volumes": null,
"WorkingDir": "/app"
},
"Created": "2020-08-16T07:05:36.169002938Z",
"Driver": "overlay2",
"ExecIDs": null,
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜中略〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 },
"failed": false
}
}
PLAY RECAP *******************************************************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
failedになることなくAnsibleが最後まで実行されましたので、コンテナが起動しているか確認し、http://127.0.01:8080
からNuxt.jsのサンプルページにアクセスできるか試してみます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f5597614f5d5 yuta28/ansible-test:Nuxtimage "docker-entrypoint.s…" 37 minutes ago Up 37 minutes 127.0.0.1:8080->3000/tcp NuxtContaier
ちゃんとサンプルページにアクセスできることが確認できました。
Docker Hubへのpush
build_image.yml
で自動pushされるように設定しましたので、ご覧のように私のDocker Hubへイメージがpushされています。
反省点
Dockerのイメージからコンテナ起動まで一通りAnsibleで実行できました。
ただ、nuxt-appの仕様上コマンド実行後に対話形式で設定する必要があり、この部分をどうしてもコンテナ内へ入って手動で入力するしかできなかったことが心残りです。
expect
というコマンドを使えば、パスワード変更のような直接入力する形式の対話形式でしたら設定できました。ただし、例えばこの中から好みのフレームワークを選択してくださいという選択形式の対話形式ですと選んだ項目が反映されず、一番上の選択肢が回答として反映されました。
しかも、ベースとなるNodeイメージには、必要なソースファイルを用意してmakeコマンドで入れる必要があります。この辺の設定をDockerfileで最初から設定するのが大変な手間ですので、自動化するか対話形式のままにするかは各自次第なところだと思います。(もっと簡単な方法ありましたらぜひとも教えてください)expect
コマンドが入っておらず、yumコマンドでもインストールできなかったので
追記
コメントにてアドバイス頂きました。
nodeコンテナはDebian OSでしたのでAPTパッケージでインストールするようです。
ただ選択式はexpect
コマンドでも選択できませんでした。
対話形式ではなく設定ファイルをコピーする方法でできないか調査してみます。
次回予告
次回ですが、モジュールを使うのではなく、Ansible-benderを用いてコンテナ管理できるように挑戦してみます。
LT資料
LTのスライド資料です。
Discussion
expectはyumじゃなくてaptで入りますよ😆
yumはRedhat系になるのでnodeイメージのベースに使われてるDebian系では使えないです。
返事が遅くなり申し訳ありません。
教えてくださりありがとうございます。
インストールできまして私のやりたいことができそうです。
助かりました。