ようへいの日々精進XP

よかろうもん

Ansible で Docker コンテナの Dynamic Inventory を試す

ども、かっぱです。前回の続き。

あくまでお試し

Python 版の Inventory スクリプト

ということで Ansible の Dynamic Inventory スクリプトの Docker コンテナ版を作ってみた。尚、Docker コンテナ版については Python 版が存在するが、consul 版と同様に手元の環境では動かなかったので止むなく自作した。

きっとちゃんと動かくはずなんだろうけど...すいません。

俺の Inventory スクリプト Ruby

拙作のスクリプトは以下の通り。docker-api を叩ける docker-api を利用した。

#!/usr/bin/env ruby

require 'docker'
require 'json'

docker_host = "192.168.59.103" # boot2docker を使っている場合、他の環境は適宜差し替える
target_host_name = "ansible_"
target_user_name = "ansible"
target_user_pass = "ansible"

containers = Docker::Container.all(:running => true)
targets = containers.select do |con|
  con.info['Names'][0].include? target_host_name
end

target = {}

targets.map do |t|
  t.info['Ports'].each do |p|
    target.merge!({ t.info['Names'][0].gsub("/","") => { "ansible_ssh_host" => docker_host, "ansible_ssh_port" =>  p['PublicPort'], "ansible_ssh_user" => target_user_name, "ansible_ssh_pass" => target_user_pass }})
  end
end

puts JSON.generate(target)

だいぶん力技感が否めないが...コンテナ名を指定して対象を絞り込む作戦。(コンテナ名を docker run 時に指定出来るのが超アリガタヤ、アリガタヤ...)

スクリプトを実行する前に以下のように環境変数をセットしておく。

export DOCKER_HOST=tcp://192.168.59.103:2376
export DOCKER_CERT_PATH=~/.boot2docker/certs/boot2docker-vm
export DOCKER_TLS_VERIFY=1

スクリプトを素で以下のように実行する。

./docker_inventory.rb

スクリプトを直接実行すると以下のように出力される。

{
    "ansible_01": {
        "ansible_ssh_host": "192.168.59.103",
        "ansible_ssh_pass": "ansible",
        "ansible_ssh_port": 49195,
        "ansible_ssh_user": "ansible"
    },
    "ansible_02": {
        "ansible_ssh_host": "192.168.59.103",
        "ansible_ssh_pass": "ansible",
        "ansible_ssh_port": 49196,
        "ansible_ssh_user": "ansible"
    }
}

前回の consul から情報を取得した時よりも Dynamic では無い、通常の Inventory ファイルに近い内容のように思える。

ということで、一連の動作を試せる環境を以下にアップした。

ということで、上記のお試し環境を利用して進める。


お試し

とりあえず docker build して run

git clone してきたら inventories ディレクトリに移動して docker build を実行。

cd sample-prj-20150305/inventories
docker build -t your_container .
docker run --name=ansible_01 -p 22 -t -i -d your_container
docker run --name=ansible_02 -p 22 -t -i -d your_container

コンテナ作っておいて...コンテナを起動しておく。念の為にコンテナの起動を確認。

CONTAINER ID        IMAGE                                COMMAND                CREATED             STATUS              PORTS                     NAMES
74575bf2be7e        inokappa/centos-ssh-ansible:latest   "/bin/sh -c '/usr/sb   2 seconds ago       Up 1 seconds        0.0.0.0:49196->22/tcp     ansible_02
d6363688bd92        inokappa/centos-ssh-ansible:latest   "/bin/sh -c '/usr/sb   8 seconds ago       Up 8 seconds        0.0.0.0:49195->22/tcp     ansible_01

ping

ansible -i ./docker_inventory.rb all -m ping

これだと...以下のような警告。どうやら Inventory ファイルに直接パスワードを記述してアクセスするのはよろしく無さそう。

ansible_01 | FAILED => to use the 'ssh' connection type with passwords, you must install the sshpass program
ansible_02 | FAILED => to use the 'ssh' connection type with passwords, you must install the sshpass program

本来であれば公開鍵認証を選択するのであるが、今回はお試しということもあり以下のように実行。

ansible -i ./docker_inventory.rb all -m ping -c paramiko

この -c オプションを利用すれば...

  -c CONNECTION, --connection=CONNECTION
                        connection type to use (default=smart)

上記の通り対象ホストへの接続モード(利用する SSH ライブラリ)を指定してすることが出来る。ドキュメントでは paramiko がデフォルトのように記載されているが、現状は smart がデフォルトのようだ。

気を取り直して -c paramiko を追加して ping を実行すると以下のように出力された。

ansible_01 | success >> {
    "changed": false,
    "ping": "pong"
}

ansible_02 | success >> {
    "changed": false,
    "ping": "pong"
}

一応、コンテナ毎にも...ansible_01 を指定して。

% ansible -i inventories/docker_inventory.rb ansible_01 -m ping -c paramiko
ansible_01 | success >> {
    "changed": false,
    "ping": "pong"
}

ansible_02 を指定して。

% ansible -i inventories/docker_inventory.rb ansible_02 -m ping -c paramiko
ansible_02 | success >> {
    "changed": false,
    "ping": "pong"
}

なんかパッケージを...

せっかくなので Playbook も走らせてみたいので role 環境で以下のような Playbook を作った。

roles/my_test/tasks/main.yml は以下の通り。

- name: install the latest version of apps
  yum: name={{ item }} state=latest
  with_items:
  - "{{ packages }}"

roles/my_test/vars/main.yml は以下の通り。

---
packages:
  - telnet
  - vim

おもむろに実行...。

% ansible-playbook -i inventories/docker_inventory.rb my_test.yml -c paramiko --check

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [ansible_01]
ok: [ansible_02]

TASK: [my_test | install the latest version of apps] **************************
changed: [ansible_02] => (item=telnet,vim)
changed: [ansible_01] => (item=telnet,vim)

PLAY RECAP ********************************************************************
ansible_01                 : ok=2    changed=1    unreachable=0    failed=0
ansible_02                 : ok=2    changed=1    unreachable=0    failed=0

うまくいきそうや。

f:id:inokara:20150307074026p:plain

ということで、最後は画像で。


最後に

イマサラ言うか...って言われそうだけど Dynamic Inventory こそ Ansible の醍醐味だと思う。