無印吉澤

ソフトウェア開発、運用管理(俗にいう DevOps)、クラウドコンピューティングなどについて、吉澤が調べたり試したことを書いていくブログです。

Ansible 2.0 から使えるようになった consul モジュールを試してみた

Ansible 2.0 になって使えるモジュールが大幅に増えましたが、その中に Consul 関係のモジュールがいくつかあります。前から気になってたので、ちょっと試してみました。

今回のお試し環境

ホストOS

  • OS X Yosemite 10.10.5
  • VirtualBox 5.0.10
  • Vagrant 1.8.1
  • Ansible 2.0.1

ゲストOS

  • CentOS 7.2

Playbook

昨年末に Web サーバ1台、MariaDB サーバ1台、Cloudera QuickStart VM で Consul クラスタを組む playbook を作ったので、今回はこれを使いました。

f:id:muziyoshiz:20160313235925p:plain:w640

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

# Install unzip
- name: Install unzip for unarchive module
  yum: name=unzip state=present

# Install Consul if not installed
- 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

# Create Consul agent common setting
- 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
# Reload files under /etc/systemd/system
- name: Call daemon-reload explicitly because service module does not call it
  command: systemctl daemon-reload
# Start consul and create autostart setting
- 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

# Create Consul client settings
- 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 は(明示しないと)初回起動時にしか実行されないので、これはちょっと不便ですね。

とりあえず動かすことはできたものの、個人的にはこのモジュールの使いどころがちょっと良くわからないな……という感想でした。