こういった悩みは、Ansibleを実務で使い始めた多くのエンジニアが通る道です。
チュートリアルの段階ではひとつのPlaybookに全部書いても問題ありません。ですが、管理するサーバー台数が増え、環境(開発・本番)が分かれ、チームで共有するようになった瞬間に「なぜこう書いたのか誰も分からない」状態に陥ります。
この記事では、ansible inventory role module の3軸を軸に、現場で崩れない構成管理の設計方針を解説します。「ファイルの置き場所の原則」「roleの分割粒度」「moduleの選び方」まで、実際に手を動かしながら理解できる内容にしています。
この記事のポイント
・ansible inventory は環境別(dev/prod)に分離し host_vars で個体差を吸収する
・role は機能単位(nginx/mariadb)で分割し依存性を ansible-galaxy で管理する
・module は「冪等性が保証されるか」を基準に選択。command/shell は最終手段
・inventory・role・module の設計が揃って初めて構成管理が安定する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜinventory・role・moduleの設計が構成管理の核心なのか
Ansibleで構成管理を始めると、最初は一枚のPlaybookで十分に感じます。しかし現場では早い段階でこんな問題が起きます。・本番と開発でIPアドレスが違うのにPlaybookをコピーして運用している
・Nginxの設定とMariaDBの設定が同一ファイルに混在していてどこを直せばいいか分からない
・`shell: curl http://...` を書いてしまい、何度実行しても同じ結果になるか確信が持てない
これらの問題はツールの問題ではなく、設計の問題です。inventory・role・moduleの3つを正しく設計すれば、Ansibleは「何度実行しても同じ状態になる」「環境差分を安全に管理できる」ツールとして機能します。
inventory設計:環境と個体差を分離する
1. ディレクトリ型inventoryで環境を分ける
ファイル型inventoryの典型的な失敗パターンは、`hosts` という1ファイルに開発・本番のホストをコメントで切り替えながら書くことです。コメントアウトのミスが本番事故につながります。推奨するのは、環境ごとにディレクトリを分けるディレクトリ型inventoryです。
# ディレクトリ構造(推奨) inventories/ ├── dev/ │ ├── hosts # 開発環境のホスト定義 │ └── group_vars/ │ └── all.yml # 開発環境共通変数 └── prod/ ├── hosts # 本番環境のホスト定義 └── group_vars/ └── all.yml # 本番環境共通変数
# inventories/dev/hosts の例 [web] web01.dev.example.com web02.dev.example.com [db] db01.dev.example.com [all:vars] ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/dev_key.pem
# 開発環境に対してPlaybookを実行 ansible-playbook -i inventories/dev site.yml # 本番環境に対してPlaybookを実行(ドライラン推奨) ansible-playbook -i inventories/prod site.yml --check
2. host_varsで個体差を吸収する
同じ役割(webサーバー)でもホストごとにIPアドレスやディスク構成が違うことがあります。これを `host_vars` で管理します。# host_vars/web01.dev.example.com.yml の例 # サーバー固有の変数をここで定義する nginx_port: 80 data_volume: /dev/xvdb max_conn: 512
# host_vars/web02.dev.example.com.yml の例 nginx_port: 80 data_volume: /dev/xvdc # 別デバイスでも吸収できる max_conn: 256
3. 動的inventoryで台数が増えても崩れない
AWSやAzureのようにインスタンスが動的に増減する環境では、静的なhostsファイルは追いつきません。Ansibleには動的inventory用のプラグインが用意されています。# inventories/dev/aws_ec2.yml(動的inventory設定例) plugin: amazon.aws.aws_ec2 regions: - ap-northeast-1 filters: "tag:Env": dev "tag:Role": web keyed_groups: - key: tags.Role prefix: role # 実行時のコマンド ansible-playbook -i inventories/dev/aws_ec2.yml site.yml
# ansible-inventory -i inventories/dev/aws_ec2.yml --list の出力例(抜粋) { "_meta": { "hostvars": { "10.0.1.23": { "ansible_host": "10.0.1.23", "tags": {"Env": "dev", "Role": "web"} } } }, "role_web": { "hosts": ["10.0.1.23", "10.0.1.24"] } }
role設計:機能単位で分割し依存を管理する
1. roleのディレクトリ構造を理解する
roleはAnsibleが定める規約ディレクトリを持ちます。`ansible-galaxy role init` で雛形を生成するのが最も確実です。# role雛形の生成 ansible-galaxy role init nginx # 生成されるディレクトリ構造 nginx/ ├── defaults/ │ └── main.yml # デフォルト変数(最低優先度) ├── handlers/ │ └── main.yml # handler(サービス再起動など) ├── tasks/ │ └── main.yml # タスク本体 ├── templates/ │ └── nginx.conf.j2 # Jinja2テンプレート ├── vars/ │ └── main.yml # role内固定変数(高優先度) ├── files/ # 静的ファイル ├── meta/ │ └── main.yml # roleの依存関係定義 └── tests/ └── test.yml
2. roleの分割粒度:「1 role = 1サービス」が基準
roleを分割する粒度で悩む人は多いです。現場で安定している基準は「1 role = 1サービス(またはデーモン)」です。・nginx role:Nginxのインストール・設定・起動
・mariadb role:MariaDBのインストール・初期化・設定
・php-fpm role:PHP-FPMのインストール・設定
・common role:全サーバー共通の設定(SELinux・ファイアウォール・ユーザー作成等)
# site.yml(roleを束ねるエントリポイント) --- - name: Configure web servers hosts: web roles: - common - nginx - php-fpm - name: Configure DB servers hosts: db roles: - common - mariadb
3. defaults/main.ymlで可変値を外に出す
role内にIPアドレスやポート番号をハードコードするのは最も避けるべきパターンです。`defaults/main.yml` にデフォルト値を定義し、inventoryの `group_vars` や `host_vars` から上書きできる設計にします。# nginx/defaults/main.yml --- nginx_port: 80 nginx_worker_processes: auto nginx_access_log: /var/log/nginx/access.log nginx_error_log: /var/log/nginx/error.log nginx_max_body_size: 10m
# nginx/templates/nginx.conf.j2(Jinja2テンプレートで変数を展開) worker_processes {{ nginx_worker_processes }}; http { access_log {{ nginx_access_log }}; error_log {{ nginx_error_log }}; server { listen {{ nginx_port }}; client_max_body_size {{ nginx_max_body_size }}; } }
4. handlerで「変更があった時だけ再起動」を実現する
handlerはAnsibleの重要な機能です。「設定ファイルを変更したときだけNginxをreloadする」という冪等な動作を実装できます。# nginx/tasks/main.yml --- - name: Install nginx ansible.builtin.dnf: name: nginx state: present - name: Deploy nginx.conf ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf mode: '0644' notify: Reload nginx # 変更があった場合のみhandlerを呼ぶ - name: Ensure nginx is started and enabled ansible.builtin.service: name: nginx state: started enabled: true
# nginx/handlers/main.yml --- - name: Reload nginx ansible.builtin.service: name: nginx state: reloaded
5. roleの依存関係はmeta/main.ymlで宣言する
`php-fpm` roleは `nginx` roleが先にインストールされている必要があるケースがあります。こういった依存関係は `meta/main.yml` に明示します。# php-fpm/meta/main.yml --- galaxy_info: role_name: php-fpm author: yourname min_ansible_version: "2.15" dependencies: - role: nginx
module設計:冪等性を基準に選ぶ
1. 「冪等性が保証されるmoduleか」を判断軸にする
Ansibleのmoduleを選ぶ基準は明確です。冪等性(何度実行しても同じ結果になる)が保証されているかどうかです。| やりたいこと | 推奨module | 冪等性 |
|---|---|---|
| パッケージをインストール | ansible.builtin.dnf / ansible.builtin.apt |
あり(state: present/absent) |
| 設定ファイルを配置 | ansible.builtin.template / ansible.builtin.copy |
あり(変更なしはスキップ) |
| サービスを起動・有効化 | ansible.builtin.service |
あり(状態を確認して実行) |
| ユーザーを作成 | ansible.builtin.user |
あり(存在確認後に作成) |
| ファイルのパーミッション設定 | ansible.builtin.file |
あり(変更なしはスキップ) |
| 設定ファイルの一部を書き換え | ansible.builtin.lineinfile |
あり(マッチした行のみ変更) |
| 任意のシェルコマンドを実行 | ansible.builtin.command / ansible.builtin.shell |
なし(最終手段) |
2. command/shellを使う前に確認すべきこと
`command` モジュールや `shell` モジュールを使いたくなったとき、まず自問してください。「このコマンドで実現したいことに、専用のAnsible moduleはないか?」例えば、`shell: systemctl enable nginx` と書きたい場合は `ansible.builtin.service` moduleの `enabled: true` で代替できます。`shell: useradd deploy` と書きたい場合は `ansible.builtin.user` moduleで代替できます。
どうしても `command` / `shell` を使う必要がある場合は、`creates` または `removes` パラメータで冪等性を自前実装します。
# commandで冪等性を確保する例 # creates: に指定したファイルが存在する場合はスキップされる - name: Initialize MariaDB data directory ansible.builtin.command: cmd: mysql_install_db --user=mysql --basedir=/usr creates: /var/lib/mysql/mysql # このディレクトリがあればスキップ
3. FQCNでmodule名を書く(Ansible 2.10以降の推奨形式)
Ansibleのmodule名はコレクション管理(FQCN:Fully Qualified Collection Name)の記法で書くことが推奨されています。・旧来の書き方:`dnf:` / `service:` / `template:`
・推奨する書き方:`ansible.builtin.dnf:` / `ansible.builtin.service:` / `ansible.builtin.template:`
FQCNで書くと、どのコレクションのmoduleを使っているかが明確になり、コレクション更新時の動作変化を追いやすくなります。チームで共有するPlaybookほどFQCN表記を徹底してください。
トラブルシュート:よくある設計ミスと対処法
「変数が上書きされない」→優先順位を確認する
Ansibleの変数優先順位は22段階あります。現場でよく起きる混乱は、`vars/main.yml`(高優先度)と `defaults/main.yml`(低優先度)の違いを理解していないことです。・`defaults/main.yml` に書いた値 → inventoryの `group_vars` や `host_vars` で上書き可能(推奨)
・`vars/main.yml` に書いた値 → inventoryの変数より優先されるため、外から上書きできない
外から変えてほしい値は必ず `defaults/main.yml` に書き、roleの内部固定値のみ `vars/main.yml` に書くのが鉄則です。
「Playbook再実行でエラーが出る」→冪等性の欠如を疑う
再実行でエラーになるタスクは、冪等性がない処理が含まれている可能性があります。# エラーが出たときのデバッグ手順 # --check でドライランして変更予定タスクを確認する ansible-playbook -i inventories/dev site.yml --check --diff # 特定のtagを付けたタスクだけ実行して切り分ける ansible-playbook -i inventories/dev site.yml --tags "nginx" # 実行結果の詳細を表示する(-vvv で最大詳細) ansible-playbook -i inventories/dev site.yml -v
「roleが見つからない」→roles_pathの設定を確認する
roleのディレクトリが `roles/` 以外にある場合、`ansible.cfg` で `roles_path` を明示します。# ansible.cfg の設定例 [defaults] inventory = inventories/dev roles_path = roles:~/.ansible/roles remote_user = ec2-user host_key_checking = False # 検証機では無効化することが多い [privilege_escalation] become = True become_method = sudo
本記事のまとめ
inventory・role・module設計の要点をまとめます。| 設計対象 | 原則 | よくある失敗 |
|---|---|---|
| inventory | 環境(dev/prod)でディレクトリを分ける | hostsファイルをコメントで切り替える |
| group_vars | 環境共通変数はgroup_vars/all.ymlに置く | PlaybookにIPをハードコードする |
| host_vars | サーバー個体固有の値をhost_varsで上書く | 全サーバーを同じ変数で一律設定する |
| role分割 | 1 role = 1サービスが基準 | 1 roleに全設定を詰め込む |
| defaults | 外から変える値はdefaults、固定値はvarsに | vars/main.ymlに全変数を書いて上書きできない |
| module選択 | 冪等性があるmoduleを優先し、command/shellは最終手段 | shellで全処理を書いて再実行でエラーになる |
inventoryで環境を分離し、roleで機能を分割し、冪等性のあるmoduleを選ぶ。この3軸を押さえるだけで、Ansibleは「1台のサーバー設定ツール」から「何台でも同じ状態を保証できる構成管理基盤」に変わります。
Ansibleのinventory・role・module設計を実際に手を動かしながら体系的に身につけたい方は、ぜひ詳細をご覧ください。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:AnsibleとシェルスクリプトSSHループの違い|構成管理に踏み出す判断
- 前のページへ:AnsibleでAWS上にNginx・PHP・MariaDBを自動構築する実践手順
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます