【構成管理】Ansible を使ってみた

今更ですが構成管理ツールの Ansible を使ってみたのでメモります。
環境は OSX10.10.2, ターゲットホストは Ubuntu14.04。

Ansibleのインストール

対象ホストへには ssh で接続するので `~/.ssh/config` に必要なssh設定を記述します。

$ cat ~/.ssh/config
Host "Ubuntu14.04's-IP"
  HostName "Ubuntu14.04"
  User ubuntu
  Port 22
  IdentityFile ~/.ssh/id_rsa
  TCPKeepAlive yes
  IdentitiesOnly yes

OSXに Ansible をインストールします。2系の場合。

$ brew update
$ brew info ansible
ansible: stable 2.0.2.0 (bottled), devel 2.1.0.0-0.2.rc2, HEAD
$ brew install ansible

下記は 1系の場合です。

$ sudo pip install ansible
$ ansible --version
ansible 1.8.4
  configured module search path = None

$ echo "Ubuntu14.04's-IP" > ~/ansible_hosts
$ export ANSIBLE_HOSTS=~/ansible_hosts

$ ansible all -m ping --ask-pass -u ubuntu
SSH password: 
xxxxxxx | success >> {
    "changed": false,
    "ping": "pong"
}

上記では インベントリ (実行する対象ホストの情報) を環境変数 ANSIBLE_HOSTS で指定しましたが, pip でインストールした場合, /etc/ansible/hosts がデフォルトのようです。または, -i オプションで直接指定できます。

# ansible 1.8.4 (pip)
$ ansible --help
...
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host file
                        (default=/etc/ansible/hosts)
# ansible 2.0.2 (brew)
$ ansible --help
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path
                        (default=/usr/local/etc/ansible/hosts) or comma
                        separated host list.

Playbook

Playbookはyamlの構文で記述します。簡単なPlaybookを書いてみます。

---
# simple.yml
- hosts: Ubuntu14.04's-IP
  user: ubuntu
  sudo: no
  gather_facts: False
  tasks:
    - debug: msg="Hello! Ansible!"

実行してみます。

# 構文チェック
$ ansible-playbook -i ansible_hosts simple.yml --syntax-check
# 実行
$ ansible-playbook -i ansible_hosts simple.yml

パッケージ管理システム(apt-get, pip)でインストールする簡単な Playbook を書きます。
見通しをよくするために, ある単位で外部ファイルにまとめておきます。

---
# python.yml
- name: install python2.7-dev
  apt: pkg=python2.7-dev state=latest

- name: install python-pip
  apt: pkg=python-pip state=latest

- name: install flask
  pip: name=flask

- name: install requests
  pip: name=requests

- name: install selenium
  pip: name=selenium

- name: install pyvirtualdisplay
  pip: name=pyvirtualdisplay

includeで外部ファイルを呼びます。

---
# ubuntu.yml
- hosts: Ubuntu14.04's IP
  user: ubuntu
  sudo: yes
  gather_facts: False
  tasks:
    - name: install vim
      apt:  pkg=vim state=latest

    - name: install git
      apt:  pkg=git state=latest

    - name: install supervisor
      apt:  pkg=supervisor state=latest

    - name: install td-agent
      shell: curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh

    - include: tasks/python.yml

when で条件判定によるタスク実行制御したり, resisterで実行結果を変数に設定したりできます。

実行してみます。-vvvv オプション で詳細な実行内容が見れます。

$ ansible-playbook ubuntu.yml -i ansible_hosts -vvvv

task実行時に何も変更がない場合は ok にカウントされ, 何かしら変更がある場合は changed にカウントされます。ただし, shell-commandを使うと, 何もインストールしていないような場合でも changed になります。

Nginxの設定ファイル変更時に再起動する

nginx.conf を local から remote に転送し, 内容に変更がある場合に Nginx を再起動させます。

notify により callback された時の処理を定義しておきます。

---
# handlers/main.yml
- name: restart nginx
  service: name=nginx state=restarted enabled=yes

下記 copy の結果が changed の時に notify に指定した handler の name に一致する task が実行されます。

---
- name: install nginx
  apt: name=nginx

- name: copy nginx.conf
  copy: src=/your/path/to/nginx.conf dest=/etc/nginx/conf.d owner=ubuntu mode=0644
  notify: restart nginx

変更があった場合に, ちゃんと restart された事を確認しました。

$ ps -eo lstart,pid,args | grep nginx
Sat May 28 21:56:13 2016 21572 grep --color=auto nginx
Mon May 23 22:53:38 2016 22860 nginx: master process /usr/sbin/nginx

ansible-vault を使うと, パスワードを含むファイルを暗号化することができます。 具体的には –ask-valut-pass オプションで指定したパスワードを使って暗号化され, 処理実行時に復号化されます。

Roles を使うと見通しの良いディレクトリ構成になりそうです。全体的に Chef より手軽に使える印象でした。

Troubleshooting

リモートホストの OS が CentOS や RHEL の場合, デフォルトで SELinux が有効になっていて ansible-playbook 実行時にエラーとなることがあります。

Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!

単純に libselinux-python をインストールすれば良いです。

$ sudo yum install libselinux-python


[1] Ansible の Playbook を使ってみる
[2] Ansibleでのパスワードの取り扱い
[3] Ansible、コマンド実行結果を”ok”にする(冪等性を保つ方法)
[4] AnsibleでNginxをソースからインストール
[5] Ansibleでシェルコマンドを実行させるときのノウハウ
[6] Ansible マジック変数の一覧と内容
[7] ansible でファイルがある場合のみ実行したい場合のベストプラクティス