このエントリーをはてなブックマークに追加

Ansible Docker Connection Pluginを使う

1年以上前の2014年4月にこんな記事を書きましたdocker containerに対して直接ansibleを実行するそれからいろいろあって、Ansible 2.0では標準でDocker Connection Pluginが入っています。(といってもぼくの実装ではありませんが)

Docker Connection Pluginとは

まず、Connection Pluginについて説明します。Ansibleでは通常SSHを使って対象となるホストに接続します。しかし、 Connection Plugin を使うことで、接続方式を切り替えることができます。

代表的なものはlocal connectionです。以下のように書くと、sshではなく、localhostでそのまま実行されます。sshのlocalhostと異なる点は、sshはまったく使わずに、そのままのユーザーがのまま実行する、という点です。開発時に便利ですね。

- hosts: all
  connection: local
  tasks:
    - file: path=/tmp/this_is_local state=directory

その他、以下のconnection pluginが用意されています。paramikoやwinrmは使ったことがある方も多いかと思います。

accelerate
accelaretモード(過去の遺産なので覚える必要なし)
chroot
chroot
funcd
Func: Fedora Unified Network Controller 経由
zone
SolarisのZone
jail
FreeBSDのJail
libvirt_lxc
virtのLXC
paramiko
sshのpython実装
winrm
Windows

この中の一つがdocker connection pluginです。

Docker connection pluginの利点

Docker Connection Pluginを使うことで、Dockerコンテナに対して直接Ansibleを実行できます。具体的にはdocker execでコマンド実行を、ファイルのコピーはdocker cpを実行します。Dockerコンテナの中にsshdを建てる必要はありません。

DockerfileによるBuildが一番シンプルであることは確かです。しかし、

  • Layerを増やさないために\で何行も増やしていく場合がある
  • templateがないため、複数種類のimageを作り分けるのがめんどう
  • 他はAnsibleで管理しているのに、ここだけDockerfileになると管理が分断されてしまう

などの理由で、Ansibleを使いたくなる場合がありますので、そういう場合に有用です。

なお、私はDockerfileで済ませられるのであればその方が良いと思います。Ansibleをわざわざ使う必要はないでしょう。しかし、複雑な構成になってくると、Ansibleの方が便利な場合もあると考えられるため、ここで紹介している次第です。

Docker connection pluginを使う

能書きはこのあたりにして、早速使ってみましょう。ほとんどの人はAnsible 2.0RC1を使っていると思いますので、新たなインストールは必要ないですが、万が一 1.9.4を使っている人はこちらからdocker.pyをダウンロードし、connection_pluginsというディレクトリを作成してその中に置きましょう。以下のような構成になります。

.
|-- connection_plugins
|   `-- docker.py
|-- hosts
`-- site.yml

また、 pipでdocker-pyをインストールしておきましょう。(ansible v2.0では必要ないです)

あとは以下のようにplaybookを書きます。

- name: Dockerコンテナを起動
  hosts: localhost
  connection: local
  vars:
    base_image: ubuntu:latest
    docker_hostname: test

  tasks:
    - name: Dockerコンテナを起動
      local_action: docker image={{ base_image }} name={{ docker_hostname }} detach=yes tty=yes command=bash
    - name: ホストを追加
      add_host: name={{ docker_hostname }}

- name: Dockerコンテナ内を構成
  hosts: test
  connection: docker   # ここで docker connectionを指定
  tasks:  # 好きなように書きます
    - file: path=/tmp/docker state=directory
    - file: path=/tmp/ansible state=directory
    - group: name=admin state=present
    - user: name=johnd comment="John Doe" uid=1040 group=admin
    - copy: src=site.yml dest=/tmp/ansible/

  post_tasks:
    - local_action: shell /usr/local/bin/docker commit {{ inventory_hostname }} ubuntu:ansible

この例のplaybookは以下の二つから構成されています。

  1. Dockerコンテナを起動
  2. 起動したDockerコンテナ内部を構成管理

1の方では、dockerモジュールを使って起動します。ここは普通にlocal接続です。2の方がDocker接続を使用しています。

重要なのは、connection: dockerという行だけが異なっており、そのほかは通常のPlaybookと何ら変わりないという点です。

最後にdokcer commitを実行して、イメージとして保存しています。それまでの箇所はすべて docker execなどで行われているため、保存されず、layerは全体で最後にdocker commitを実行した時に出来る一つだけとなります。これにより、Dockerfileで何行も続けたり、ということをしなくてすみます。

commitも自動化

先ほどの例ではpost_tasksとして、docker commitを実行しています。しかし、Ansible を使って Docker コンテナーをプロビジョニングするという記事では、callback pluginを使って毎回のtask実行毎にcommitをする例を示しています。

この方式はDockerfileによる方式と同じくlayerがたくさんできることになります。その代わり、キャッシュされるため、次回は高速になるという利点もあります。

RemoteのDockerホストを使う

Dockerホストは手元だけでなく、リモートでも構いません。

export DOCKER_HOST=tcp://192.168.0.10:4243

DOCKER_HOSTを環境変数で設定すれば、そのホストを経由してDockerコンテナにアクセスします。試していませんが、Swarmなどでもきちんと動くと思います。

これで、

  • インスタンス起動などのクラウドサービスの利用
  • dockerホスト自体の構築
  • dockerコンテナ/イメージの構築
  • ELBの付け外しなど、デプロイに必要な機能

のすべてがAnsibleで可能となります。

まとめ

この記事ではAnsibleからDockerコンテナを直接触れる Docker Connection Pluginを紹介しました。一つのpythonファイルを置くだけで、Dockerコンテナにたいして通常のsshホストと同じことができるようになります。また、Dockerホストはローカルだけでなく、リモートに対しても可能です。

最後に。

最初の方に述べましたが、Dockerfileで済ませられるのであればその方が良いでしょう。なんでもAnsibleでやりたくなる気持ちも分かりますが、Ansibleを使わなくてはならない理由はありません。適材適所、不要な苦労をしないために、もう一度考えましょう。

そして、そもそもDockerコンテナ内部が複雑な時点で間違っていると思います。golangをDockerでデプロイするで示したように、golangであれば、1バイナリだけ置けば動くため、「プロビジョニング」なんてものは存在しなくなります。現在はGoogleに転職したIanさんも(より)小さいDockerイメージを作ろうという記事を書いており、必要な最小限のファイルだけ置くのが理想です。

自動化をするまえに、「そもそも本当に必要なのか?」を考えましょう。