目次


Ansible を使って Docker コンテナーをプロビジョニングする

プレイブック、プラグイン、Docker モジュールを使って Ansible 環境を構築して拡張する

Comments

Docker が極めて高い評判を得ている理由は、便利なコマンド・ライン・インターフェース (CLI) ツールと HTTP API ツールからコンテナーをパッケージ化し、実行、保守するための統一された方法を生み出したためです。こうした単純化によって、この Docker というテクノロジーを利用するにあたっての壁が低くなり、Docker ではアプリケーションとそのランタイム環境を、自己完結したイメージとして 1 つの単純な Dockerfile にパッケージ化することが実現できるようになりました。Docker は、開発者がより複雑なプロジェクトを提供できるようにしますが、それでもなお、それらのコンテナーを構成するのは開発者の仕事であることに変わりはありません。この記事では、Ansible が簡潔な構文でどのようにして構成マネージャーの機能を実現しているのか、その方法を紹介します。あらゆるスタックを、Python と Docker だけをインストールして作成する方法を学んでください。

Ansible の詳細に踏み込む前に、Ansible についての分析で取り上げられた、以下の点について検討してみましょう。

  • コンテナーによってもたらされた新しいワークフローが登場したにも関わらず、オーケストレーション・ツールや構成ツールは変わらずに使われています。
  • Ansible や Salt などの新参ツールが Chef や Puppet などの既存のツールに挑んでいます。
  • Docker に関与している多くの開発者たちは、これらのツールにも関心を持っています。

明確にするために言っておきますが、Docker では完全に隔離されたスタック環境をほんの数秒で立ち上げることや、サーバー間でまったく同一のセットアップを複製することができますが、その一方で開発用にも本番用にも、Docker にはエンド・ツー・エンドのエクスペリエンスを提供する堅牢なツールが含まれていません。Docker チームは、これらの進化していくニーズに新たなクラスタリング・ツールで対応し、コンテナーを大規模に実行するための信頼性の高いソリューションへと Docker を変えようとしました。それでもなお、Docker ではタスクを手作業でハードコーディングして、共通のセットアップを繰り返さなければなりません。つまり、Docker の主要なオーケストレーション・プロセスについても、コンテナーの構成管理についても、依然として解決されていないのです。この記事では、これらの問題に対処するために、Docker で Ansible を使用する方法を説明します。

DevOps の登場

最近のアプリケーションは、本番へ移行する前に、複雑なデプロイメント・パイプラインが関わってくるのが通常です。ベスト・プラクティスとして提案されているのは、短期間のイテレーションが終わるごとに、コードを早い段階で頻繁にリリースすることです。このタスクを手作業で実行するとなると、規模が大きくなったときに対応できないため、組織は開発者とシステム管理者の中間をとって、このプロセスを改良するようになりました。こうして誕生したのが DevOps です。DevOps が誕生して以来、アジャイルな (機動的な) チームでは、コードをテストしてユーザーに提供する方法を、強力なものにして自動化しようと努めています。

企業は、最先端のテクノロジーと手法を実装することで、サーバー上のコードの信頼性を確保しているものの、アプリケーションの規模が大きくなり、複雑さが増してくるなかで、開発者とシステム管理者には次から次へと数々の課題が突き付けられます。これまで以上に、製品をサポートするコミュニティー主導のツールが必要になってきているのです。

Ansible の拡張可能な設計

このような環境において、Ansible はインフラストラクチャーを管理するための興味深いフレームワークとなります。Ansible を使用すると、サーバー用に定義されるもの (インストールするパッケージや、コピーするファイルなど) を管理することや、その構成を数千台のサーバーにまでスケーリングすることが可能です。Ansible ではプレイブックによって、クラスターに要求される状態の確実な表現が構成されます。Ansible の YAML 構文と広範なモジュールのリストによって生成される構成ファイルは、読みやすくてどの開発者でもすぐに理解できるものになっています。Chef や Puppet とは異なり、Ansible はエージェントレスです。つまり、SSH で接続しさえすれば、リモート・ホスト上でコマンドを実行することができます。以上のことから明らかなように、Ansible では簡単に、DevOps の複雑さに対処することができます。

しかしながら、Ansible は、コンテナーの使用が急増してクラウド開発環境に革命を起こす前に設計されたものです。それでも Ansible が関係してくるのでしょうか?マイクロサービスでは、そのパラダイムと複雑な開発環境に対処するために、以下の新しい要件が導入されました。

  • 軽量のイメージであること。トランスポートしやすくするため、またはコストを削減するために、イメージの依存関係は必要最小限にまで取り除かれます。
  • 1 つのことを目的とした単一のプロセスであること。アプリケーションでどうしても必要とされているのでなければ、SSH デーモンを実行する必要はありません。
  • 一時的であること。コンテナーは、いつでも破棄されることや、移動されること、さらには復活させられることが求められます。

以上のコンテキストでは、Ansible の拡張可能なアーキテクチャーが問題に対処します。Docker モジュールは、より上位のレベルでホストとコンテナーを管理します。この環境に、どのオーケストレーション・ツール (Google の Kubernetes、または New Relic の Centurion) が最適であるかについては議論の余地があるかもしれませんが、Docker モジュールは効率的に機能します。これが、この記事で Docker モジュールを選択した理由です。ただし、公式の Ansible イメージから起動されるコンテナーをビルドして、その内部からローカル・モードでプレイブックを実行するという手法もあります。この手法は Packer に極めてよく適合し、多くの使用ケースに適しているのも確かですが、他との共存ができないことが多いのが欠点となります。

  • 1 つの基本イメージを使用するしかなく、特殊なレシピや他のスタックを利用することができません。
  • 生成される成果物は Ansible とその依存関係をインストールしますが、これらの依存関係は、実際のアプリケーションとはまったく関係がなく、成果物を不必要に重くしています。
  • Ansible は数千台のサーバーを管理できるものの、1 つのコンテナーしかプロビジョニングしません。

この手法では、コンテナーを小さな VM とみなし、その VM で特定のソリューションを使用することになります。幸い、Ansible ではモジュール式の設計が採用されていて、複数のモジュールがさまざまなモジュールに分散されます。さらに、Ansible のほとんどの機能はプラグインによって拡張することができます。

次のセクションでは、Ansible を自分の要求に適応させる上で効果的な環境を構築します。

Ansible 環境を構築する

例として、簡単にデプロイできて、軽量のコンテナー内にアプリケーション環境を構成するツールが必要だとします。コンテナーとは別に、Ansible がインストールされたクライアント・ノードも必要になります。そのノードを使って、コマンドを Docker デーモンに送信するためです。図 1 に、この例でのセットアップを示します。

図 1. Ansible でコンテナーをプロビジョニングするために必要なコンポーネント
Ansible でコンテナーをプロビジョニングするために必要なコンポーネントを示す図
Ansible でコンテナーをプロビジョニングするために必要なコンポーネントを示す図

この構成で管理しなければならない依存関係は、コンテナーから Ansble を実行することで、最小限に抑えられます。このアーキテクチャーでは、ホストの役割が、コンテナーとコマンドとの間の通信ブリッジに制限されます。

Docker をサーバーにインストールするには、以下のようにさまざまな方法があります。

  • docker-machine を使用して、リモート・ホストにインストールする。
  • ローカルにインストールする。一言付け加えると、本格的なコンテナー・ベースのインフラストラクチャーを自分で管理したくない場合は、外部プロバイダーを利用することを検討してください。
  • 外部プロバイダーを利用する。
  • Docker コンテナーを Windows 上または Mac 上で実行する軽量の Linux ディストリビューション boot2docker を使用する。

どのソリューションを選ぶかに関わらず、必ず Docker バージョン 1.3 またはそれ以降のバージョンを導入してください (バージョン 1.3 から、プロセス・インジェクションが導入されています)。また、Ansible コマンドをセキュアに処理するために、SSH サーバーを実行する必要もあります。

リスト 1 に記載するコマンドは、公開鍵を使用して、便利で堅牢な認証方法をセットアップします。

リスト 1. 公開鍵を使用して認証をセットアップするコマンド
# install dependencies
sudo apt-get install -y openssh-server libssl-dev
# generate private and public keys
ssh-keygen -t rsa -f ansible_id_rsa
# allow future client with this public key to connect to this server
cat ansible_id_rsa.pub > ~/.ssh/authorized_keys
# setup proper permissions
chmod 0700  ~/.ssh/
chmod 0600  ~/.ssh/authorized_keys
# make sure the daemon is running
sudo service ssh restart

SSH とセキュリティーをどのように構成するかについては、この記事では取り上げないので、興味がある読者の方は、/etc/ssh/sshd_config ファイルを調べれば、SSH を構成する上での選択肢について詳しく学ぶことができます。

次のステップは、Ansible を実行するクライアント・コンテナーに公開鍵をロードして、ビルダー・コンテナーをプロビジョニングすることです。ビルダーをプロビジョニングするには、Dockerfile を使用します。リスト 2 を参照してください。

リスト 2. ビルダーをプロビジョニングする Dockerfile
FROM python:2.7

# Install Ansible from source (master)
RUN apt-get -y update & \
    apt-get install -y python-httplib2 python-keyczar python-setuptools python-pkg-resources
git python-pip & \
    apt-get clean & rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN pip install paramiko jinja2 PyYAML setuptools pycrypto>=2.6 six \
    requests docker-py  # docker inventory plugin
RUN git clone http://github.com/ansible/ansible.git /opt/ansible & \
    cd /opt/ansible & \
    git reset --hard fbec8bfb90df1d2e8a0a4df7ac1d9879ca8f4dde & \
    git submodule update --init

ENV PATH /opt/ansible/bin:$PATH
ENV PYTHONPATH $PYTHONPATH:/opt/ansible/lib
ENV ANSIBLE_LIBRARY /opt/ansible/library

# setup ssh
RUN mkdir /root/.ssh
ADD ansible_id_rsa /root/.ssh/id_rsa
ADD ansible_id_rsa.pub /root/.ssh/id_rsa.pub

# extend Ansible
# use an inventory directory for multiple inventories support
RUN mkdir -p /etc/ansible/inventory & \
    cp /opt/ansible/plugins/inventory/docker.py /etc/ansible/inventory/
ADD ansible.cfg  /etc/ansible/ansible.cfg
ADD hosts  /etc/ansible/inventory/hosts

上記の命令は公式ビルドから引用したもので、Ansible マスター・ブランチに対するコミット fbec8bfb90df1d2e8a0a4df7ac1d9879ca8f4dde により、実際のインストールを自動化します。

これで、ホスト構成ファイルと ansible.cfg 構成ファイル (リスト 3 とリスト 4 を参照) がパッケージ化されました。コンテナーを使用することで、確実に同じ環境を共有することになります。例えば、この Dockerfile は、Python バージョン 2.7.10 と Ansible バージョン 2.0.0 をインストールします。

リスト 3. ホスト構成ファイル
# hosts
# this file is an inventory that Ansible is using to address remote servers. 
Make sure to replace the information with your specific setup and variables 
that you don't want to provide for every command.

[docker]
# host properties where docker daemon is running
192.168.0.12 ansible_ssh_user=xavier
リスト 4. Ansible 構成ファイル
# ansible.cfg

[defaults]

# use the path created from the Dockerfile
inventory = /etc/ansible/inventory

# not really secure but convenient in non-interactive environment
host_key_checking = False
# free you from typing `--private-key` parameter
priva_key_file = ~/.sh/id_rsa

# tell Ansible where are the plugins to load
callback_plugins   = /opt/ansible-plugins/callbacks
connection_plugins = /opt/ansible-plugins/connections

Ansible コンテナーをビルドするには、その前に、DOCKER_HOST 環境変数をエクスポートする必要があります。Ansible はこの環境変数を使って、リモートの Docker デーモンに接続するためです。HTTP エンドポイントを使用する際は、/etc/default/docker に変更を加える必要があります (リスト 5 を参照)。

リスト 5. /etc/default/docker に変更を加える
# make docker to listen on HTTP and default socket
DOCKER_OPTS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock"

変更内容を構成ファイルに適用するために、コマンド sudo service docker restart を実行して Docker デーモンを再起動します。

以下のコマンドを実行すると、実行した場所から Ansible コンテナーがビルドされて検証されます (リスト 6 を参照)。

リスト 6. Ansible コンテナーをビルドして検証するコマンド
# you need DOCKER_HOST variable to point to a reachable docker daemon
# pick the method that suits your installation

# for boot2docker users
eval "$(boot2docker shellinit)"
# for docker-machine users, provisioning the running VM was named "dev"
eval "$(docker-machine env dev)"
# for users running daemon locally
export DOCKER_HOST=tcp://$(hostname -I | cut -d" " -f1):2375
# finally users relying on a remote daemon should provide the server's public ip
export DOCKER_HOST=tcp://1.2.3.4:2375

# build the container from Dockerfile
docker build -t article/ansible .

# provide server API version, as returned by `docker version | grep -i "server api"`
# it should be at least greater or equal than 1.8
export DOCKER_API_VERSION=1.19

# create and enter the workspace
docker run -it --name builder \
    # make docker client available inside
    -v /usr/bin/docker:/usr/bin/docker \
    -v /var/run/docker.sock:/var/run/docker.sock \
    # detect local ip
    -e DOCKER_HOST=$DOCKER_HOST \
    -e DEFAULT_DOCKER_API_VERSION=DOCKER_API_VERSION \
    -v $PWD:/app -w /app \  # mount the working space
    article/ansible bash

# challenge the setup
$ container > ansible docker -m ping
192.168.0.12 | SUCCESS => {
    "invocation": {
        "module_name": "ping",
        "module_args": {}
    },
    "changed": false,
    "ping": "pong"
}

ここまでのところ、順調に進んでいます。これで、コンテナーからコマンドを実行できるようになりました。次のセクションでは、Docker 固有の Ansible 拡張を使用します。

プレイブックとプラグインを使用して Ansible 環境を拡張する

Ansible の実行をその中核で自動化するのはプレイブックです。プレイブックとは、実行するすべてのタスクと、それらのタスクのプロパティーを指定する YAML ファイルです (リスト 7 を参照)。

また、Ansible はユーザーが指定したホストをインフラストラクチャー内の具体的なエンド・ポイントにマッピングするために、インベントリーも参照します。前のセクションで使用されている静的な hosts ファイルとは異なり、Ansible は動的コンテンツもサポートします。以下の組み込みリストには、Docker デーモンに対してクエリーを実行可能な Docker プラグインが含まれています。このプラグインによって、かなりの量の情報を Ansible プレイブックと共有することができます。

リスト 7. Ansible プレイブック
# provision.yml

- name: debug docker host
  hosts: docker
  tasks:
  - name: debug infrastructure
    # access container data : print the state
    debug: var=hostvars["builder"]["docker_state"]

# you can target individual containers by name
- name: configure the container
  hosts: builder
  tasks:
   - name: run dummy command
     command: /bin/echo hello world

リスト 8 に記載するコマンドは、Docker ホストに対してクエリーを実行し、ファクトをインポートしてそのいくつかを出力するとともに、ファクトを使用して、ビルダー・コンテナーに対する 2 つ目のタスク (リスト 7 に記載されています) を実行します。

リスト 8. Docker ホストに対してクエリーを実行するコマンド
ansible-playbook provision.yml -i /etc/ansible/inventory
# ...
TASK [setup] ********************************************************************
fatal: [builder]: FAILED! => {"msg": "ERROR! SSH encountered an unknown error during the
connection. Re-run the command using -vvvv, which enables SSH debugging
output to help diagnose the issue", "failed": true}
# ...

Ansible は、SSH サーバーを実行しないので、コンテナーに到達することができません。SSH サーバーは、追加で管理するプロセスであり、実際のアプリケーションとはまったく関係がありません。この問題は、次のセクションで接続プラグインを使用することによって解消します。

接続プラグインとは、転送用のコマンド (SSH またはローカルの実行など) を実装するクラスです。Docker 1.3 には、docker exec が用意されていて、コンテナー名前空間内でタスクを実行することができます。さらに読者の方は、前に特定のコンテナーをターゲットにする方法を学習しているので、その機能を使ってプレイバックを処理することができます。

他のタイプのプラグインと同じく、接続フック (リスト 9 を参照) は抽象クラスを継承するため、前提とされるディレクトリー (ansible.cfg 構成ファイルの中で構成した /opt/ansible-plugins/connections) に接続フックを配置すると、接続フックは自動的に使用可能になります。

リスト 9. 接続プラグイン
# saved as ./connection_plugins/docker.py

import subprocess
from ansible.plugins.connections import ConnectionBase

class Connection(ConnectionBase):

   @property
    def transport(self):
        " Distinguish connection plugin. "
        return 'docker'

   def _connect(self):
        " Connect to the container. Nothing to do "
        return self

   def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False,
                     executable='/bin/sh', in_data=None, su=None,
                     su_user=None):
        " Run a command within container namespace. "

    if executable:
        local_cmd = ["docker", "exec", self._connection_info.remote_addr, executable, '-c', cmd]
    else:
        local_cmd = '%s exec "%s" %s' % ("docker", self._connection_info.remote_addr, cmd)

    self._display.vvv("EXEC %s" % (local_cmd), host=self._connection_info.remote_addr)
    p = subprocess.Popen(local_cmd,
        shell=isinstance(local_cmd, basestring),
        stdin=subprocess.PIPE, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)

    stdout, stderr = p.communicate()
    return (p.returncode, '', stdout, stderr)

    def put_file(self, in_path, out_path):
        " Transfer a file from local to container "
        pass

    def fetch_file(self, in_path, out_path):
        " Fetch a file from container to local. "
        pass

    def close(self):
        " Terminate the connection. Nothing to do for Docker"
        pass

上記のコードは、デフォルトの ssh ではなく、ローカルの docker exec を使用してコマンドを実行する Ansible のメソッドに接続します。Ansible にこのプラグインを使用するよう指示するには、いくつかのセットアップ・ステップを組み立て直す必要があります (リスト 10 を参照)。

リスト 10. docker exec 対応の接続プラグイン
# modify the builder Dockerfile to upload the plugin code 
where Ansible is expecting connection plugins
echo "ADD connection_plugins/docker.py /opt/ansible-plugins/connections/docker.py" > Dockerfile

# then, you need to explicitly tell which connection hook to use 
when executing playbooks.
# you can achieve this by inserting the 'connection' property at the top 
of provision tasks in provision.yml

- name: configure the container
  connection: docker
  hosts: builder

# you are ready to redeploy the builder container 
# (providing DOCKER_HOST and DOCKER_API_VERSION are still set like before)

# rebuild the image
docker build -t article/ansible .

# restart the builder environment
docker run -it --name builder \
    # make docker client available inside
    -v /usr/bin/docker:/usr/bin/docker \
    -v /var/run/docker.sock:/var/run/docker.sock \
    # detect local ip
    -e DOCKER_HOST=$DOCKER_HOST \
    -e DEFAULT_DOCKER_API_VERSION=DOCKER_API_VERSION \
    -v $PWD:/app -w /app \  # mount the working space
    article/ansible bash

# rerun provisioning from inside
ansible-playbook -i /etc/ansible/inventory provision.yml
# ... Hurrah, full green output ...

ここまでは、Ansible タスクをコンテナー内で実行してきたため、コンテナーに関する要件も、ホストに関する要件もそれほど多くはありませんでした。この実装は初期要件を満たすものの、対処しなければならない不正確さが残っています。

上記のコードは同じノード上でタスクを実行しましたが、それよりも現実的なワークフローでは、新しい基本イメージを立ち上げてプロビジョニングし、最終的には成果物をコミット、プッシュ、シャットダウンすることになるでしょう。Ansible に組み込まれた Docker モジュールのおかげで、コードを追加しなくても、これらのステップを実現することができます (リスト 11 を参照)。

リスト 11. 新しい基本イメージを立ち上げる、Ansible の Docker モジュール
---
- name: initialize provisioning
  hosts: docker

  - name: start up target container
    docker:
      image: python:2.7
      name: lab
      pull: missing
      detach: yes
      tty: yes
      command: sleep infinity
      state: started
  # dynamically update inventory to make it available down the playbook
  - name: register new container hostname
    add_host: name=lab

- name: provision container
  connection: docker
  hosts: lab
  tasks:
      # ...

- name: finalize build
  hosts: docker
  tasks:
    - name: stop container
      docker:
        name: lab
        image: python:2.7
        state: stopped

前述のとおり、プロビジョニングが正常に完了してビルドされたイメージに自動的に名前が付けられて保管されるとしたら都合が良いのですが、あいにく Ansible の Docker モジュールは、イメージにタグを付けてプッシュするためのメソッドを実装していません。この制限は、単純なシェル・コマンドを使って克服することができます (リスト 12 を参照)。

リスト 12. イメージに名前を付けて保管するシェル・コマンド
# name the resulting artifact under a human readable image tag
docker tag lab article/lab:experimental

# push this image to the official docker hub
# make sure to replace 'article' by your own Docker Hub login (https://hub.docker.com)
# (this step is optional and will only make the image available from any docker host. 
You can skip it or even use your own registry)
docker push article/lab:experimental

ツールは形になってきましたが、必要不可欠な機能がまだ欠けています。それは、レイヤー・キャッシングです。

Dockerfile を使ってコンテナーをビルドするには、通常、正しくビルドされるようになるまで何度も処理を繰り返す必要があります。このプロセスを大幅にスピードアップするために、正常に完了したステップがキャッシングされて、以降の実行で再利用されます。

この動作を複製するために、このツールはタスクが正常に完了するごとにコンテナーの状態をコミットします。ビルド・エラーが発生した場合、ツールは最後のスナップショットからプロビジョニング・プロセスを再開します。Ansible はべき等のタスクを約束するため、前に成功したタスクが再び処理されることはありません。

Ansible では、コールバック・プラグインを使用して、タスクのイベントに接続することができます (リスト 13 を参照)。リスト 13 に示されているクラスは、それぞれに、プレイブックのライフサイクルのさまざまなステップでトリガーされる特定のコールバックを実装することになっています。

リスト 13. タスクのイベントに接続するコールバック・プラグイン
# save as callback_plugins/docker-cache.py
import hashlib
import os
import socket

# Hacky Fix `ImportError: cannot import name display`
# pylint: disable=unused-import
import ansible.utils
import requests
import docker


class DockerDriver(object):
    " Provide snapshot feature through 'docker commit'. "

    def __init__(self, author='ansible'):
        self._author = author
        self._hostname = socket.gethostname()
        try:
            err = self._connect()
        except (requests.exceptions.ConnectionError, docker.errors.APIError), error:
            ansible.utils.warning('Failed to contact docker daemon: {}'.format(error))
            # deactivate the plugin on error
            self.disabled = True
            return

        self._container = self.target_container()
        self.disabled = True if self._container is None else False

    def _connect(self):
        # use the same environment variable as other docker plugins
        docker_host = os.getenv('DOCKER_HOST', 'unix:///var/run/docker.sock')
        # default version is current stable docker release (10/07/2015)
        # if provided, DOCKER_VERSION should match docker server api version
        docker_server_version = os.getenv('DOCKER_VERSION', '1.19')
        self._client = docker.Client(base_url=docker_host,
                                     version=docker_server_version)
        return self._client.ping()

    def target_container(self):
        " Retrieve data on the container you want to provision. "
        def _match_container(metadatas):
            return metadatas['Id'][:len(self._hostname)] == self._hostname

        matchs = filter(_match_container, self._client.containers())
        return matchs[0] if len(matchs) == 1 else None

    def snapshot(self, host, task):
        tag = hashlib.md5(repr(task)).hexdigest()
        try:
            feedback = self._client.commit(container=self._container['Id'],
                                           repository='factory',
                                           tag=tag,
                                           author=self._author)
        except docker.errors.APIError, error:
            ansible.utils.warning('Failed to commit container: {}'.format(error))
            self.disabled = True


# pylint: disable=E1101
class CallbackModule(object):
    "Emulate docker cache.
    Commit the current container for each task.

    This plugin makes use of the following environment variables:
        - DOCKER_HOST (optional): How to reach docker daemon.
          Default: unix://var/run/docker.sock
        - DOCKER_VERSION (optional): Docker daemon version.
          Default: 1.19
        - DOCKER_AUTHOR (optional): Used when committing image. Default: Ansible

    Requires:
        - docker-py >= v0.5.3

    Resources:
        - http://docker-py.readthedocs.org/en/latest/api/
    "

    _current_task = None

    def playbook_on_setup(self):
        " initialize client. "
        self.controller = DockerDriver(self.conf.get('author', 'ansible'))

    def playbook_on_task_start(self, name, is_conditional):
        self._current_task = name

    def runner_on_ok(self, host, res):
        if self._current_task is None:
            # No task performed yet, don't commit
            return
        self.controller.snapshot(host, self._current_task)

前提となる場所にコードをアップロードし、ビルダー・コンテナーを再ビルドしたので、このプラグインも、docker exec 接続プラグインと同じように登録することができます。

リスト 14. コールバック・プラグインを登録するコマンド
# modify the builder Dockerfile to upload the code where Ansible is expecting callback plugins
echo "ADD callback_plugins/docker-cache.py /opt/ansible-plugins/callbacks/docker-cache.py" > Dockerfile

ビルダー・コンテナーを再ビルドして、Ansible プレイバックを再実行すると、モジュールが自動的にロードされます。これで、中間コンテナーがどのように作成されているかを確認することができます (リスト 15 を参照)。

リスト 15. Docker イメージ
REPOSITORY          TAG                     IMAGE ID            CREATED             VIRTUAL SIZE
factory             bc0fb8843e88566c    bbdfab2bd904        32 seconds ago      829.8 MB
factory             d19d39e0f0e5c133    e82743310d8c        55 seconds ago      785.2 MB

まとめ

プロビジョニングは複雑なプロセスです。このチュートリアルで行った実装は、さらに開発を進めるための土台となります。コード自体は単純化されましたが、人間の介入が必要なステップもまだあります。キャッシュの実装には、さらに多くの注意を要するのは確かです。例えば、より具体的なコミットの命名や、クリーンアップのスキルなどが必要になります。

それでも、このチュートリアルで作成したツールは、コンテナーの構成を管理する Ansible プレイブックを実行することができます。この実装を基に、インフラストラクチャーを構成するマイクロサービスの宣言型ビルド・ファイルを組み合わせて再利用し、セットアップすることで、Ansible の能力を最大限活用できるはずです。このソリューションは、ロックインの問題を回避できるよう支援します。このチュートリアルで開発したプラグインは、さまざまなターゲットに対して再利用できるプレイブックをラップします。また、要件も最小限に抑えられているため、このプロジェクトはほとんどのプロバイダーに対応できるようになっています。


ダウンロード可能なリソース


関連トピック

  • Ansible のドキュメントで詳しく学んでください。
  • Docker のドキュメントで詳しく学んでください。
  • Ansible を Docker コンテナーとともに使用するとよい理由を学んでください。
  • Docker をローカルにインストールする方法に関するチュートリアルを読んでください。
  • 強力な IT 自動化ツールである Ansible を入手してください。
  • docker-machine を使用してリモート・ホストに Docker をインストールしてください。
  • Docker コンテナーを実行する軽量の Linux ディストリビューション boot2docker を入手してください。
  • Consul はインフラストラクチャー内でサービスを発見して構成するためのツールです。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing, DevOps
ArticleID=1018809
ArticleTitle=Ansible を使って Docker コンテナーをプロビジョニングする
publish-date=11052015