「Ansible Container」でDockerコンテナの構成管理を行う
現在、ansible-containerプロジェクトは開発終了しています。詳細は同プロジェクトのGitHubページをご覧ください。
「Ansible Container」は、構成管理ツールであるAnibleを使ってDockerコンテナのビルドや管理を行えるツールだ。記事後編となる今回は、Ansible Containerを使ってコンテナの設定を自動化する方法や、Kubernetesとの連携について紹介する。
Ansible Containerで「Role」をコンテナに適用する
記事前編では、Ansible Containerのインストールや設定ファイル、基本的なコンテナ作成と起動の流れを紹介した。続いて後編となる本記事では、Ansible Containerを使ってコンテナへのソフトウェアインストールや設定を自動化する方法を紹介していく。
「Role」とは
Ansible Containerでは、コンテナに対し適用する「Role」を指定することで、そのコンテナの構成管理を行うようになっている。RoleというのはAnsibleで使われている構成管理単位であり、その名前のとおり「役割」ベースでインストールするソフトウェアやファイル、各種設定作業を定義するようになっている。
Roleについてより詳しくはAnsibleの公式ドキュメントを参照して欲しいが、おおまかに言えばサーバー単位ではなく、目的単位で設定ファイルを用意するととらえておけば良いだろう。
さて、Ansible Container向けのRoleを用意するには複数の方法があるが、もっとも簡単なのはAnsible Containerの設定ファイルを用意したディレクトリ(ansible-container initコマンドを実行したディレクトリ)内に「roles」というディレクトリを作成し、そこに設定ファイルを作成するという方法だ。このrolesディレクトリ内では、図1のようなディレクトリ配置ルールに従って必要なファイルを配置していく。
ここに配置するファイルは表1のとおりだ。
ファイル名 | 説明 |
---|---|
tasks/main.yml | このRoleを指定した対象に適用するタスクを記述する |
handlers/main.yml | 特定のタスク実行後に実行されるHandlerを記述する |
defaults/main.yml | タスクやHandlerで使われる変数のデフォルト値を指定する |
vars/main.yml | タスクやHandlerで使われる変数を記述する |
files/ | Roleを指定した対象にコピーするファイルなどをここに格納しておく |
templates/ | 設定ファイル作成時に使用されるテンプレートファイルをここに格納しておく |
meta/main.yml | このRoleに関するメタデータを記述する |
なお、このすべてが必要なわけではなく、設定が不要なものについてはファイル/ディレクトリを作成する必要はない。
Roleを使った設定例
それでは、Ansible ContainerとRoleを使ったコンテナ設定の例として、Webサーバー用のコンテナに指定したファイルをコピーする、という作業を紹介しよう。
前編で紹介したとおり、まず適当なディレクトリ(今回は「httpd-test」とした)内でansible-container initコマンドを実行して設定ファイルのひな形を作成する。
$ mkdir httpd-test $ cd httpd-test $ ansible-container init
コンテナ作成に必要なcontainer.ymlだが、今回は下記のような内容とした。前編で紹介したものとほぼ同じだが、それに加えて適用するRoleを指定する「roles」パラメータを追加している。rolesパラメータには「test-webserver」を指定しているが、これがこのコンテナに適用されるRoleとなる。今回はRoleを1つしか指定していないが、複数を指定することも可能だ。
version: "2" settings: conductor_base: debian:jessie-backports services: test-httpd: from: "httpd:2.4" ports: - "8888:80" environment: PATH: "/usr/local/apache2/bin:/bin:/usr/bin:/usr/local/bin" command: ["httpd-foreground"] roles: - test-webserver registries: {}
続いて、rolesディレクトリおよびroles/test-webserverディレクトリを作成し、そこに必要なディレクトリとファイルを作成していく。
$ mkdir roles $ mkdir roles/test-webserver $ cd roles/test-webserver/ $ mkdir tasks $ mkdir files $ vi tasks/main.yml
コンテナの設定を行うタスクを定義するroles/test-webserver/tasks/main.ymlは、以下のようにした。
- name: copy index.html copy: src: index.html dest: /usr/local/apache2/htdocs/ mode: 0644
ここでは「copy」コマンドを実行し、「index.html」ファイルをコンテナ内の/usr/local/apache2/htdocsディレクトリにコピーする、というタスクを定義している。また、ここでコピーするindex.htmlファイルはfilesディレクトリ内に配置しておく。
これらの作業完了後、rolesディレクトリ内には次のようなファイル/ディレクトリが作成されていることになる。
$ find roles roles roles/test-webserver roles/test-webserver/tasks roles/test-webserver/tasks/main.yml roles/test-webserver/files roles/test-webserver/files/index.html
これら設定ファイルの準備が完了したら、「ansible-container build」コマンドを実行してコンテナイメージを作成する。
$ 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=httpd-test Building service... project=httpd-test service=test-httpd PLAY [test-httpd] ******************************************************************* TASK [Gathering Facts] ********************************************************* ok: [test-httpd] TASK [test-webserver : copy index.html] **************************************** changed: [test-httpd] PLAY RECAP ********************************************************************* test-httpd : ok=2 changed=1 unreachable=0 failed=0 Applied role to service role=test-webserver service=test-httpd Committed layer as image image=sha256:54ed55e81d9dc643154e449340efb6b4cab9d476c290a53c95aa96f1379d9365e service=test-httpd Build complete. service=test-httpd All images successfully built. Conductor terminated. Cleaning up. command_rc=0 conductor_id=699adc48c8afb85922645c63b9afb82100c49a32b1376a676df94cb1eda7a410 save_container=False
この出力結果から、「test-webserver」Roleが「httpd」コンテナに適用され、ファイルのコピーが行われていることが分かる。あとは「ansible-container run」コマンドを実行すれば、設定が反映されたコンテナが起動する。
Kubernetesにデプロイする
Ansible Containerではローカルで稼働しているDockerを使ってコンテナを立ち上げるだけでなく、KubernetesやOpenShiftなどで構築されたコンテナクラスタ上にコンテナを立ち上げる機能も備えている。続いては、この機能を使ってKubernetesクラスタ上にコンテナを立ち上げる例を紹介しよう。
なお、Kubernetesについてやその環境構築については今回は割愛する。こちらについて詳しくはkubernetesによるDockerコンテナ管理入門記事などを参照してほしい。
Kubernetesを利用するための設定
以下では、先に作成したWebサーバーコンテナを例にKubernetes上へのデプロイ手順を紹介しよう。なお、Kubernetesへのデプロイを行うには、Kubernetes用のパッケージをインストールしておく必要がある。もしインストールしていなかった場合、次のようにしてインストールしておこう。
# pip install ansible-container[docker,k8s]
また、Kubernetes上にコンテナをデプロイする際には、作成したイメージを一度コンテナリポジトリにアップロードする必要がある。これにはDockerの公式リポジトリであるDockerHubを使っても良いし、ローカルリポジトリを用意しても良い。ローカルリポジトリを用意し利用できるようにする手順についてもkubernetesによるDockerコンテナ管理入門記事で紹介している。
ローカルリポジトリを利用する場合に注意が必要なのが、ローカルリポジトリに対しconductorコンテナ内からアクセスできるようになっている必要がある点だ。たとえばhostsファイルを使ってローカルリポジトリのホスト名とIPアドレスの対応付けをしている場合、この情報はそのままではコンテナ内に引き継がれないためデプロイに失敗する。そのため、IPアドレスでローカルリポジトリを指定するか、もしくはDNSサーバーを用意してホスト名からIPアドレスを参照できるよう設定しておく必要がある。また、コンテナ内からローカルリポジトリにアクセスできるようファイアウォールの設定も確認しておこう。
利用するリポジトリが決まったら、まずその情報をcontainer.ymlファイルの「registries:」以下に適当な名前で追加する。たとえば「http://192.168.1.10:5000」というリポジトリを「local-test」という名前で登録する場合、以下のようになる。
version: "2" settings: conductor_base: debian:jessie-backports services: test-httpd: from: "httpd:2.4" ports: - "8888:80" environment: PATH: "/usr/local/apache2/bin:/bin:/usr/bin:/usr/local/bin" command: ["httpd-foreground"] roles: - test-webserver registries: local-test: url: "http://192.168.1.10:5000"
続いて、docker loginコマンドでこのリポジトリへのログインを行っておく。
$ docker login http://192.168.1.10:5000 Username: foo ←ユーザー名を入力 Password: ←パスワードを入力 Login Succeeded
これによって、Ansible Containerが参照する ~/.docker/config.jsonという設定ファイルが作成される。なお、独自に立ち上げたリポジトリでユーザー名やパスワードを設定していない場合、どのようなユーザー名/パスワードでも認証は成功するので、適当なユーザー名/パスワードを入力すれば良い。
また、Kubernetesサーバーやそのログインなどに関する情報については、~/.kube/configというファイルが参照される。このファイルはkubectl configコマンドで作成できる。こちらについてもkubernetesによるDockerコンテナ管理入門記事で紹介しているので、詳細はそちらを参照して欲しい。
これらの設定が完了したら、続いてビルドしたイメージをリポジトリに登録できることを確認しておこう。ただし後述する「ansible-container deploy」コマンドでは自動的にイメージのプッシュも実行するので、もしリポジトリが利用できることが確認できているのであればこの作業は実行する必要はない。
まず「ansible-container build」コマンドでコンテナをビルドし、「ansible-container push」コマンドでリポジトリへのプッシュを実行する。このとき、「--push-to」オプション引数でcontainer.yml内に記述したリポジトリ名を指定する。
$ ansible-container push --push-to local-test Parsing conductor CLI args. Engine integration loaded. Preparing push. engine=Docker™ daemon Tagging 192.168.1.10:5000/foo/httpd-test-httpd Pushing 192.168.1.10:5000/foo/httpd-test-httpd:20170614142249... The push refers to a repository [192.168.1.10:5000/foo/httpd-test-httpd] Preparing Waiting Pushing : : : 20170614142249: digest: sha256:e088007a8cbdeaf4597b1b664b4455dde302b24c2ba8d27024d56f6a9a9bf558 size: 1987 Conductor terminated. Cleaning up. command_rc=0 conductor_id=e69985e3a33f1135d448bdfc772ffc1c89e73ffc31b8ea723f9c049a7d558d3f save_container=False
設定に問題がなければ、これでコンテナイメージがリポジトリに登録される。ローカルリポジトリを利用している場合、「curl <リポジトリURL>/v2/_catalog」コマンドでリポジトリが正しく登録できているかが確認できる。
$ curl http://192.168.1.10:5000/v2/_catalog {"repositories":["foo/httpd-test-httpd"]}
リポジトリ設定が問題ないことが確認できたら、次は「ansible-container deploy」コマンドを実行して設定ファイルの準備を行う。
$ ansible-container --engine k8s deploy --push-to local-test Parsing conductor CLI args. Engine integration loaded. Preparing push. engine=K8s Tagging 192.168.1.10:5000/foo/httpd-test-httpd Pushing 192.168.1.10:5000/foo/httpd-test-httpd:20170614142249... The push refers to a repository [192.168.1.10:5000/foo/httpd-test-httpd] Preparing Waiting Layer already exists 20170614142249: digest: sha256:e088007a8cbdeaf4597b1b664b4455dde302b24c2ba8d27024d56f6a9a9bf558 size: 1987 Conductor terminated. Cleaning up. command_rc=0 conductor_id=4c949053776d6b1ea07f9340f9d11c783679dd34e152fe2542af9ae2735b2771 save_container=False Parsing conductor CLI args. Engine integration loaded. Preparing deploy. engine=K8s Verifying image for httpd Conductor terminated. Cleaning up. command_rc=0 conductor_id=8a4abe677b10fa1dc591b50f01388e334efd45977975ec3164af8b1335391c38 save_container=False
「ansible-container deploy」コマンドではイメージや設定ファイルの準備は行われるが、コンテナの起動は行われない。コンテナを起動するには、続けて「ansible-container run」コマンドを「--engine k8s」オプション引数付きで実行する。
$ ansible-container --engine k8s run Parsing conductor CLI args. Engine integration loaded. Preparing run. engine=K8s Verifying service image service=httpd PLAY [Manage the lifecycle of httpd-test on K8s] ******************************* TASK [Create namespace httpd-test] ********************************************* changed: [localhost] TASK [Create service] ********************************************************** changed: [localhost] TASK [Create deployment, and scale replicas up] ******************************** changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=3 changed=3 unreachable=0 failed=0 All services running. playbook_rc=0 Conductor terminated. Cleaning up. command_rc=0 conductor_id=a37d015c6d665e8ec12a3eb8371b2da8233c717396295673c1caff8608e127d2 save_container=False
実行に成功すれば、プロジェクト名(通常は「ansible-container init」コマンドを実行したディレクトリのディレクトリ名)と一致するネームスペース内でKubernetesのdeployやpodが作成される。今回は「httpd-test」というプロジェクト名を使用したので、次のようにネームスペースやデプロイ、Podを確認できる。
$ kubectl get namespace NAME STATUS AGE default Active 5d httpd-test Active 16h kube-system Active 5d $ kubectl -n httpd-test get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE test-httpd 1 1 1 1 16h $ kubectl -n httpd-test get pod NAME READY STATUS RESTARTS AGE test-httpd-1181566071-wdsxf 1/1 Running 0 1m
Podの停止や破棄はDockerの場合と同様、「ansible-container stop」や「ansible-container destroy」コマンドで実行できる。
$ ansible-container --engine k8s stop Parsing conductor CLI args. Engine integration loaded. Preparing to stop all containers. engine=K8s PLAY [Manage the lifecycle of httpd-test on K8s] ******************************* TASK [Stop running containers by scaling replicas down to 0] ******************* 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=34fbb1a83a92636fdee79c102a1f8107c64c4553a0f39a684ee0baf139bc554b save_container=False
デプロイ設定を追加する
先の例では利用するリポジトリ設定のみしか行っていなかったが、container.ymlファイルではKubernetesへのデプロイなどの際の設定を記述することもできる。たとえばクラスタ内でのレプリカ数を設定するには、次のように設定したいサービス以下に「k8s:」および「deployment:」パラメータを追加し、「replicas:」パラメータでレプリカ数を指定すれば良い。
version: "2" settings: conductor_base: debian:jessie-backports services: test-httpd: from: "httpd:2.4" ports: - "8888:80" environment: PATH: "/usr/local/apache2/bin:/bin:/usr/bin:/usr/local/bin" command: ["httpd-foreground"] roles: - test-webserver k8s: deployment: replicas: 2 registries: local-test: url: "http://192.168.1.10:5000"
また、デプロイ時のノード決定方法を設定する「strategy:」パラメータやなども用意されている。詳しくはドキュメントを参照してほしい。
まだ不親切な点も多いが、Ansibleユーザーには便利なAnsible Container
Ansible Containerはまだ開発段階のソフトウェアであり、そのためドキュメントが必要最低限しか用意されておらず、また問題が発生した際のメッセージも不親切で分かりにくいといった問題もある。とはいえ、現時点でも十分に活用可能であり、Ansibleを利用しているユーザーであれば簡単にコンテナの設定や管理を行える。Dockerクラスタ管理ツールはさまざまなものが登場しており、Ansible Containerの競合となるソフトウェアもあるが、AnsibleユーザーであればAnsible Containerはかなり有用なツールだと思われる。今後のバージョンアップにも期待したい。