前回環境ができたところで、改めて公式ドキュメントからAnsibleに関するもろもろまとめ。
前提
- 2018/02/28時点の情報つまりAnsible v2.4
- 以降のリンクは最新版(latest)への参照であり、また正式なレビューも受けていないため、本記事と内容が異なる場合は参照先が真
- deprecatedなものは記載しない
コマンドリファレンス
まずはよく使う(であろう)コマンドから。
ansible
ホスト(セット)に対し、シングルタスク(playbook)を実行するコマンド。
単発で「リモートでなにか実行(doing ‘remote things’)」する。
$ ansible windows -i /etc/ansible/hosts -m win_file -a "path=C:\\\test state=directory"
$ ansible windows -m ping
- 最初の引数("windows")はインベントリのグループ名("all"を指定すると全部、公式マニュアル上は"host-pattern")
-
-i
でインベントリファイル(デフォルトは"/etc/ansible/hosts")を指定 -
-m
で使うモジュール(詳細後述)を指定 -
-a
でモジュールへの引数(argument)を指定
補足:インベントリファイル
そのままだが、管理対象ホストのリストを記載したファイル。[groupname]
でセクション化することで、ホストをグルーピング可。
[groupname]
10.1.1.1
hostname.mydomain.com
[hogeWebServers]
www1.hogehoge.com
www2.hogehoge.com
www3.hogehoge.com
ansible-playbook
こちらは"playbook"(後述)を作成して複数タスクを実行するコマンド。こいつこそがAnsibleの真骨頂(のはず)。
$ ansible-playbook playbook.yml
- ほとんどの設定(実行サーバ等)はplaybook自体に書くので、実行時は割りとシンプル
-
-C
or--check
をオプション指定すれば実際の変更操作は行わず、起こりうる変更を予測する(try to predict some of the changes that may occur)。
ansible-vault
YAMLファイルを暗号化したり複合化したりするユーティリティ。vaultは地下金庫(Harry Potterにも出てきましたね)。Ansibleのデータファイル(/etc/ansible/group_vars,host_vars下)中にパスワードなどのセンシティブな情報を書き込んだら暗号化しておきましょう。
$ ansible-vault encrypt /etc/ansible/group_vars/windows.yml
- 暗号化したら
ansible
やansible-playbook
実行時に--ask-vault-pass
オプションをつけるなりしないと、当然動かない - 第一引数に
create
を指定するとエディタが開いて保存時に暗号化
ansible-galaxy
すごい名前。インターネット接続前提(または自分の共有リポジトリ)のようなので、今回は対象外。
とりあえずロール(リポジトリを管理する上での役割と推測)を管理するためのユーティリティらしい。
ansible-console
AnsibleのREPL(Read-eval-print loop)なコンソールユーティリティ。
$ ansible-console hogeWebServers
-m ping
-m ping
ansible-config
Ansibleの設定周りを表示するコマンド。
$ ansible-config list
$ ansible-config dump
$ ansible-config view
- ANSIBLE_CONFIG環境変数でcfgファイルを指定(/etc/ansible/ansible.cfg overrided by ~/.ansible.cfg)
- または
-c
or--config
オプションでオーバーライド
ansible-doc
Ansibleプラグインのドキュメントを表示するユーティリティ。
$ ansible-doc -m ping
ansible-inventory
インベントリを表示するユーティリティ。
$ ansible-inventory --graph all
$ ansible-inventory --list all
ansible-pull
"playbook"をリポジトリからダウンロードしてきて実行するユーティリティ。
モジュール
モジュールとは
簡単に言えば、AnsibleのコントロールマシンからOSネイティブコマンドを実行せずとも、モジュールと引数によってなんらかの処理をしてくれる。タスク・プラグイン、ライブラリ・プラグインとも呼ばれる。APIのようなもの。
もちろん、自作のモジュールを開発することもできる(腕があれば)。
概要
リンク先のほぼ翻訳です。
$ ansible webservers -m service -a "name=httpd state=started"
$ ansible webservers -m ping
-m
でモジュールを指定し、-a
でモジュールへの引数を渡す。ほとんどのモジュールは"key=value"型で引数を渡し、複数あるときはスペースで区切る。"ping"のように引数が不要なモジュールもある。
これを"playbook"にすると、
- name: start the webservers
service:
name: httpd
state: started
のようになる。
$ ansible webservers -m command -a "/sbin/reboot -t now"
これを"playbook"にすると、
- name: reboot the webservers
action: command /sbin/reboot -t now
これはplaybookの解説によれば古い書き方で、次のように短く書くのがモダンなやり方。、
- name: reboot the webservers
command: /sbin/reboot -t now
自分でモジュールを書くようなことでもないかぎりあまり気にしなくてもいいけど、モジュールはJSONフォーマットのレスポンスを返す。
モジュールは冪等性を持つべき(should be idempotent)で、実行前に状態を確認して、既に最終形になっているなら、なにもしないほうがいい(should avoid making any changes)。
個別の詳細は実際に使うときになって調べることにしますが、どんなものがあるかくらいは目を通しておいてよさそうです。
あとはサードパーティ製のモジュールもあったりなかったりだとか。
YAML Syntax
既にちょこちょこと出てきている"playbook"はYAML形式で記載します。HTMLに対するmarkdownのようなもので、XMLやJSONに比べて人間に優しい形式だと主張していますが、実際のところどうなんでしょうね。
リストとディクショナリ
AnsibleではほぼすべてのYAMLファイルはリストで始まります。リスト内の各項目はkey/valueのペアで、一般的にハッシュとかディクショナリと呼ばれるものです。
YAMLは"---"で開始と終端を表すことができます。
リスト内のすべての項目は同じインデントレベルで、行頭を"- "(a dash + a space)にします。
---
# A list
hogeList:
- listItem1
- listItem2
- listItem3
---
ディクショナリは"key: value"で表します(コロンの後ろのスペース1個は必須)。
---
# A dictionary
hogeDict:
name: hogename
attr: hogeattr
value: hogevalue
---
リストもディクショナリも短縮形で書けます。
---
hogeList: ['listItem1', 'listItem2', 'listItem3']
hogeDict: {name: hogename, attr: hogeattr, value: hogevalue}
---
複数行にまたがる場合の指示子
複数行をみたまま表示させるか(HTMLでいうところのpre的な)、空行や改行を無視するかを指定する場合、それぞれ"|"と">"を使用します。
# みたままバージョン
asYouCanSee: |
hogehoge
the second line
the third line
# 改行等無視バージョン
ignoreLineBreaks: >
hogehoge
hogehoge
hogehoge
注意点
コロンが値にある場合は注意が必要です。
test: this is test: which is intended to be meaningless
drive: c:
このままだとシンタックスエラーになりますが、それぞれ'"'(ダブルクォート)で括ることで回避できます。
test: "this is test: which is intended to be meaningless"
drive: "c:"
ただし、クォートが不要なケースも存在します(なぜOKなのか言及されていないので詳細不明)。
windows_path: c:\windows
さらに、Ansibleでは"{{ var }}"という形式で変数を保存する一方、YAMLパーサはそれをディクショナリのワンライナー型と解釈するため、この場合もダブルクォートする必要があります。
その他、クォートするべき事項をまとめます。
hoge: "{{ var }}"
hoge2: "{{ basedir }}/hoge/geho" # 固定文字列を含む場合は全体をクォート
hoge3: "{{ basedir }}\\hoge\\geho" # バックスラッシュも特殊文字
hoge4: "text which includes white spaces all must be quoted" # スペースを含む文字列も全体をクォート
hoge5: "yes" # booleanではなく文字列としての"yes"
hoge6: "1.0" # 浮動少数点数ではなく文字列としての"1.0"
Playbooks
最後にこれで締めます。
「モジュールが道具だとすれば、"playbooks"はマニュアル(操作手順)であり、インベントリは素材だ」とのことです(DIY好きな人にはわかりやすい例えなのかしら?)。
また、「とりあえず読んでおけ、これらがベストプラクティスだ!」とのことです。
まずは、ドキュメント中の例をそのまま記載します。
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache
service: name=httpd state=restarted
---
"key=value"となっている部分は、ディクショナリ形式でも書けます。
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service:
name: httpd
state: started
enabled: yes
handlers:
- name: restart apache
service:
name: httpd
state:restarted
---
さて、どちらが見やすい(あるいはメンテしやすい、Excel等から自動生成しやすい)ですかね。
hostsとremote_user
hosts
hosts行は1つ以上のグループやホストパターンのリストです。複数指定する場合はコロン":"で区切ります。
詳細はpatternの項に記載のとおり。
remote_user
説明の必要がないくらい文字通り、管理対象サーバで"play"を実行するユーザ名。
タスク単位で指定可能。
---
hosts: webservers
remote_user: root
tasks:
- name: test
ping:
remote_user: ec2-user
---
become
sudoとかで権限昇格して実行する場合に指定。
---
hosts: webservers
remote_user: ec2-user
tasks:
- name: test
ping:
become: root
become_method: sudo
---
順序制御
複数のホストが対象となっている場合、"order"で実行順序を制御可能。
- inventory
- これがデフォルト。インベントリファイルに記載のとおりの順序で実行する。
- reverse_inventory
- インベントリファイルの逆順で実行する。
- sorted
- 実行ホスト名のアルファベット降順で実行する。
- reverse_sorted
- 実行ホスト名のアルファベット昇順で実行する。
- shuffle
- ランダムな順序で実行する。
タスクリスト
各"play"はタスクのリストを含められ、上から順に逐次実行します。エラーとなったホストは、以後スキップされます。失敗したら修正してやり直せとのことです(だからこそモジュールの冪等性が重要で、"playbook"内で使用するモジュールに冪等性があれば、"playbook"全体も冪等性があるでしょうと)。
すべてのタスクには名前("name")をつけましょう。結果のログに読みやすい形で出力されます。指定がない場合は、"action"とそっけなく表示されます。
変数
変数は"playbook"のvarsセクション、またはインベントリの"Host Variables"や"Group Variables"で宣言し、アクション行から"{{varName}}"で参照します。
変数名に使える文字種は、文字(a-zA-Z)とアンダースコア("_")と数字で、必ず文字から始まる必要があります。
YAMLではディクショナリも使えるので、"[]"や"."記法を使った参照も可能です。
---
- hosts: webservers
vars:
hoge1: hogevalue1
hoge2: hogevalue2
tasks:
- name: test1
command: /bin/echo {{ hoge1 }}
- name: test2
command: /bin/echo {{ hoge2 }}
- name: test3
command: /bin/echo vars.hoge1
- name: test4
command: /bin/echo vars['hoge2']
---
ハンドラ
例えば設定ファイルを変更するタスクを定義し、実際に変更があった場合にのみ特定のサービスを再起動させたいような場合、ハンドラを使うことで実現できるというお話。
---
- hosts: webservers
tasks:
- name: replace httpd.conf
template:
src: template.conf
dest: /etc/apache/conf/httpd.conf
notify:
- restart memcached
- restart apache
handlers:
- name: restart memcached
service:
name: memcached
state: restarted
- name: restart apache
service:
name: apache
state: restarted
---
"nofify"に指定したリストがハンドラであり、"handlers"セクションに実際のアクションを記載します(普通の"tasks"とほぼ同じ)。"handlers"セクションのリストで、"name"にハンドラで定義した文字列を設定します(グローバルにユニークである必要)。
"handlers"アクションの実行順序は、"handlers"に定義した順番となり、"notify"した順番ではないことに注意が必要。
上記とは別の方法として、"handers"のタスクに"listen"を加えることでも実現可能。
---
tasks:
- name: replace httpd.conf
template: src=template.conf dest=/etc/apache/conf/httpd.conf
nofity: "restart web services"
handlers:
- name: restart memecached
service: name=memcached state=restarted
listen: "restart web services"
- name: restart apache
service: name=apache state=restarted
listen: "restart web services"
---
また、全てのハンドラを実行したい場合、次のように"meta"行を入れることで実現可能です。
tasks:
- shell: /bin/echo executing all handler tasks
- meta: flush_handlers
- shell: /bin/echo done
YAMLのシンタックスチェック
ansible-playbook
コマンドに--syntax-check
オプションを付与することで確認可能です。また、実行対象ホストを確認するには`--list-hosts"オプションを付与します。
$ ansible-playbook playbook.yml --syntax-check
$ ansible-playbook playbook.yml --list-hosts

まだまだ奥というか底が深そうなAnsiblですが、必要に迫られたらもう少しお勉強したいところです。