Ansible の block ディレクティブを使ってみて良かったこと

morikawaAnsible

インフラグループの Morikawa です。

今回は Ansible 2.0 でリリースされた block ディレクティブ について、ここ 1 年半ほど使ってみて便利だったシーンをピックアップしてみようと思います。

個人的に良くなったと思うのは以下の 3 つでした。

  • tags 設定が集約できる
  • 条件分岐の集約ができる
  • タスクの階層が見た目でも分かりやすい

これらのメリットについて、PostgreSQL サーバのインストールを例にとって説明したいと思います。

block ディレクティブの無い Playbook

block ディレクティブを用いずに書いた場合の Playbook の一例が以下となります。

なお、個々のタスクを処理内容ごとに部分的に実行可能とするため、私が Playbook を書く際は原則タスクに対して tags の設定を行うことにしており、下記の Playbook もそのようなルールで書いています。

- yum:
    name: postgresql-server
  tags:
    - postgresql-server
    - postgresql-server-install

- stat:
    path: /var/lib/pgsql/data/postgresql.conf
  register: postgresql_conf
  tags:
    - postgresql-server
    - postgresql-server-init

- shell: /usr/bin/initdb -D /var/lib/pgsql/data -E UTF-8 --no-locale
  become: yes
  become_user: postgres
  tags:
    - postgresql-server
    - postgresql-server-init
  when: postgresql_conf.stat.exists == false

- stat:
    path: /var/lib/pgsql/data/postgresql.conf
  register: postgresql_conf
  tags:
    - postgresql-server
    - postgresql-server-config

- lineinfile:
    dest:   /var/lib/pgsql/data/postgresql.conf
    regexp: ^[#\s]*listen_addresses\s*=
    line:   "listen_addresses = '*'"
  tags:
    - postgresql-server
    - postgresql-server-config
  when: postgresql_conf.stat.exists == true

- lineinfile:
    dest:   /var/lib/pgsql/data/postgresql.conf
    regexp: ^[#\s]*log_filename\s*=
    line:   "log_filename = 'postgresql-%Y-%m-%d_%H%M%S'"
  tags:
    - postgresql-server
    - postgresql-server-config
  when: postgresql_conf.stat.exists == true

- lineinfile:
    dest:   /var/lib/pgsql/data/postgresql.conf
    regexp: ^[#\s]*log_filename\s*=
    line:   "log_filename = 'postgresql-%Y-%m-%d_%H%M%S'"
  tags:
    - postgresql-server
    - postgresql-server-config
  when: postgresql_conf.stat.exists == true

- service:
    name:    postgresql
    state:   started
    enabled: yes
  tags:
    - postgresql-server
    - postgresql-server-start

block ディレクティブで書き換えた Playbook

上記 Playbook を block ディレクティブを使って書き直すと、例えば以下のようになります。

- block: 

  - yum:
      name: postgresql-server
    tags: postgresql-server-install

  - block: 

    - stat:
        path: /var/lib/pgsql/data/postgresql.conf
      register: postgresql_conf

    - shell: /usr/bin/initdb -D /var/lib/pgsql/data -E UTF-8 --no-locale
      become: yes
      become_user: postgres
      when: postgresql_conf.stat.exists == false

    tags: postgresql-server-init

  - block: 

    - stat:
        path: /var/lib/pgsql/data/postgresql.conf
      register: postgresql_conf

    - block:

      - lineinfile:
          dest:   /var/lib/pgsql/data/postgresql.conf
          regexp: ^[#\s]*listen_addresses\s*=
          line:   "listen_addresses = '*'"

      - lineinfile:
          dest:   /var/lib/pgsql/data/postgresql.conf
          regexp: ^[#\s]*log_filename\s*=
          line:   "log_filename = 'postgresql-%Y-%m-%d_%H%M%S'"

      - lineinfile:
          dest:   /var/lib/pgsql/data/postgresql.conf
          regexp: ^[#\s]*log_filename\s*=
          line:   "log_filename = 'postgresql-%Y-%m-%d_%H%M%S'"

      when: postgresql_conf.stat.exists == true

    tags: postgresql-server-config

  - service:
      name:    postgresql
      state:   started
      enabled: yes
    tags: postgresql-server-start

  tags:
    - postgresql-server

block ディレクティブにより得られるメリット

tags 設定が集約できる

block ディレクティブがない状態では、個々のタスクごとに tags を書く以外には、rule や include 単位で tags を設定する方法しか無く、一つの Playbook ファイル内に記載するタスクを役割ごとに分けたり、特定の処理群に tags を設定するのは結構な手間でした。

block ディレクティブにより、複数のタスクは block 内に含め、その block に対して tags を設定する方法が取れるようになったため、tags を記述する手間が省けるとともに、特定の tags に含まれるタスクがどれか、といったことも視覚的に把握しやすくなりました。

上記の例でいうと、 postgresql-server-config など綺麗にまとめることができています。

条件分岐の集約ができる

tags 以外に、when 句による条件分岐についても block ディレクティブで集約が可能です。

上記の例では、設定ファイルの変更について /var/lib/pgsql/data/postgresql.conf の存在を確認した結果を用いて、対象の設定ファイルの書き換えを行っています。

従来の場合タスクごとに when の記載が必要ですが、block を利用することで when の記載が 1 箇所で済みます。また、視覚的にも把握がしやすいメリットがあります。

タスクの階層が見た目でも分かりやすい

tags や when の記載の有無を別にしても、block によりタスクをグルーピングすることができるため、従来のようにタスクが全てフラットに並ぶ書き方に比べ、一連の処理群についてまとまりを視覚的に把握しやすいと言えるでしょう。

まとめ

今回は Ansible 2.0 で追加された block ディレクティブについて、実際に使ってきた経験を踏まえて簡単な記事にさせてもらいました。

ソースコードの読みやすさが大切なように、 Playbook も読みやすさは重要と思います。最近私が Playbook を記述する際はほぼ必ず block ディレクティブは利用するようにしていますし、過去書いたものも時間があれば block ディレクティブで書き直すなどしています。

余談ですが、block に rescue や always を組み合わせて利用することで、タスクの例外処理も可能になります。これまで ignore_errors を用いたり結果のステータスを保存した変数で条件分岐していたりしていた部分もより簡潔にかけるはずなので、活用してみたいと考えています。

たまたまトライコーンの場合はインフラ周りのエンジニアからサーバ構築・運用のコスト軽減のために Ansible の導入を進めてきましたが、最近は開発系のエンジニアもいじるようになってくれており、徐々にサーバの構成管理もコード化が進んできていて、良い感じです。

それでは

参考サイト

morikawaAnsible

Posted by morikawa