ゆるい感じのプログラムを書きたい。

プログラムの敷居を下げて、多くの人が開発出来るように色々書いていきます!

【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ステートメントに到達したときに、キューに入れられたハンドラーが処理されます。
これは少しニッチなケースですが、時々役に立ちます。