Vagrant 1.2 から ansible がサポートされたということで、気になって試してみた。
まだ自作モジュールとかは作ってなくて、単に vagrant で使えるところまで。
vagrant-ansible
vagrant plugin install ansible
で vagrant の provision 機能として ansible が使えるようになる。
これを使うと vagrant に完結するのだが、これがメリットにもデメリットにもなる。 なにか playbook を作って vagrant 上で試そうと思ったら、 ansible-playbook コマンドが使えず、 Vagrantfile で指定した playbook に include してやらないといけない。 しかも ansible に渡せるオプションは vagrant-ansible がサポートしているものだけだ。
なので、開発メンバーに Vagrant ファイルを共有して同じ vm をセットアップするとかの目的にはいいが、 ansible を試すだけなら ansible 単体で起動できたほうがいい。
ansible-vagrant
ansible に標準で搭載されている vagrant モジュール。vagrant-ansible の逆で、 vagrant を ansible から起動する。
これはモジュールなので、 「localhost で vagrant up されている」という状態にしたあと、その vm を inventory (対象ホストの一覧) に追加する。
ただ、やっぱりこれを使うにも、試したい playbook に hosts: localhost で task: vagrant を追加しておかないといけなくて、再利用できる playbook を単体で試したいのにはちょっと面倒。
自力
~/.ansible.cfg に次のような設定をした。
[defaults] hostfile = ~/.ansible/hosts.d
これで ~/.ansible/hosts.d
ディレクトリの中に、 hosts みたいなテキストファイルや、 inventory を生成するスクリプトを置くことが出来る。このスクリプトは --list
でホストの一覧を、 --host ホスト名
でそのホストに対する設定を出力する。 ssh のオプションは ansible_ssh_host などで設定できる。
~/.ansible/hosts.d/vagrant:
#!/usr/bin/env python import sys import subprocess import json def hosts(): print json.dumps({"vagrant": ["vagrant"]}) def variable(): output = subprocess.check_output("vagrant ssh-config", shell=True) for line in output.splitlines(): line = line.strip() try: k, v = line.split(' ', 1) except ValueError: continue k = k.lower() if k == 'hostname': hostname = v elif k == 'port': port = v elif k == 'user': user = v elif k == 'identityfile': v = v.strip('"') identity = v.decode('string_escape') print json.dumps({ 'ansible_ssh_host': hostname, 'ansible_ssh_port': port, 'ansible_ssh_user': user, 'ansible_ssh_private_key_file': identity, }) if sys.argv[1] == '--host': # show host variables. variable() else: # show list of hosts. hosts() # ft=python
これで vagrant 経由で ansible を起動したり ansible 経由で vagrant を起動しなくても playbook を試せるようになった。
感想
まだ本格的な構成管理ツールは必要なくて、ふだん fabric + cuisine でやっている初期設定 (パッケージのアップグレードやいくつかのパッケージのインストール) をやってみただけなんだけど、これだけなら fabric の方が楽だ。
@task def install_devtools(): packages = '''python-dev libz-dev libbz2-dev libpng-dev vim-nox exuberant-ctags git-core bzr bzrtools build-essential python-distribute python-virtualenv mercurial linux-tools pkg-config libzmq-dev '''.split() for pkg in packages: package_ensure(pkg)
こんな感じの fabfile.py を
--- - hosts: all sudo: yes tasks: - name: update apt action: apt pkg=$item state=latest update_cache=yes with_items: - vim-nox - exuberant-ctags - build-essential - pkg-config - libzmq-dev - libz-dev ...
という playbook にして、 ansible -l vagrant devel.yml
として実行してみたところ、 libz-dev
で失敗してしまう。
fabric + cuisine は apt-get install libz-dev
を実行するだけなので問題ない (これで充分 idempotent になってる) のに対して、 ansible は現在インストールされているパッケージのバージョンとかまで管理しようとしてしまうので、 virtual package な libz-dev は使えず、本体となる zlib1g-dev を指定しないといけないようだ。
ただし action に apt じゃなくて command を使えば任意の apt-get install を実行できるので、ある程度 fabric 的にも使える。
action: command /usr/bin/apt-get install -y $item
とりあえずこんなかんじでお茶を濁して、ちゃんとモジュールを使ったり作ったりは本格的なことをする段階になってから試してみる。