Ansibleのツボ

ようやく自宅サーバや開発環境仮想マシンの構築手順を Ansible 化した。

この手のツールはハマりポイント+よく使うイディオムを抑えるのが大事。Pythonプロダクトらしく非常にドキュメントが充実しているのだけど、充実しすぎているのでポイントを自分のためにもまとめておくことにする。

例はおもに Ansible のドキュメントから引用させていただきました。

設定ファイルを書きかえる(一行)

lineinfile モジュールを使う。使い方は以下のような形になる。

1name: enalbe sudo without password if user belongs to the wheel group
2lineinfile: "dest=/etc/sudoers state=present regexp='^%wheel' line='%wheel ALL=(ALL) NOPASSWD: ALL'"

stateabsent にすれば削除することができる。動きとしては regexp にマッチする行をみつけたら line に書きかえる、という動作になる。またデフォルトでは regexp にマッチする行がない場合最終行に追加される。

上記のほかにも regexp にマッチする業の前後に追記するなど柔軟な動作が可能。

ファイルコピーを行う(再帰的)

copy モジュールを使えばファイルコピーできるのは当たり前なのだが、じゃあディレクトリの場合どうするかというとてっとりばやくは以下のようにするとよい。

1shell: rsync -a /path_to/source/  /path_to/dest/ creates=/path_to/dest/hoge

このとおり、 rsync してしまうのがよい。上記はターゲットマシン上どうしでの rsync で、playbookを実行しているホスト→ターゲットマシンで実行する場合は以下。

1local_action: command rsync -a /path_to/source/ {{ inventory_hostname }}:/path_to/dest/

local_action を使うとターゲット上でなくplaybookを実行しているホスト上でコマンドを実行できる。

make installする

make install するソフトウェアをどうするか。一つ目のパターンはよく見る形で以下のように1個ずつタスクにする。

1- name: "wget hoge src"
2  command: wget -O http://example.com/hoge.tar.gz  creates=hoge.tar.gz
3
4- name: "expand src"
5  command: tar xvfz hoge.tar.gz creates=hoge
6
7# 続く…

私の場合こっちというのは以下のような形で1個にまとめてしまう。たかが make install に上記のようにつらつらタスクを書きまくるのはしんどいので。

 1name: install python3.3
 2shell: >-
 3  wget http://www.python.org/ftp/python/3.3.2/Python-3.3.2.tgz &&
 4  tar zxvf Python-3.3.2.tgz &&
 5  rm -f Python-3.3.2.tgz &&
 6  cd Python-3.3.2 &&
 7  ./configure --prefix=/usr/local/python3.3.2 --enable-shared &&
 8  make &&
 9  paco -D make install
10  chdir=/usr/local/src creates=/usr/local/python3.3.2/bin/python3.3  

もちろん、途中でこけると中途半端なことになるのだがそうそうコケないのでこれでよいと思っている。

変数を使いこなす

ターゲット固有の情報はデフォルトで収集される。内容を見たければ ansible hostname -m setup と実行すればよい。

他のホストの情報は以下のようにすればアクセスできる。

1{{ hostvars['test.example.com']['ansible_distribution'] }}

変数は実行時にコマンドラインオプションで上書きできる。

1ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"

ループを使いこなす

Ansibleは結構複雑なループが使える。ただ実用的な範囲で言うと以下ぐらいを抑えておくとよいのでは。

with_items による単純ループ

1name: add several users
2user: name={{ item }} state=present groups=wheel
3with_items:
4   - testuser1
5   - testuser2

with_items + 辞書によるループ

1name: add several users
2user: name={{ item.name }} state=present groups={{ item.groups }}
3with_items:
4  - { name: 'testuser1', groups: 'wheel' }
5  - { name: 'testuser2', groups: 'root' }

コマンド実行結果を with_items で回す

1- name: retrieve the list of home directories
2  command: ls /home
3  register: home_dirs
4
5- name: add home dirs to the backup spooler
6  file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
7  with_items: home_dirs.stdout_lines
8  # same as with_items: home_dirs.stdout.split()

with_sequence による整数範囲ループ(Pythonの range のようなもの)

1file: dest=/var/stuff/{{ item }} state=directory
2with_sequence: start=4 end=16 stride=2

do-until(+sleep)ループ

1action: shell /usr/bin/foo
2register: result
3until: result.stdout.find("all systems go") != -1
4retries: 5
5delay: 10

ファイルglobでループ

1copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
2with_fileglob:
3  - /playbooks/files/fooapp/*

条件分岐を使いこなす

これまた条件分岐もいろいろできることはあるのだが、以下のパターンを抑えておくとよいと思う。

単純な変数による分岐

1- name: "shutdown Debian flavored systems"
2  command: /sbin/shutdown -t now
3  when: ansible_os_family == "Debian"

コマンド実行結果による分岐

 1tasks:
 2  # まずはコマンドを実行してresultに格納
 3  - shell: /usr/bin/foo
 4    register: result
 5    ignore_errors: True
 6
 7  # タスクが失敗した場合
 8  - debug: msg="it failed"
 9    when: result|failed
10
11  # タスクにより更新された場合
12  - debug: msg="it changed"
13    when: result|changed
14
15  # タスクが成功した場合
16  - debug: msg="it succeeded"
17    when: result|success
18
19  # タスクがskipされた場合
20  - debug: msg="it was skipped"
21    when: result|skipped
22
23  # タスクの標準出力によって分岐
24  - shell: echo "hi does not found"
25    when: result.stdout.find('hi') != -1

複数ターゲットが関連するタスクを実行する

ローリングアップデートのように複数ターゲットが連動して動くタスクがある。その場合、playbookを実行するマシンを核としてタスクを作ればよい。

 1- hosts: webservers
 2  serial: 5
 3
 4  tasks:
 5    - name: take out of load balancer pool
 6      local_action: command /usr/bin/take_out_of_pool {{ inventory_hostname }}
 7
 8    - name: actual steps would go here
 9      yum: name=acme-web-stack state=latest
10
11    - name: add back to load balancer pool
12      local_action: command: /usr/bin/add_back_to_pool {{ inventory_hostname }}

local_action モジュールはplaybookを実行しているホストで実行するコマンドを定義する。上記の例だとWEBサーバを5並列でLB切り離し→更新→LB組み込みを実行する。


この程度を理解していればだいたいやりたいことはできるはず。あとはモジュール一覧を頭にいれるだけですね。ついつい shell でゴリ押ししそうになるのでぐっとそこをこらえて…

comments powered by Disqus