Ansible 2.0 になって使えるモジュールが大幅に増えましたが、その中に Consul 関係のモジュールがいくつかあります。前から気になってたので、ちょっと試してみました。
今回のお試し環境
ホストOS
- OS X Yosemite 10.10.5
- VirtualBox 5.0.10
- Vagrant 1.8.1
- Ansible 2.0.1
ゲストOS
Playbook
昨年末に Web サーバ1台、MariaDB サーバ1台、Cloudera QuickStart VM で Consul クラスタを組む playbook を作ったので、今回はこれを使いました。
- consul モジュールの検証に使った playbook
Ansible 2.0 対応
以前作った playbook のままだと Ansible 2.0 での実行時に WARNING が出たので、事前に少し修正しました。
今回は 2.0 への移行については触れないので、そちらに興味のある方は、先週末に職場ブログに書いた記事をご参考ください。Ansible 2.0 への移行方法、移行時の注意点に関する詳細をまとめています。
recruit.gmo.jp
話はちょっとズレますが、Consul は yum で配布されていないので、以下のように zip を落として解凍して……という処理をいちいち書いてます。Ansible 2.0 にアップグレードしたので、block を使って少し書き換えました。
hashicorp-sample/ansible/roles/consul_agents/centos7/tasks/main.yml
- name: Install unzip for unarchive module
yum: name=unzip state=present
- name: Check if consul is installed
stat: path=/usr/local/bin/consul
register: consul_bin
- block:
- name: Download and unzip Consul {{ consul_version }} command
unarchive: src="https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_linux_amd64.zip" dest=/home/vagrant copy=no
- name: Add execution permission to consul command
file: path=/home/vagrant/consul state=file mode="0755"
- name: Move consul command
command: mv /home/vagrant/consul /usr/local/bin/consul
when: not consul_bin.stat.exists
- name: Create consul setting directory
file: path=/etc/consul.d state=directory owner=root group=root mode=0755
- name: Create common consul setting
template: src="consul.service" dest="/etc/systemd/system/consul.service" owner=root group=root mode=0644
- name: Call daemon-reload explicitly because service module does not call it
command: systemctl daemon-reload
- name: Autostart Consul
service: name=consul state=started enabled=yes
Consul 関係のモジュール
Ansible 2.0 Has Arrived によると、Ansible 2.0 は200個以上の新モジュールを含む、とのこと。All Modules — Ansible Documentation を見る限り、Consul 関係では以下の4個が新たに追加されたようです。
今回は、一番使いそうな consul モジュールを試してみました。
consul モジュールで書き換えるとこうなる before/after
before
consul モジュールを使わない場合、Consul にサービスを追加する playbook はこんな感じになります。これは、何らかの管理機能を提供する Web サーバを、Consul にサービスとして登録する例です。
hashicorp-sample/ansible/roles/managers/tasks/main.yml
- name: Create manager service information for consul
template: src="consul/manager.json" dest="/etc/consul.d/manager.json" owner=root group=root mode=0644
- name: Restart consul
service: name=consul state=restarted
hashicorp-sample/ansible/roles/managers/templates/consul/manager.json
{
"service": {
"name": "manager",
"port": 80,
"check": {
"script": "curl localhost:80 >/dev/null 2>&1",
"interval": "15s"
}
}
}
after
単純に考えると、こう書けば OK そうな気がします。Before とは違って、テンプレートは不要になります。簡潔ですね。
- name: Register manager service
consul:
service_name: manager
service_port: 80
script: "curl localhost:80 >/dev/null 2>&1"
interval: 15s
これを実行すると、こんなエラーが出て失敗します。
TASK [cdh_quickstart : Register manager service] *******************************
fatal: [cdh-quickstart]: FAILED! => {"changed": false, "failed": true, "msg": "python-consul required for this module. see http://python-consul.readthedocs.org/en/latest/#installation"}
consul モジュールのページを見て、最初はホストOSに python-consul を入れろということなのか?と誤解してしまったのですが、ゲストOSの方に入れないと駄目みたいです。python-consul のインストールには pip が必要なので、修正後は以下のようになります。
- name: Install pip
yum: name=python-pip state=present
- name: Install python-consul
pip: name=python-consul state=present
- name: Register manager service
consul:
service_name: manager
service_port: 80
script: "curl localhost:80 >/dev/null 2>&1"
interval: 15s
これで python-consul のエラーは出なくなったのですが、今度は以下のエラーが出たり出なかったりするようになりました……。
TASK [managers : Register manager service] *************************************
fatal: [managers]: FAILED! => {"changed": false, "failed": true, "msg": "Could not connect to consul agent at localhost:8500, error was HTTPConnectionPool(host='localhost', port=8500): Max retries exceeded with url: /v1/agent/services (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0xef5650>: Failed to establish a new connection: [Errno 111] \\xe6\\x8e\\xa5\\xe7\\xb6\\x9a\\xe3\\x82\\x92\\xe6\\x8b\\x92\\xe5\\x90\\xa6\\xe3\\x81\\x95\\xe3\\x82\\x8c\\xe3\\x81\\xbe\\xe3\\x81\\x97\\xe3\\x81\\x9f',))"}
ローカルで動作する consul agent に接続できない、というメッセージに見えます。このタスクより前に agent は起動しているんですが……。色々試してみたところ、consul モジュールの実行前に agent を再起動すれば、このエラーは出なくなりました。
最終形はこんな感じ。
hashicorp-sample/ansible/roles/managers/tasks/main.yml
- name: Install pip
yum: name=python-pip state=present
- name: Install python-consul
pip: name=python-consul state=present
- name: Restart consul
service: name=consul state=restarted
- name: Register manager service
consul:
service_name: manager
service_port: 80
script: "curl localhost:80 >/dev/null 2>&1"
interval: 15s
この hashicorp-sample は dnsmasq の設定も行っているので、$ dig @127.0.0.1 -p 8600 impala.service.consul SRV
と問い合わせると IP アドレスが返されます。また、この manager の Nginx を停止させると、IPアドレスが返されなくなります。
まとめ
pip と python-consul のインストールを要求される割に、consul モジュールを使わない場合と比べて、それほど簡潔な表記にはなりませんでした。1台のマシンで複数のサービスを起動するような場合には、テンプレートファイルを減らすことができるので、それがメリットでしょうか?
あと、これはユースケースによっては致命的だと思うのですが、 consul モジュールで登録したサービスは consul agent を再起動すると消えてしまいます 。実サービスで使う場合、consul agent が落ちるたびに playbook を最初から実行しなおし、という想定なのでしょうか。また、今回のように Vagrant の provisioner として Ansible を使う場合も、playbook は(明示しないと)初回起動時にしか実行されないので、これはちょっと不便ですね。
とりあえず動かすことはできたものの、個人的にはこのモジュールの使いどころがちょっと良くわからないな……という感想でした。