Edited at

Ansible Containerで始めるAnsibleからのコンテナ作成(v0.9.0対応)

More than 1 year has passed since last update.

AnsibleからDockerコンテナを作成するAnsible Containerを試してみます。Ansible Containerは、Ansible Galaxyベースで作成されたRoleを元にDockerコンテナを作成するプロジェクトです。Ansible ContainerそのものもGalaxyへ登録することが可能です。

Ansibleで構成管理している方・組織は多くなってきたのではないかと思います。ただ、Mutable InfrastructureからImmutable Infrastructureへの転換でサービスの継続性・安定性が見込まれる場合はコンテナベースのアーキテクチャとすることがより望ましく、ただAnsible資産をこの転換で無駄にしないためには重要なプロジェクトなのではないでしょうか。

また、Docker Composeを使ったことがある方でしたら親しみやすい記述方法です。逆にComposeを使ったことがない方もAnsible Containerを学ぶことで、Composeの理解も進むので良かったら目を通してみてください。


コンテンツ


  • Ansible Containerの準備

  • サンプル実行を通してAnsible Containerの初歩を理解する


前提条件・前提環境


  • macOS (Sierraで動作確認)

  • Windows 10 Pro (Hyper-Vを用いるためPro)

  • Ubuntu (Trusty〜Xenialで動作確認 ※Yakkety,Zestyも恐らく動作可)

  • サンプル実行が失敗しても許せる心…回避方法を記載していますが、それでもうまくいかない可能性があります。


Windows 10の方へ

MAC, Ubuntu利用の方は次へ進んでください。

Windows 10にはWSL(Windows Subsystem for Linux)というカーネル上のサブシステムより、ユーザーランド上にLinux環境:今はBash on Ubuntu on Windowsと呼ばれる仕組みが利用できます。(今後はUbuntuだけではなくFedora, openSUSEも取り込まれる予定のようです)

(2017/10/20追記: 2017/10/17のUpdateをもって、とうとうBetaではなくなりました。UbuntuだけではないのでBash on Ubuntu on Windowsという名称はなくなり、Windows Subsystem for Linuxが正式名称になりました。)

これを有効化することで、今後はUbuntuの方と同じ方法で読み進めていくことが可能です。

有効可の手順については後ほど紹介します。


Ansible Containerの準備

Ansible Containerは、Conductorと呼ばれる中間コンテナを始めに作成し、それが最終的に作成したいコンテナに対してAnsibleを実行する仕様のため、Ansible Containerを実行するマシンにはAnsibleは不要です。ですが、せっかくなのでAnsibleのインストール方法も紹介しておきます。


前提条件のインストール【MAC】

Windows, Ubuntuの方は次へ進んでください。

Homebrewで前提条件をインストールします。


Ansible

最新への追従も早く、2017/05/12時点でバージョン2.3.0がインストールできました。

brew install ansible

※ 追記(2017/10/18): brew install ansibleの場合、Ansibleのextra moduleがインストールされませんでした。Ansibleをがっつり触っていくという方はsudo pip install ansibleなど他の方法を試してください。


Git

後ほど、コードをgit cloneするので必要になります。HomeBrewで入れるgitはBash Completionなども使えるのが便利です。

brew install git

余談ですが、bash completionのために~/.bash_profileなんかに以下を記載しておくと良いです。プロンプト(PS1)にブランチ名を表示する方法も併せて紹介します。

# bash completion

source /usr/local/etc/bash_completion.d/git-prompt.sh
source /usr/local/etc/bash_completion.d/git-completion.bash

# gitブランチをプロンプトへ表示
GIT_PS1_SHOWDIRTYSTATE=true
export PS1='\h\[\033[00m\]:\w \[\033[31m\]$(__git_ps1 \(%s\))\[\033[00m\]\$ '


Docker

macOS上ではDockerを動作させることができませんが、xhyve上にDocker Machineを稼働させ、/var/run/docker.sockより連携することでユーザは意識することなくDockerをシームレスに利用することができます。

インストール方法は公式ページを参考にしてください。

https://docs.docker.com/docker-for-mac/install/


前提条件のインストール【Windows】


WSLの有効化とAnsible

WSLとはWindows Subsystem for Linuxの略で、Linuxを動作させるためのカーネルドライバを読み込むことでユーザランド上にUbuntuを展開することで、WindowsながらもBash実行環境を得ることが可能になります。

詳細はこちらを参照してください。

Windows向けの記事ですが、WSLの実行環境はUbuntuのため、Ubuntu Trusty, Xenialの方も2章以降のAnsibleインストールは同様の手順で進めることが可能です。

http://qiita.com/komattaka/items/042537c87bb5bef0cfae


Docker

Docker for Windowsをインストールします。Hyper-V上にDocker Engineを持つVMを展開することでWindowsからDockerを実行することができるようになります。

特別な操作もありませんので公式ページを参照してください。

https://docs.docker.com/docker-for-windows/install/

Docker for Windowsは、Hyper-V上にMobyLinuxを動作させることでDockerの実行環境を得るのですが、2GBほどメモリを消費してしまいます。

今回はDocker Machineを扱うdocker-machineコマンドがあれば良いので、タスクバー右にあるDockerアイコン(表示なければインジケーター内にあります)を右クリックし「Quit Docker」をクリックし、MobyLinuxを停止します。


前提条件のインストール【Ubuntu, Windows】


Docker

WindowsはBash on Ubuntuに対して、以下を参照してDockerをインストールしてください。

Docker for Ubuntuは以下の公式ページより、Docker CEをインストールします。

https://docs.docker.com/engine/installation/linux/ubuntu/

Windowsのみ、BashにDocker Machineをインストールします。Ubuntuの方はインストールしなくても結構です。

curl -L https://github.com/docker/machine/releases/download/v0.10.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&

chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine

もしエラーが起こる場合は、URLなどが変わった可能性もあるので以下を参照してください。

https://docs.docker.com/machine/install-machine/


Git

Githubよりコードを取得するため、gitをインストールします。WindowsはBash on Ubuntuでの実行です。

sudo apt install git


Ansible Containerのインストール【共通】

MAC, Windows, Ubuntu共通の手順です。

pipよりAnsible Containerとその前提条件をインストールします。dockerはDockerを扱うためのPythonライブラリのことで、Docker本体を意味している訳ではありません。

pip install ansible-container[docker]

もし上記でエラーが起こる場合は、dockerのインストールを分けます。

pip install ansible-container docker

WindowsまたはUbuntuの方で、依存関係でもしエラーが生じた場合はこちらも行います。筆者はUbuntuでruamel.yamlがインストールされませんでした。その依存関係を解決するためのパッケージを入れ、その後で上記のコマンドを実行してください。

sudo apt install python2.7-dev libyaml-dev


Docker Machineの用意

手元の端末毎にそれぞれ操作が異なります。


Docker Machine【MAC】

docker machineを用意し、dockerコンテナを起動できるようにしておきます。

MACではVirtual Boxを使うのが手っ取り早いので--driver virtualboxを指定し、dockerという名前のdocker machineを作成します。(Virtual Boxのインストール方法は省略します)

docker-machine create --driver virtualbox docker

Virtual Box上にdockerという名前のVMが作成されていることを確認できるはずです。


Docker Machine【Windows 10】

Windows 10の場合はHyper-V上にDocker Machineを用意するのが手っ取り早いです。Windows 10はHyper-V ClientというWindows Serverのそれと比べると少ない機能のHyper-Vが利用できます。VMレプリカなどServerとして必要な機能が使えないだけなので十分です。

Hyper-Vには少なくとも1つの外部接続用のvSwitchがあることを前提とします。

まずはWindows PowerShellからDocker Machineを作成しますが、Hyper-Vを操作するため、PowerShellは右クリックメニューより「管理者として実行」で起動してください。

docker-machine create --driver hyperv docker

DockerMachine_hyper-v.png

暫く待つと、Hyper-V上に「docker」という名前のVMができていると思います。

そのままdocker-machine envコマンドを使って環境変数を確認します。

docker-machine env docker

以下のような表示になります。Bashで使うのでコピーしておいてください。

PS C:\WINDOWS\system32> docker-machine env docker

$Env:DOCKER_TLS_VERIFY = "1"
$Env:DOCKER_HOST = "tcp://192.168.1.13:2376"
$Env:DOCKER_CERT_PATH = "C:\Users\kusak\.docker\machine\machines\docker"
$Env:DOCKER_MACHINE_NAME = "docker"
$Env:COMPOSE_CONVERT_WINDOWS_PATHS = "true"
# Run this command to configure your shell:
# & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env docker | Invoke-Expression

次に、Ansible ContainerはBash on Ubuntuより実行することになるため、BashからDocker Machineを操作できるようにします。

Bashを開き、以下を.bash_profileへ記載します。(.bash_profileじゃなくても良いですが、ログイン時に勝手に読み込まれるのでオススメしておきます)

ここで、先程のdocker-machine env内容を元に、以下のような内容に変更します。

変更ポイント:


  • 全行:先頭をexportに変更する。

  • 全行:「=」の両隣のスペースを削除する。

  • DOCKER_CERT_PATH:「/mnt/c/...」へ変更する。ユーザ名は各自修正すること。

export DOCKER_TLS_VERIFY="1"

export DOCKER_HOST="tcp://192.168.1.13:2376"
export DOCKER_CERT_PATH="/mnt/c/Users/(ユーザ名)/.docker/machine/machines/docker/"
export DOCKER_MACHINE_NAME="docker"
export COMPOSE_CONVERT_WINDOWS_PATHS="true"

.bash_profileは書いただけでは読み込まれないので、sourceコマンドを使って読み込みます。

source .bash_profile

Docker Machineへ接続できることを確認します。

docker ps

以下のようなリプライが返ってきて、エラーがないことを確認します。

$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES


Docker Machine【Ubuntu】

Ubuntuは自分自身上にDockerコンテナを起動することが可能(Docker Engineを利用可能)なので、Docker Machineの用意は不要です。

以下のコマンドにて、dockerが起動していることを確認してください。

sudo systemctl status docker

もし、runningではなければ以下のコマンドで起動します。

sudo systemctl start docker


共通

Docker Machineの準備が整ったら、以下のようにDocker Machineの情報を環境変数に入れます。

eval $(docker-machine env docker)

環境変数は以下のようになります。(MACの例を記載)

$ set | grep -i docker

DOCKER_CERT_PATH=/Users/01008455/.docker/machine/machines/docker
DOCKER_HOST=tcp://192.168.99.100:2376
DOCKER_MACHINE_NAME=docker
DOCKER_TLS_VERIFY=1

以上でAnsible Containerの準備が完了しました。(疲弊)


Ansible Containerのデモを起動してみる

デモ用のプロジェクトを動かしてみます。Nginxを起動するだけの簡単なコンテナを実行するのが目的です。

まずはデモプロジェクトのgit cloneから。

git clone https://github.com/komattaka/ansible-container-demo.git

Ansible Containerはカレントディレクトリのコードを参照してコンテナを作成していくので、移動します。

cd ansible-container-demo

続いてansible-containerコマンドを使ったコンテナの作成などを行っていきますが、その前にanisble-containerコマンドの体系を確認していきましょう。


  • コンテナのビルド: ansible-container build

  • ローカル環境でのコンテナ起動: ansible-container run

  • コンテナレジストリへの登録: ansible-container push

  • KubernetesまたはOpenShiftへのデプロイ: ansible-container deploy (v0.4.0以下の頃はshipitでした)

それでは、まずはbuild=コンテナ作成を行います。

と言いたいのですが、バグのせいでansible-container buildの過程で行われるdocker pullが正常に行われないため、今回必要なubuntu:xenialは手動でdocker pullしたいと思います…。(2018/05/07追記:v0.9.1になってから、このバグは見られなくなりましたが、一応記載を残しておきます)

docker pull ubuntu:xenial

では改めて、ビルドを行います。このコマンドでDocker imageの作成が行われます。

anisble-container --debug build

--debugを付けたので、Ansibleのタスクが動いているのがプロンプトに表示されているはずです。(version0.9.0の場合、--debugを付けた方が安定性が高いので、付けたほうが良いです。付けずにいるとタイムアウトが短いような気がします、詳細は分かっていません)

しばらく待って完了すると、この段階でdocker image lsでコンテナイメージが表示されます。

$ docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE
ansible-container-demo-web 20170511115247 f2ffd07029a6 14 hours ago 390MB
ansible-container-demo-web latest f2ffd07029a6 14 hours ago 390MB
ansible-container-demo-conductor latest 9c0a4399c8d0 14 hours ago 582MB
ubuntu xenial f7b3f317ec73 2 weeks ago 117MB

Docker Machine上では、project名-group名という名前のコンテナ、TAGは日付YYYYMMDDhhmmssの形式と最新のものにはlatest(同じ名前・groupで作成される更新される)が付くようです。

末尾にconductorと付くものもありますが、これはbuild対象のコンテナに対してAnsibleを実行するためのコンテナで、AnsibleやPython Libraryなどが含まれており、これは"centos:7"イメージをベースに作成されます。

では、作成したコンテナを起動してみます。Docker Machine上で起動します。

ansible-container run

内部的にはAnsibleのdocker_serviceモジュールを用いてコンテナを起動しているようです。

$ ansible-container run

Parsing conductor CLI args.
Engine integration loaded. Preparing run. engine=Docker™ daemon
Verifying service image service=web

PLAY [localhost] ***************************************************************

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=98249f6fd306692012e8355771195b4952ebf7519b496e1d93743d9f6c748016 save_container=False

今回のデモではNginxを起動するだけですので、アクセスしてみるとWelcomeページが表示されるはずです。下記の通りポートマッピングは「80:80」としているので、コンテナ内部の80番はDocker Machineの80番ポートにアクセスすれば良いです。

$ docker ps

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
32fb1a8587f9 ansible-container-demo-web:20170511115247 "/usr/sbin/nginx -..." About a minute ago Up About a minute 0.0.0.0:80->80/tcp acdemo_web_1

MAC, Windowsの方でDocker MachineのIPアドレスが分からない方は、以下のコマンドで推測できます。1行目DOCKER_HOSTに書いてありますね。

$ env | grep -i docker

DOCKER_HOST=tcp://192.168.99.100:2376
DOCKER_MACHINE_NAME=docker
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/Users/komattaka/.docker/machine/machines/docker

筆者のDocker Machineアドレスは http://192.168.99.100/ でしたのでアクセスします。

nginx_welcome.png

表示されました。

最後に停止します。

ansible-container stop

このコンテナを削除したい場合はdestroyを指定します。

ansible-container destroy


Ansible Containerの実装方法をちょっとだけ

さて、デモに使ったAnsible Containerのコードですが、少しだけ解説してみます。


container.yml

先頭の"version"はDocker Composeのバージョンを示すのですが、この通りcontainer.ymlはDocker Composeに対応しています。

version: "2"

services:
web:
from: "ubuntu:xenial"
ports:
- "80:80"
command: ["/usr/sbin/nginx", "-g", "daemon off;"]
roles:
- "apache-container"

それぞれの意味を記します。

key
sub key
意味

version

Composeのversionを指定します。1 or 2

services

ネストした1番目のkeyがgroup名になります。デモで利用したコードでは"web"というgroupになります。

from
どのコンテナをベースにするかを指定します。v0.4.0の頃はimageでしたが、直感的に分かるkey名になりましたね。

ports
外部から参照させるためのポートを指定します。内外で同じポートを使う場合でも、分かりやすく"80:80"のように書いておくと良いかと思います。

command
コンテナ起動時のコマンドを指定します。デモでは、Nginxは"/etc/init.d/nginx start"はバックグラウンドでの実行になってしまいコンテナがすぐ落ちてしまうので、フォアグラウンドで実行されるように"-g daemon off;"を引数にするように指定しています。

roles
コンテナに対して実行するRoleを指定します。RoleをAnsible Galaxyより取得する場合はrequirements.ymlにも記載する必要があります。

dev_overrides
ansible-container runの場合にのみ適用され、build, deploy実行時は無視されます。ローカルや開発環境でのみ試すことがある場合に有用です。例えば、開発環境のみポートを変えてみる、とか、コンフィグがfeature flagsのような作りになっている時に開発を示す環境変数を与える、ということが可能です。デモでは記載ありませんが、重要なパラメータのため紹介しました。

詳細は以下の公式リファレンスを参照してください。

https://docs.ansible.com/ansible-container/container_yml/reference.html


ansible.cfg

これはAnsible ContainerではなくAnsibleそのものでも利用されているもののため、特記することはしません。

デモではUbuntu minimalのイメージを利用したのですが、これにはPythonが入っていないため最初のGather Fact(setupモジュール)が動作しないようにしています。

本来はAnsibleの前提条件を満たすためのパッケージを入れたベースコンテナを保存しておき、imageにはそのイメージを指定することが望ましいかと思います。(毎回apt update/installする時間がもったいないため)

[defaults]

gathering = explicit


meta.yml

Ansible ContainerプロジェクトをAnsible Galaxyに登録する際には必要になってきます。今回は登録しないため、適当な記述としています。

galaxy_info:

author: Your name
description: Describe your awesome application here.
company: Your company
license: license (GPLv2, CC-BY, etc)

min_ansible_container_version: 0.9.0.0

tags: []


requirements.yml

Roleをどこから取得するかを記載します。ここで指定するRoleはAnsible Galaxyに登録されている必要はなく、GithubやGitLabでも構いません。実際にデモではGithubから取得しています。

内部的にはConductor Image作成(ansible-container build)時にansible-galaxy install -r requirements.ymlが動作し、Ansible実行へと流れていきます。

- src: git+https://github.com/komattaka/nginx-container.git

version: "remotes/origin/master"


ansible-requirements.txt

これはbuild対象のコンテナに対してAnsibleを実行するConductorにインストールされるPython Libraryを指定します。Python Docker Libraryはバージョン〜2.1.0はバグがありAnsibleによるComposeが失敗するため、2.2以上を明示的に記載しています。(今は記載する必要ないかもしれませんが…)

# These are the python requirements for your Ansible Container builder.

# You do not need to include Ansible itself in this file.
docker>=2.2.1


あとがき

Ansible Containerは、まだversion 1にもなっていないプロジェクトです。ですが、KubernetesやOpenShiftへの対応、またバージョンが0.9.0になって(まだバグはありますが)安定性の向上や直感的な記述への変更など、これからが非常に期待できるプロジェクトだと思います。

ここまで読んでいただきまして、ありがとうございました。


ことわり

社内勉強会のついでの記載のため、もしかしたら閉じるかもしれません。