はじめに
このラボでは、RHEL 上で複雑な Ansible Playbook を構造化するための必須テクニックを学び、より管理しやすく、スケーラブルで、再利用可能な自動化を作成します。基本的な概念から高度な組織戦略まで進み、自動化を実行するホストを正確に制御する方法と、大規模な Playbook を論理的でモジュール化されたコンポーネントに分割する方法に焦点を当てます。
まず、インベントリ内の特定のノードをターゲットにするために、基本的なグループ名、ワイルドカード、除外、および論理演算子を使用してホスト選択を習得します。次に、include_tasks および import_tasks を使用してタスクを個別のファイルにリファクタリングすることにより、モジュール化を探求します。最後に、import_playbook を使用して完全なマルチ Playbook ワークフローを構成し、最終的には完全に構造化されモジュール化された Ansible プロジェクトの実行と検証を行います。
基本パターンとワイルドカードパターンを使用したホストの選択
このステップでは、Ansible 自動化で特定のホストをターゲットにするための基本を学びます。その核心となるのは、管理対象のサーバーをリストする Ansible インベントリファイルと、Playbook 内の hosts ディレクティブであり、これによりタスクセットを実行する対象のサーバーを指定します。まず Ansible をインストールし、基本的なインベントリと Playbook を作成してから、グループ名とワイルドカードパターンを使用してホストを選択する方法を探求します。
まず、環境に Ansible がインストールされていることを確認しましょう。Ansible はデフォルトではインストールされていないため、DNF パッケージマネージャーを使用してインストールする必要があります。ansible-core パッケージは、ansible-playbook を含む、Ansible の基本的なコマンドラインツールを提供します。次のコマンドを実行してください。
sudo dnf install -y ansible-core
以下のような出力が表示されるはずです。
...
Installed:
ansible-core-2.16.x-x.el9.x86_64
...
Complete!
次に、ファイルを整理するために、この演習用の専用ディレクトリを作成しましょう。このステップの以降のすべての操作は、この新しいディレクトリ内で行われます。
mkdir -p ~/project/ansible_patterns
cd ~/project/ansible_patterns
ここで、インベントリファイルを作成します。インベントリは、Ansible コマンド、モジュール、およびタスクが操作するホストとホストのグループを定義するテキストファイルです。ここでは、そのシンプルさから INI フォーマットを使用します。
nano エディタを使用して inventory という名前のファイルを作成します。
nano inventory
inventory ファイルに以下の内容を追加します。これは、それぞれ 2 つのホストを含む webservers と dbservers という 2 つのグループを定義しています。
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.lab.net
db2.lab.net
ファイルを保存し、Ctrl+X、Y、Enter の順に押して nano を終了します。
インベントリの準備ができたので、簡単な Playbook を作成しましょう。この Playbook は ansible.builtin.debug モジュールを使用してメッセージを表示し、タスクがどのホストで実行されているかを確認します。これは、システムに変更を加えることなくホストパターンをテストするのに最適な方法です。
playbook.yml という名前の新しいファイルを作成します。
nano playbook.yml
以下の YAML コンテンツを追加します。最初は webservers グループのすべてのホストをターゲットにしています。
---
- name: Test Host Patterns
hosts: webservers
gather_facts: false
tasks:
- name: Display the inventory hostname
ansible.builtin.debug:
msg: "This task is running on {{ inventory_hostname }}"
エディタを保存して終了します。次に、ansible-playbook を使用して Playbook を実行します。-i フラグはカスタムインベントリファイルを指定します。
ansible-playbook playbook.yml -i inventory
出力は次のようになります。
PLAY [Test Host Patterns] ******************************************************
TASK [Display the inventory hostname] ******************************************
ok: [web1.example.com] => {
"msg": "This task is running on web1.example.com"
}
ok: [web2.example.com] => {
"msg": "This task is running on web2.example.com"
}
PLAY RECAP *********************************************************************
web1.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ご覧のとおり、webservers グループのホストのみがターゲットにされました。次に、ワイルドカード (*) を使用するように Playbook を変更しましょう。ワイルドカードは、より柔軟なパターンマッチングを可能にします。
playbook.yml を編集し、hosts 行を hosts: "*.lab.net" に変更します。ワイルドカードを含むパターンは引用符で囲むことを忘れないでください。
---
- name: Test Host Patterns
hosts: "*.lab.net"
gather_facts: false
tasks:
- name: Display the inventory hostname
ansible.builtin.debug:
msg: "This task is running on {{ inventory_hostname }}"
Playbook を再度実行します。
ansible-playbook playbook.yml -i inventory
以下のような出力が表示されるはずです。
PLAY [Test Host Patterns] ******************************************************
TASK [Display the inventory hostname] ******************************************
ok: [db1.lab.net] => {
"msg": "This task is running on db1.lab.net"
}
ok: [db2.lab.net] => {
"msg": "This task is running on db2.lab.net"
}
PLAY RECAP *********************************************************************
db1.lab.net : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
db2.lab.net : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
今回は、プレイは .lab.net で終わるホストでのみ実行されました。最後に、特別なキーワード all を使用して、インベントリで定義されたすべてのホストをターゲットにしましょう。
playbook.yml をもう一度編集し、hosts 行を hosts: all に変更します。
---
- name: Test Host Patterns
hosts: all
gather_facts: false
tasks:
- name: Display the inventory hostname
ansible.builtin.debug:
msg: "This task is running on {{ inventory_hostname }}"
Playbook を実行して結果を確認します。
ansible-playbook playbook.yml -i inventory
出力には、すべてのホストがターゲットになっていることが示されます。
PLAY [Test Host Patterns] ******************************************************
TASK [Display the inventory hostname] ******************************************
ok: [web1.example.com] => {
"msg": "This task is running on web1.example.com"
}
ok: [web2.example.com] => {
"msg": "This task is running on web2.example.com"
}
ok: [db1.lab.net] => {
"msg": "This task is running on db1.lab.net"
}
ok: [db2.lab.net] => {
"msg": "This task is running on db2.lab.net"
}
PLAY RECAP *********************************************************************
db1.lab.net : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
db2.lab.net : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web1.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook は現在、インベントリの 4 つすべてのホストで実行されており、all パターンの強力さを示しています。
除外と論理演算子によるホスト選択の絞り込み
このステップでは、除外と論理演算子の使用方法を学ぶことで、ホスト選択スキルを向上させます。これらの機能により、複雑な環境を管理する上で不可欠な、非常に具体的なターゲティングが可能になります。! (NOT) 演算子を使用したホストの除外方法と、& (AND) 演算子を使用したグループの結合方法を学びます。前のステップで使用した inventory および playbook.yml ファイルを引き続き使用します。
まず、正しい作業ディレクトリにいることを確認してください。
cd ~/project/ansible_patterns
論理演算子を効果的に示すために、ホストグループに一部重複を作成する必要があります。inventory ファイルを編集して、1 つの Web サーバーと 1 つのデータベースサーバーを含む production という新しいグループを追加しましょう。
nano inventory
ファイルの末尾に [production] グループとそのメンバーを追加します。
[webservers]
web1.example.com
web2.example.com
[dbservers]
db1.lab.net
db2.lab.net
[production]
web1.example.com
db1.lab.net
ファイルを保存し、Ctrl+X、Y、Enter の順に押して nano を終了します。
次に、除外を練習しましょう。NOT を意味する ! 演算子を使用すると、選択からホストまたはグループを除外できます。playbook.yml を編集して、dbservers グループのホストを除くすべてのホストをターゲットにします。
nano playbook.yml
以下のように hosts 行を更新します。パターン all,!dbservers は、すべてのホストを選択してから、dbservers グループに含まれるホストを削除します。
---
- name: Test Host Patterns
hosts: all,!dbservers
gather_facts: false
tasks:
- name: Display the inventory hostname
ansible.builtin.debug:
msg: "This task is running on {{ inventory_hostname }}"
エディタを保存して終了し、Playbook を実行します。
ansible-playbook playbook.yml -i inventory
Web サーバーのみがターゲットになっているはずです。
PLAY [Test Host Patterns] ******************************************************
TASK [Display the inventory hostname] ******************************************
ok: [web1.example.com] => {
"msg": "This task is running on web1.example.com"
}
ok: [web2.example.com] => {
"msg": "This task is running on web2.example.com"
}
PLAY RECAP *********************************************************************
web1.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
予想どおり、webservers グループのホストのみがターゲットになりました。
次に、論理 AND 演算子を探求しましょう。& 演算子は、両方の指定されたグループに存在するホストのみを選択します(共通部分)。Playbook を変更して、webservers グループと production グループの両方に属するホストをターゲットにします。
nano playbook.yml
hosts 行を webservers,&production に変更します。
---
- name: Test Host Patterns
hosts: webservers,&production
gather_facts: false
tasks:
- name: Display the inventory hostname
ansible.builtin.debug:
msg: "This task is running on {{ inventory_hostname }}"
保存して Playbook を実行します。
ansible-playbook playbook.yml -i inventory
今回は、両方のグループの共通部分のみがターゲットになります。
PLAY [Test Host Patterns] ******************************************************
TASK [Display the inventory hostname] ******************************************
ok: [web1.example.com] => {
"msg": "This task is running on web1.example.com"
}
PLAY RECAP *********************************************************************
web1.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
出力は、web1.example.com が webservers および production グループの両方のメンバーである唯一のホストであるため、正しくターゲットにされたことを示しています。これらの演算子により、自動化が影響を与えるホストを正確に制御できます。
include_tasks と import_tasks を使用した Play のモジュール化
このステップでは、より大きな Ansible プロジェクトを、小さく再利用可能なファイルに分割して構造化する方法を学びます。Playbook が大きくなるにつれて、すべてのタスクを 1 つのファイルに保持することは管理が困難になります。Ansible はこのための 2 つの主要なディレクティブを提供します:import_tasks と include_tasks です。どちらも別のファイルからタスクを取り込むことができます。
import_tasksは静的です。Playbook が Ansible によって最初に解析されるときに処理されます。これは、Play の条件なしの構造的な部分に最適です。include_tasksは動的です。Play の実行中に処理されます。これにより、ループや条件付きで使用するのに適しています。
これらの両方を使用するように Playbook をリファクタリングします。まず、プロジェクトディレクトリにいることを確認してください。
cd ~/project/ansible_patterns
続行する前に、この実験環境でホストが localhost を指すようにインベントリファイルを更新しましょう。これにより、Playbook が正常に実行できるようになります。
nano inventory
以下の設定でコンテンツを置き換えて、例のホストを localhost にマッピングします。
[webservers]
web1.example.com ansible_host=localhost ansible_connection=local
web2.example.com ansible_host=localhost ansible_connection=local
[dbservers]
db1.lab.net ansible_host=localhost ansible_connection=local
db2.lab.net ansible_host=localhost ansible_connection=local
エディタを保存して終了します。この設定では、ansible_host=localhost を使用してローカルマシンへの接続をリダイレクトし、ansible_connection=local を使用して SSH 接続の試行を回避します。
一般的なプラクティスとして、再利用可能なタスクファイルを専用のサブディレクトリに保存します。tasks という名前のディレクトリを作成しましょう。
mkdir tasks
次に、多くのサーバーに適用される可能性のある一般的なセットアップタスク用のファイルを作成します。ここでは httpd Web サーバーパッケージをインストールするタスクを配置します。
nano tasks/web_setup.yml
以下のコンテンツを追加します。このファイルはタスクのリストにすぎず、完全な Play 構造(hosts: や name: など)は含まれていないことに注意してください。
- name: Install the httpd package
ansible.builtin.dnf:
name: httpd
state: present
become: true
nano を保存して終了します。次に、簡単な検証ステップ用の 2 番目のタスクファイルを作成します。
nano tasks/verify_config.yml
このファイルに以下のデバッグタスクを追加します。
- name: Display a verification message
ansible.builtin.debug:
msg: "Configuration tasks applied to {{ inventory_hostname }}"
エディタを保存して終了します。次に、これらの新しいタスクファイルを使用するように、メインの playbook.yml を変更します。静的なセットアップには import_tasks を、動的な検証メッセージには include_tasks を使用します。
nano playbook.yml
playbook.yml のコンテンツ全体を以下に置き換えます。この Playbook は、webservers グループをターゲットにし、モジュール化されたタスクファイルを使用します。
---
- name: Configure Web Servers
hosts: webservers
gather_facts: false
tasks:
- name: Import web server setup tasks
import_tasks: tasks/web_setup.yml
- name: Include verification tasks
include_tasks: tasks/verify_config.yml
ファイルを保存して Playbook を実行します。
ansible-playbook playbook.yml -i inventory
モジュール化されたタスクが実行されているのが表示されるはずです。
PLAY [Configure Web Servers] ***************************************************
TASK [Import web server setup tasks] *******************************************
imported: /home/labex/project/ansible_patterns/tasks/web_setup.yml
TASK [Install the httpd package] ***********************************************
changed: [web1.example.com]
changed: [web2.example.com]
TASK [Include verification tasks] **********************************************
included: /home/labex/project/ansible_patterns/tasks/verify_config.yml for web1.example.com, web2.example.com
TASK [Display a verification message] ******************************************
ok: [web1.example.com] => {
"msg": "Configuration tasks applied to web1.example.com"
}
ok: [web2.example.com] => {
"msg": "Configuration tasks applied to web2.example.com"
}
PLAY RECAP *********************************************************************
web1.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
出力で、タスクがそれぞれのファイルからインポートおよびインクルードされていることが明確に示されていることに注目してください。このモジュール化されたアプローチにより、自動化がよりクリーンで保守しやすくなります。
import_playbook を使用したワークフローの構成
このステップでは、import_playbook を使用して、個々の Playbook をオーケストレーションし、複雑なワークフローを形成する方法を学びます。import_tasks および include_tasks が単一の Play 内でタスクリストを再利用するためのものであるのに対し、import_playbook はより上位のレベルで機能します。これにより、特定の順序で他の自己完結型 Playbook を実行するマスター Playbook を作成できます。これは、アプリケーションスタック全体をプロビジョニングするなど、大規模な自動化を管理するための標準的な方法です。
まず、正しいディレクトリにいることを確認し、この新しい構造のためにプロジェクトを整理しましょう。
cd ~/project/ansible_patterns
個々のコンポーネント Playbook を専用のサブディレクトリに保存することは、ベストプラクティスです。playbooks という名前のディレクトリを作成しましょう。
mkdir playbooks
次に、前のステップで作成した、Web サーバーを構成する Playbook をこの新しいディレクトリに移動します。より分かりやすい名前に変更することも良い考えです。
mv playbook.yml playbooks/web_configure.yml
ただし、Playbook をサブディレクトリに移動したため、タスクファイルへの相対パスを更新する必要があります。タスクファイルは、メインプロジェクトディレクトリからの相対パスで tasks/ ディレクトリにまだ存在するため、パスを調整する必要があります。
nano playbooks/web_configure.yml
Playbook 内のパスを tasks/ の代わりに ../tasks/ を使用するように更新します。
---
- name: Configure Web Servers
hosts: webservers
gather_facts: false
tasks:
- name: Import web server setup tasks
import_tasks: ../tasks/web_setup.yml
- name: Include verification tasks
include_tasks: ../tasks/verify_config.yml
エディタを保存して終了します。
パスが正しく機能していることを確認するために、修正された Playbook をテストしましょう。
ansible-playbook playbooks/web_configure.yml -i inventory
修正されたパスで Playbook が正常に実行されるはずです。
次に、データベースサーバーを構成するための新しい独立した Playbook を作成します。この Playbook は dbservers グループをターゲットにし、mariadb パッケージをインストールします。
nano playbooks/db_setup.yml
ファイルに以下のコンテンツを追加します。これは完全なスタンドアロン Play です。
---
- name: Configure Database Servers
hosts: dbservers
gather_facts: false
tasks:
- name: Install mariadb package
ansible.builtin.dnf:
name: mariadb
state: present
become: true
- name: Display a confirmation message
ansible.builtin.debug:
msg: "Database server {{ inventory_hostname }} configured."
エディタを保存して終了します。これで、Web サーバー用の Playbook とデータベースサーバー用の Playbook の 2 つのコンポーネント Playbook ができました。
最後に、トップレベルの「メイン」Playbook を作成します。このファイル自体にはホストやタスクは含まれません。その唯一のジョブは、他の Playbook を正しい順序でインポートして、全体的なワークフローを定義することです。
nano main.yml
以下のコンテンツを追加します。これにより、まず Web サーバーを構成し、次にデータベースサーバーを構成するワークフローが作成されます。
---
- name: Import the web server configuration play
import_playbook: playbooks/web_configure.yml
- name: Import the database server configuration play
import_playbook: playbooks/db_setup.yml
nano を保存して終了します。これで、main.yml Playbook を実行して、ワークフロー全体を実行する準備が整いました。
ansible-playbook main.yml -i inventory
出力には、2 つの Playbook が順次実行されていることが表示され、import_playbook がどのようにして小さく管理可能な部分からより大きなワークフローを効果的に構成するかを示しています。
PLAY [Configure Web Servers] ***************************************************
TASK [Import web server setup tasks] *******************************************
imported: /home/labex/project/ansible_patterns/playbooks/../tasks/web_setup.yml
TASK [Install the httpd package] ***********************************************
ok: [web1.example.com]
ok: [web2.example.com]
TASK [Include verification tasks] **********************************************
included: /home/labex/project/ansible_patterns/playbooks/../tasks/verify_config.yml for web1.example.com, web2.example.com
TASK [Display a verification message] ******************************************
ok: [web1.example.com] => {
"msg": "Configuration tasks applied to web1.example.com"
}
ok: [web2.example.com] => {
"msg": "Configuration tasks applied to web2.example.com"
}
PLAY [Configure Database Servers] **********************************************
TASK [Install mariadb package] *************************************************
changed: [db1.lab.net]
changed: [db2.lab.net]
TASK [Display a confirmation message] ******************************************
ok: [db1.lab.net] => {
"msg": "Database server db1.lab.net configured."
}
ok: [db2.lab.net] => {
"msg": "Database server db2.lab.net configured."
}
PLAY RECAP *********************************************************************
db1.lab.net : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
db2.lab.net : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web1.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
web2.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
出力は、2 つの別々の Play が順次実行されていることを明確に示しており、import_playbook がどのようにして小さく管理可能な部分からより大きなワークフローを効果的に構成するかを示しています。
完全なモジュール化 Playbook の実行と検証
この最終ステップでは、構築した完全なモジュール化されたワークフローを実行し、さらに重要なこととして、自動化がターゲットシステムで意図した状態を達成したことを確認する方法を学びます。Playbook の実行が成功することは良いことですが、結果を確認することは信頼性の高い自動化のために不可欠です。
まず、メインプロジェクトディレクトリにいることを確認してください。
cd ~/project/ansible_patterns
最終 Playbook を実行する前に、作成したプロジェクト全体の構造を視覚化しましょう。tree コマンドはこの目的に最適です。インストールされていない場合は、dnf で追加できます。
sudo dnf install -y tree
tree .
以下のような構造が表示されるはずです。
.
├── inventory
├── main.yml
├── playbooks
│ ├── db_setup.yml
│ └── web_configure.yml
└── tasks
├── verify_config.yml
└── web_setup.yml
2 directories, 6 files
この構造は、メインのエントリポイント (main.yml)、個別の Playbook ファイル、および再利用可能なタスクファイルを備えており、Ansible プロジェクトを管理するためのスケーラブルで保守性の高い方法です。
次に、トップレベルの main.yml Playbook を実行して、ワークフロー全体を実行します。
ansible-playbook main.yml -i inventory
Playbook が正常に完了した後、次の重要なステップは検証です。システムが意図した状態にあることを確認する必要があります。私たちの Playbook は、Web サーバーに httpd パッケージを、データベースサーバーに mariadb パッケージをインストールするように設計されていました。この実験環境のすべてのタスクはローカルマシンで実行されるため、rpm コマンドを使用して直接インストールを確認できます。
まず、Web サーバー構成の一部として httpd パッケージがインストールされたかどうかを確認します。
rpm -q httpd
パッケージがインストールされていることを確認する出力が表示されるはずです。
httpd-2.4.xx-x.el9.x86_64
次に、データベースサーバー構成からの mariadb パッケージのインストールを確認します。
rpm -q mariadb
同様に、mariadb がインストールされていることを確認する出力が表示されるはずです。
mariadb-10.5.xx-x.el9.x86_64
パッケージ名が出力に表示されることで、Ansible Playbook がシステムを意図したとおりに正常に構成したことが確認できます。これで、モジュール化された Ansible プロジェクトを最初から最後まで正常に構築、実行、および検証しました。
まとめ
この実験では、RHEL 上で複雑な Ansible Playbook を構造化するための基本的なテクニックを学びました。まず、ホスト選択の基本から始め、インベントリファイルで定義されたノードを正確にターゲットするために、基本的なグループ名、ワイルドカード、除外、および論理演算子を使用しました。次に、モジュール化に焦点を移し、include_tasks(動的インクルード用)と import_tasks(静的インクルード用)の両方を使用して、大きな Play をより管理可能で再利用可能なコンポーネントに分割する練習を行いました。
これらのスキルを基盤として、個々の Playbook を import_playbook でリンクすることにより、完全なマルチステージワークフローを構成する方法を学びました。実践的なプロセスには、Ansible のインストール、プロジェクト構造の作成、および単純な Playbook を段階的にリファクタリングして洗練されたマルチファイル構造にする作業が含まれました。この実験は、最終的な複合 Playbook を実行し、自動化されたワークフロー全体が正しくターゲットされたホストに対して正常に実行されたことを検証することで最高潮に達し、自動化に対する整理されたスケーラブルなアプローチを示しました。


