Ansible - 推奨ディレクトリ構成

前々回前回とAnsibleで簡単なPlaybookを作成し実行しました。一つのPlaybookファイルに必要な処理をすべて記載していましたが、Ansibleでは推奨ディレクトリ構成があります。推奨ディレクトリ構成はチーム開発や大規模なシステムで有用です。

Sample directory layout

推奨ディレクトリ構成を使用すると一部のディレクトリ内にある設定を自動的に読み込みます。また、規則通りに配置するとPlaybook内でのファイルの指定がフルパス・相対パスではなくファイル名のみで指定可能になります。処理内容を一つのPlaybookにまとめて書くのではなく、役割毎に分割記載して適切なディレクトリに配置することで推奨ディレクトリ構成を活用できます。

今回は、前々回のブログで作成したchronyの設定を行うPlaybookを推奨ディレクトリ構成へ変更します。

推奨ディレクトリ構成の作成

前回ブログ記事時点では、ansibleディレクトリを作成し、その中にPlaybookファイルやテンプレートファイルを配置していました。

[user01@ansible-ctl01 ~]$ tree ansible/
ansible/
├─ chrony.conf.j2
├─ chrony_setting.yml
├─ hosts.ini
└─ vault.yml

0 directories, 4 files

ansibleディレクトリ以下に推奨ディレクトリ構成を作成します。使用しないものは作成しなくても問題ありません。rolesの下の「chrony」ディレクトリの名前は任意です。役割(処理)の名称にしておくとわかりやすいと思います。

[user01@ansible-ctl01 ~]$ cd ansible/
[user01@ansible-ctl01 ansible]$ mkdir -p group_vars host_vars library module_utils filter_plugins roles roles/chrony roles/chrony/defaults roles/chrony/files roles/chrony/handlers roles/chrony/meta roles/chrony/tasks roles/chrony/templates roles/chrony/vars
[user01@ansible-ctl01 ansible]$ cd ../
[user01@ansible-ctl01 ~]$ tree -F ansible/
ansible/
├─ chrony.conf.j2
├─ chrony_setting.yml
├─ filter_plugins/
├─ group_vars/
├─ host_vars/
├─ hosts.ini
├─ library/
├─ module_utils/
├─ roles/
│   └─ chrony/
│       ├─ defaults/
│       ├─ files/
│       ├─ handlers/
│       ├─ meta/
│       ├─ tasks/
│       ├─ templates/
│       └─ vars/
└─ vault.yml

Playbookファイルの再作成

先述の通り、前々回作成したchronyの設定を行うPlaybookをそのまま使用することは適切ではないので再作成します。元のPlaybookは以下でした。

[user01@ansible-ctl01 ~]$ cat ansible/chrony_setting.yml
---
- name: Configure NTP servers in chrony.conf
  hosts: all
  become: true

  vars_files:
    - vault.yml

  vars:
    ntp_servers:
      - 10.0.1.3
      - ntp.nict.jp

  tasks:
    - name: Replace chrony.conf
      template:
        src: chrony.conf.j2
        dest: /etc/chrony.conf
        mode: 0644
        owner: root
        group: root
      notify: Restart chronyd

  handlers:
    - name: Restart chronyd
      service:
        name: chronyd
        state: restarted

まず、最初にansible-playbookコマンドで指定する最初に呼び出されるPlaybookを作成します。
ここでは「site.yml」として作成します。

[user01@ansible-ctl01 ~]$ cat ansible/site.yml
# chrony setting playbook
---
- name: Apply chrony settings
  hosts: all
  gather_facts: yes
  become: true

  roles:
    - chrony

元のPlaybookファイルの先頭付近の記述(対象ホスト指定、become指定)がここに入ります。
「roles:」で推奨ディレクトリ構成のroles配下に作成したディレクトリ名「chrony」を指定します。この指定で、「roles/chrony/tasks/」内に作成するタスクリストが呼び出されることになります。
「gather_facts:」は対象サーバの情報を収集する指示です。

元のPlaybookの「vars_files:」で指定していた、パスワードを暗号化したファイル「vault.yml」は「group_vars」に入れておきます。今回は、「group_vars」の下に「all」ディレクトリを作成し、そこに配置します。「all」ディレクトリ内のファイルはすべてのホストに適用されます。インベントリファイルでグループ分けをしている場合等に使い分けが可能になります。グループ分けについては本ブログでは初出ですが、ansibleドキュメントを確認してください。
「group_vars」に配置したファイルは自動的に読み込まれるので、元のPlaybookファイルにある「vars_files:」は記載不要になります。

[user01@ansible-ctl01 ~]$ mv ansible/vault.yml ansible/group_vars/all/

元のPlaybookファイルの「vars:」で指定しているntpサーバのIPを別ファイルに移動させます。移動先は、「/roles/chrony/defaults/main.yml」です。ファイル名は「main.yml」である必要があります。「main.yml」は自動的に読み込まれますが、「main.yml」以外は自動で読み込まれません。

[user01@ansible-ctl01 ~]$ cat ansible/roles/chrony/defaults/main.yml
# default vars of ntp server
---
ntp_servers:
  - 10.0.1.3
  - ntp.nict.jp

変数ファイルの配置場所は「roles/chrony/vars/」ではないのか?と思ってしまいますが、「default」も変数ファイルを置く場所になります。両者の違いは、優先順位の違いです。
・roles/chrony/defaults/ ・・・ 優先度低。他の箇所で同じ変数が設定されている場合に上書きされる
・roles/chrony/vars/ ・・・ 優先度高。他の箇所で同じ変数が設定されていても上書きされない(ここより優先度が高い指定箇所もある)

優先順位の詳細については、ansibleドキュメントを確認してください。

次はメインの処理、tasks部分を別ファイルに移動させます。
「roles/chrony/tasks/」ディレクトリに「chrony_setting.yml」を作成し、元のPlaybookファイルの「tasks:」部分を記載します。task名の「name:」も追加しておくと、実行ログにも出力されて可読性が上がります。

[user01@ansible-ctl01 ~]$ cat ansible/roles/chrony/tasks/chrony_setting.yml
---
- name: replace chrony.conf
  template:
    src: chrony.conf.j2
    dest: /etc/chrony.conf
    mode: 0644
    owner: root
    group: root
  notify: Restart chronyd

「template:」で指定しているテンプレートファイルの場所を移動します。移動先は、「/roles/chrony/templates/」になります。「templates」ディレクトリに配置しておくと、ファイル名のみの記載で読み込んでくれます。

[user01@ansible-ctl01 ~]$ mv ansible/chrony.conf.j2 ansible/roles/chrony/templates/

tasksのファイル名を「chrony_setting.yml」として作成しましたが、このファイル名では最初に作成した「site.yml」の記載方法では自動的に呼び出されません。自動的に呼び出されるようにするには、「main.yml」というファイル名にする必要があります。「main.yml」とすることで「site.yml」内でrole名の指定(ディレクトリ名)だけで読み込まれるようになります。
今回は、「main.yml」に「chrony_setting.yml」をインポートする方法で記述し、「chrony_setting.yml」タスクが実行されるようにします。

[user01@ansible-ctl01 tasks]$ cat ansible/roles/chrony/tasks/main.yml
- name: setting chrony task
  import_tasks: chrony_setting.yml

「main.yml」に直接tasks内容を書かないのは、事前のチェック処理(OS種別判定等)や他の処理を追加しやすくするためです。例えばtimezoneの設定も変える等々。

残りはhandlersの部分になります。handlersは「ansible/roles/chrony/handlers/main.yml」に移動させます。handlersには、tasksで変化があった時のみ実行したい処理を記載します。handlerの処理はPlaybook終了時に一度だけ実行されます。複数のtasksから複数回notifyで呼び出されても実行は一度だけです。

[user01@ansible-ctl01 ~]$ cat ansible/roles/chrony/handlers/main.yml
---
- name: Restart chronyd
  systemd:
    name: chronyd
    state: restarted

前々回のブログでhandlersで再起動させるモジュールに「service」を使用していましたが、今回の検証環境はAlmalinux9.6なのでsystemdに変更しました。一応serviceモジュールでもサービスの起動・停止・再起動は可能です。

これで、元々のPlaybookの記載内容が推奨ディレクトリ構成にあったファイル・記述に変更できました。元々あったPlaybookは不要になったので、削除または退避しておきます。

最終的に以下のようなディレクトリ・ファイル配置になっています。

[user01@ansible-ctl01 ~]$ tree -F ansible/
ansible/
├─ filter_plugins/
├─ group_vars/
│   └─ all/
│       └─ vault.yml
├─ host_vars/
├─ hosts.ini
├─ library/
├─ module_utils/
├─ roles/
│   └─ chrony/
│       ├─ defaults/
│       │   └─ main.yml
│       ├─ files/
│       ├─ handlers/
│       │   └─ main.yml
│       ├─ meta/
│       ├─ tasks/
│       │   ├─ chrony_setting.yml
│       │   └─ main.yml
│       ├─ templates/
│       │   └─ chrony.conf.j2
│       └─ vars/
└─ site.yml

実行

では、実行してみます。
ansible-playbookに引数で渡すPlaybookは「site.yml」になります。操作対象サーバは前々回と同じansible-client01サーバで、chrony.confを修正済みですが、一旦chrony.confをデフォルト設定に戻して、ansibleによる変更が行われることを確認します。

[user01@ansible-ctl01 ~]$ ansible-playbook -i ansible/hosts.ini ansible/site.yml --vault-password-file=~/.vault_pass.txt

PLAY [Apply chrony settings] ******************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [ansible-client01]

TASK [chrony : replace chrony.conf] ***********************************************************************************************
changed: [ansible-client01]

RUNNING HANDLER [chrony : Restart chronyd] ****************************************************************************************
changed: [ansible-client01]

PLAY RECAP ************************************************************************************************************************
ansible-client01           : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

正常に処理が実行されました。対象サーバ側でも変更されたことを確認します。

[root@ansible-client01 ~]# chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* 10.0.1.3                     3   6    17    17    -21us[  -53us] +/- 3778us
^? ntp-a3.nict.go.jp             0   7     0     -     +0ns[   +0ns] +/-    0ns
[root@ansible-client01 ~]#
[root@ansible-client01 ~]#
[root@ansible-client01 ~]# head -n 10 /etc/chrony.conf
# Ansible-managed chrony.conf

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (https://www.pool.ntp.org/join.html).
#pool 2.almalinux.pool.ntp.org iburst
server 10.0.1.3 iburst
server ntp.nict.jp iburst

# Use NTP servers from DHCP.
sourcedir /run/chrony-dhcp
[root@ansible-client01 ~]#

まとめ

Ansible推奨構成ディレクトリを使用してのPlaybookの実行もできました。推奨ディレクトリを使用するとファイル数が増え、記載内容も細切れになった感がありますが、再利用性・可読性・保守性・抽象性などで利点があります。

参考

お問い合わせ

弊社では様々なサービスを取り扱っております。
詳細はサービス一覧からご覧ください。

お気軽にお問い合わせください。応対時間 9:30-17:30 [ 土・日・祝日除く ]

お問い合わせ