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

docker containerに対して直接ansibleを実行する

注釈

まだ試作段階ということをご承知おきください。ツッコミ大歓迎です。

dockerのイメージを構築するにはDockerfileを使って構築します。しかし、Dockerfileはほぼ単なるshell scriptなのでいろいろと書きにくいという問題があります。そのため、packerを使ってイメージを構築する手段が取られたりします。が、packerのansible provisionerはansible-pullを内部で実行するという形式のため、ansible実行環境やgitをイメージの中に入れる必要があります。

また、起動しているコンテナに対してコマンドを実行するためにはsshで入る必要があります。これはつまり、sshdを入れてsshのポートをexposeする必要があり、なおかつ動的に変わるdockerの外側sshポートを把握する必要があります。

これらの問題点を解決するために、ansibleが直接dockerコンテナとやりとりをするプラグインを作成しました。(注: ansibleはssh以外も使え、さらにその部分はプラグイン構造になっていて任意に追加できるのです)

dockerに対してlxcでアクセス

docker 0.9.0からlibcontainerというライブラリが入り、dockerはLXCに依存する必要はなくなりました。しかし、現時点ではdockerは通常はLXCを使用していると思います。そのため、今回のプラグインはLXCを使ってアクセスします。

前提

  • docker 0.9.1
  • lxcを入れること
  • linux 3.8以上
  • imageにはpython2が入っていること (ansibleはpython3に非対応。残念)
  • /usr/bin/tee がimageにあること (/bin/teeじゃないです)

準備

  1. docker -e lxc でlxcドライバーで立ち上げておきます

  2. docker run でコンテナを起動しておきます

  3. このgistからファイルを2つ取得し、配置します

    • docker_connection.pyはinventoryファイルの置き場に。 chmod ugo+x して実行権限を付けておく
    • docker_inventory.pyは connection_plugins というディレクトリの下におく

    結果としてこんな構成になります。

    |- docker_inventory.py
    |- connection_plugins
    |  |
    |  +- docker_connection.py
    +- なにか.yml
    

実行

通常のansible実行と異なる点は、inventoryにdocker_inventory.pyを指定することだけです。

% ansible-playbook -i docker_inventory.py  なにか.yml

これにより、 dockerという名前のグループに対して指定したplaybookが実行されます。なお、中でホスト側のsudoを呼んでいるため、実行前にsudoを実行してキャッシュしておく必要があるかもしれません。

ちなみに、sshを介していないため、実行はかなり早いです。

内部詳細

ansibleにはlibvirtを使ったlxcアクセスのプラグインがすでに内蔵されているのですが、手元の環境ではvirshからdockerのLXCが見えなかったのと、LXC決め打ちであればlibvirtを使う必要はないことから、lx-attachを使っています。というか、このlibvirt_lxc.pyをほぼそのまま使っています。

lxc-attachで任意のコマンドを実行するにはLinux 3.8以上が必要です。

dockerのcontainer IDはdocker ps --no-truncで得ることが出来、このcontainer IDを使ってLXCでコンテナにアクセスできます。

本当はdockerというグループ決め打ちじゃなく、iamge名をグループにしようとしたのですが、imageのIDしかinspectでは得られなかったので一旦後回しにしました。

まとめ

試作ではありますが、起動しているdocker containerに対して直接ansibleを実行できるプラグインを作成しました。ansible-playbookを実行した後にcommitをすることで、イメージを作成できると思います。

また、生成と実行が早いことから、ansible playbookを作成するときの試行錯誤にも使えると思います。

さらに、dockerモジュールと組み合わせることにより、より複雑な動作ができるかもしれません。

最後に、助言を頂いた mopemope さんに感謝します。