【Ansible備忘録⑤】プレイブックの基本-特殊なディレクティブについて-
プレイブックの処理は、再利用性を高めるために、反復処理や条件分岐などの処理を行うための
ディレクティブが用意されている。
条件分岐
Ansible では、特定の条件の時のみタスクを実行したい時に利用する「when」ディレクティブを用意している。
例)
WebサーバーとDBサーバーでインストールするパッケージが異なる場合
tasks: - name: Webサーバーへ Apache のインストール yum: name=httpd state=installed when: host_role=web - name: DBサーバーへ PostgreSQL のインストール yum: name=postgresql11-server state=installed when: host_role=db
ファクト変数との連携
ファクト変数との連携によって、サーバーに適切なタスクを指定することもできる。
例)
RedHat系(RedHat、CentOS、Amazon Linux2 など)は Apache をインストールする。
Debian系(Debian、Mint、Ubuntu など)はNginx をインストールする。
tasks: - name: 【RedHat】Apache のインストール yum: name=httpd state=installed when: ansible_os_family == "RedHat" - name: 【Debian】Nginx のインストール apt: name=nginx state=installed update_cache=yes when: ansible_os_family == "Debian"
変数フィルタとの連携
変数フィルタとの連携によって、細かなエラーハンドリングが実装できる。
レジスタ変数に処理結果(succeeded、failed、changed、skipped)が挿入されることを利用して、
「when」ディレクティブ内で変数フィルタによる条件判定を実装できる。
例)
tasks: - shell: /usr/bin/alias ls="ls -ltar" register: result ignore_errors: True ## result == failed の場合 - debug: msg="失敗しました" when: result|failed ## result == changed の場合 - debug: msg="変更しました" when: result|changed ## result == succeeded の場合 - debug: msg="成功しました" when: result|succeeded ## result == skipped の場合 - debug: msg="スキップされました" when: result|skipped
実行結果の取り扱い
Ansible は、タスク実行に以上が発生した場合、処理が停止してコマンドのリターンコードが返ってくるが、
成功するまで処理を継続するなど実行結果を意図的にコントロールすることができる。
実行結果の操作
Ansible は、「shell」や「command」といったコマンドモジュール群を使用すると、状態が変化していなくても「changed」という結果が返ってくる。
このままでは、変更があったのかわからないので、 Ansible は「chenged_when」というディレクティブを用意している。
「changed_when」ディレクティブを利用することで、タスクに変更があったのかどうかを判定して、「changed」にするかを決定する。
また、「failed_when」ディレクティブという「failed」にする判定を実装できるディレクティブも用意されている。
例)
モジュールが存在するので、「ok」にしたい場合
tasks: - name: Apache の存在確認 command: which httpd register: changed_result changed_when: changed_result.rc != 0
ディレクトリすでに存在するが、「failed」にしたくない場合
tasks: - name: ディレクトリ作成 command: mkdir /home register: failed_result failed_when: failed_result.stderr == ""
失敗による停止を回避
Ansible では、1つのタスクが失敗すると、そのターゲットノードではエラー対象のタスク以降のタスクは実行されない。
タスクが失敗しても後続のタスクを実行したい場合、「ignore_errors」ディレクティブを失敗する可能性のあるタスクに設定することで、失敗しても後続のタスクを実行できる。
例)
エラーを無視して継続する場合、「ignore_erorrs: true」を設定する。
tasks: - name: エラーを無視して継続するタスク shell: /bin/false ignore_errors: true - name: このタスクも実行される shell: echo "test"
ループの呼び出し
同じタスクを繰り返し何度も実行したい場合、ループを利用することでタスクを再利用できる。
with_items ディレクティブ
プレイブックの内容が重複する場合、「with_items」ディレクティブを利用することで、繰り返し表現を定義できる。
「with_items」ディレクティブの後にシーケンスで繰り返し変数に導入したい項目を定義できる。変数は「{{ item }}」という変数の中に入り、指定の値が繰り返し代入される。
例)
同じタスクで複数のユーザーを追加する場合
tasks: - name: ユーザーの追加(グループは管理者) user: name: "{{ item }}" state: present groups: wheel with_items: - kento75 - takano - gakky
マッピングも使用できる。
例)
ユーザーの追加処理をユーザーごとに違うグループで行いたい場合
tasks: - name: ユーザーの追加 user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" with_items: - { name: "kento75", groups: "admin" } - { name: "gakky", groups: "wheel" }
with_nested ディレクティブ
「with_nested」ディレクティブは、ネストされた多重のシーケンスを交互に繰り返し呼ぶことができる。
こちらは、「with_items」と異なり、プログラミング言語のリスト構造に似ている。
例)
下の例では、それぞれのDBにユーザー(kento75とgakky)を追加している。
tasks: - name: DBへのユーザー追加 postgresql_user: db: "{{ item[0] }}" name: "{{ item[1] }}" password: "{{ demo }}" priv: ALL state: present with_nested: - [ "dev_db", "stg_db", "prod_db" ] - [ "kento75", "gakky" ]
タスクのグループ化
「block」を利用することで、指定のタスクをグループ化できる。
グループ化した全てのタスクに対して同一の「when」や「tag」などのディレクティブを指定できる。
例)
tasks: ## RedHat系を対象としたインストール - block: - copy: src=epel.repo dest=/etc/yml.repos.d/epel_andible.repo - yum: name={{ item }} state=present with_items: - libselinux-python - nginx when: ansible_os_family == "RedHat" ## Debian系を対象としたインストール - block: - apt_repository: repo="ppa:nginx/stable" - apt: name={{ item }} state=installed with_items: - python-selinux - nginx when: ansibe_os_family == "Debian" ## ここは共通なのでグループ化しない - template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf - service: name=nginx state=restarted
「block」には、プログラミング言語の try-catch-finally のような機能が用意されている。
通常は、「block」内でのタスクでエラーが返ってきた時点でタスクが終了してしまうが、「rescure」ディレクティブ(プログラミング言語でいうところの catch)を利用することで、エラーが発生した時のみ実行する処理を定義できる。また、常に実行する処理を「always」ディレクティブ(プログラミング言語でいうところの finally)で定義できる。
例)
tasks: - block: - command: /bin/false - debug: msg="command ディレクティブでエラーが発生するのでこのタスクは実行されない" rescure: - debug: msg="上でエラーが発生したのでこのタスクは実行される" - command: /bin/false - debug: msg="command ディレクティブでエラーが発生するのでこのタスクは実行されない" always: - debug: msg="常に実行されるタスク"
その他
ループの呼び出しには、「with_dict」とか「with_sequence」など色々用意されているが、使ったことないので記載しない。