【PlayBook概要】構築方法 3章:タスク
各Playにはタスクリストが含まれている
- タスクは、次のタスクに進む前に、ホストパターンに一致するマシンに対して、
一度に1つずつ順番
に実行されます。 Play
内では、全てのホストが同じタスクディレクティブを取得することを理解することが重要。- Playの目的は、選択したホストをタスクにマップすることです。
- 上から下に実行されるPlaybookを実行すると、タスクが失敗したホストは、Playbook全体のローテーションから除外されます。
- 問題が発生した場合は、Playbookファイルを修正し、再実行します。
各タスクの目的
- 非常に具体的な引数を使用してモジュールを実行することです。
- 変数はモジュールの引数で使用できます。
- モジュールは冪等(べきとう)である必要があります。
- モジュールをシーケンスで複数回実行すると、1回だけ実行した場合と同じ結果になります。
- 冪等性(べきとうせい)を達成する1つの方法は、モジュールに目的の最終状態がすでに実現しているかどうかを確認し、その状態が実現している場合は、アクションを実行せずに終了することです。
important
Playbookが使用するすべてのモジュールの冪等(べきとう)である場合は、Playbook自体が冪等(べきとう)である可能性が高いため、Playbookを再実行しても安全です。
commandモジュールとshellモジュール
- 通常、同じコマンドを実行します。
chmod
またはsetsebool
などのコマンドの場合は、まったく問題ありません。- これらのモジュールを冪等(べきとう)にするために使用できる
creates
フラグが利用できます。
すべてのタスクにはname
が必要です。
これは、Playbookの実行から出力に含まれます。
人間が読める形式の出力であるため、各タスクステップの適切な説明を提供すると便利です。
ただし、名前が指定されてない場合は、actionに渡される文字列
が出力されます。
推奨は
タスクは、レガシーの
action:module option
形式を使用して宣言出来ますが より一般的なmodule:option
形式を使用することが推奨されます。
この推奨される形式はドキュメント全体で使用されていますが
一部のPlaybook
では古い形式を使用している場合があります。
以下は基本的なタスクです。
ほとんどのモジュールの場合と同様、サービスモジュールはkey=value
引数をとります。
tasks: - name: make sure apache is running service: name: httpd state: started
commandモジュールとshellモジュールは
引数のリストを取り、
key=value
形式を使用しないユイツのモジュールです。 これにより、それらは予想どおりに機能します。
name: enable selinux command: /sbin/setenforce 1
commandモジュールとshellモジュールは戻りコードを処理するため コマンドがあり、その正常な終了コードがゼロでない場合は以下を行うことが出来ます。
name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true
アクション行が長すぎて快適ではなくなった場合
スペースで改行し、継続している行にインシデントを追加できます。
name:Copy ansible inventory file to client copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts owner=root group=root mode=0644
変数はアクション行で使用できます。
たとえば、vars
セクションでvhost
という名前の変数定義したとすると、次のようになります。
name: create a virtual host file for {{ vhost }} template: src: somefile.j2 dest: /etc/httpd/conf.d/{{ vhost }}
同じような変数は、後で使用するテンプレートで使用できます。
非常に基本的なPlaybookでは、すべてのタスクがそのPlay
に直接リストされますが
通常は「再利用可能なPlaybookの作成」の説明に従って、タスクを破損せる方が分かりやすくなります。
アクション(短縮形表記)
Ansibleでは、以下のようなモジュールリストが推奨されます。
template: src: templates/foo.j2 dest: /etc/foo.conf
Ansibleの初期バージョンでは以下の形式が使用されていましたが、これは引き続き動作します。
action: template src=templates/foo.j2 dest=/etc/foo.conf
ハンドラー:変更時の操作の実行
モジュールは冪等(べきとう)である必要があり、リモートシステムに変更を加えた時にリレーできます。Playbookはこれを認識し、変化に対応すために使用できる基本的なイベントシステムを備えています。
これらの「通知」アクションは、Play
のタスクの各ブロックの最後にトリガーされ、複数の異なるタスクから通知された場合でも1回だけトリガーされます。
たとえば、複数のリソースが設定ファイルを変更したためにApacheを再起動する必要があることを示している場合がありますが、不必要な再起動を回避するために、Apacheは1回だけバウンスされます。
<実例>
次に、ファイルの内容が変更された時に2つのサービスを再起動する。
ファイルが変更された場合のみ
name: template configuration file template: src: template.j2 dest: /etc/foo.conf #ハンドラーと呼ばれている notify: restart memcached restart apache
タスクのnotify
セクションに挙げられているものは、ハンドラーと呼ばれています。
ハンドラーとは
- タスクのリストであり、通常のタスクとの違いはない。
- グローバルに一意の名前で参照され、通知機能によって通知されます。
- ハンドラーは何も通知しないと、実行されません。
- ハンドラーに通知するタスクの数に関係なく、特定の
Play
でタスクがすべて完了すると、ハンドラーは1回だけ実行されます。
以下は、ハンドラーセクションの例
handlers: - name: restart memcached service: name: memcached state: restarted - name: restart apache service: name: apache state: restarted
Ansibleハンドラーが変数を使用することが望ましい場合があります。
たとえば、サービスの名前がディストリビューションによって若干異なる場合は、出力で各ターゲットマシンについて再起動したサービスの正確な名前を表示させる必要があります。
ハンドラーの名前を変数にしないようにします。
ハンドラー名はすぐにテンプレート化されるため、Ansibleには以下のように、ハンドラー名に使用できない値がない場合がある。
handlers: # this handler name may cause your play to fail! - name: restart “{{ web_service_name }}”
ハンドラー名で使用される変数が使用出来ない場合
Play
全体が失敗します。
この変数を中間のPlay
に変更すると、ハンドラーは新たには作成されません。
代わりに、変数をハンドラーのtaskパラメータに設定します。
以下のようなinclude_vars
を使用して値を読み込むことが出来ます。
tasks: - name:Set host variables based on distribution include_vars: "{{ ansible_facts.distribution }}.yml"
handlers: name: restart web service service: name: “{{ web_service_name | default(‘httpd’) }}” state: restarted
Ansible2.2以降、ハンドラーは一般的なトピックを「リッスン」することもでき、タスクは次のようにそれらのトピックに通知できます。
handlers: name: restart memcached service: name: memcached state: restarted listen: “restart web services” name: restart apache service: name: apache state: restarted listen: “restart web services” tasks: name: restart everything command: echo “this task will restart the web services” notify: “restart web services”
この使用により、複数のハンドラーをトリガーすることがはるかに簡単になります。
また、ハンドラーを名前から切り離し、Playbookとロールの間でハンドラーを共有しやくします。
(特にGalaxyなどの共有ソースからサードパーティのロールを使用する場合)
note
・通知ハンドラーは常に、notify-statementに記載される順番ではなく、
定義される順序で実行されます。これは、listenを使用するハンドラーの場合
でも当てはまります。
・ハンドラー名とlistenトピックは、グローバルな名前空間にあります。
・ハンドラー名は一時的なものですが、listenトピックは一時的ではありません。
・固有のハンドラー名を使用します。
同じ名前のハンドラーを複数トリガーすると、最初のハンドラーが上書きされます。
定義された最後のモノのみが実行されます。
・インクルード内で定義されたハンドラーに通知することは出来ません。
Ansible2.1の時点ではこれは機能しますが、包含は静的だある必要がります。
ロールについては、次の点に注意してください。
・pre_task
セクション、task
セクション、およびpost_task
セクション内で通知される
ハンドラーは、通知されたセクションの最後に自動的にフラッシュされます。
・roles
セクション内で通知されるハンドラーは、tasks
セクションの最後ではなく、
tasks
ハンドラーの前に自動的にフラッシュされます。
・ハンドラーはスコープのあるPlay
であるため、
ハンドラーは定義されているロールの外で使用できます。
すべてのハンドラーコマンドをすぐにフラッシュする必要のある場合は、
以下を実行できます。
tasks: shell: some tasks go here meta: flush_handlers shell: some other tasks
上記の例では、meta
ステートメントに到達したときに、キューに入れられたハンドラーが処理されます。
これは少しニッチなケースですが、時々役に立ちます。