Ansible動的インベントリ設計|aws_ec2プラグインでEC2ホストを自動取得する仕組みと設定パターン

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Ansible > Ansible動的インベントリ設計|aws_ec2プラグインでEC2ホストを自動取得する仕組みと設定パターン
「EC2インスタンスを起動するたびにhosts.iniを手動で書き直している。Auto ScalingでIPが変わったらもうPlaybookが動かない」
AWSでAnsibleを使い始めたエンジニアが必ずぶつかる壁だ。クラウド環境では静的なインベントリファイルとインフラの実態がすぐに乖離する。その結果、「インベントリにあるホストが実際には存在しない」エラーや、「起動したばかりのインスタンスがPlaybookの対象にならない」という問題が頻発する。

この記事では、Ansibleの動的インベントリ(Dynamic Inventory)の仕組みと、aws_ec2プラグインを使ったEC2ホスト自動取得の設定パターンを解説する。aws_ec2.yamlの記述方法、タグベースのグループ設計、ansible-inventoryコマンドによる動作確認、静的インベントリとの併用設計、トラブルシュートまで、設計の観点から順を追って説明する。
動作確認環境: RHEL 10 / Ubuntu 24.04 LTS、Ansible 2.17(amazon.aws 8.x)、boto3 1.34。

この記事のポイント

・aws_ec2プラグインはEC2 APIをリアルタイムで呼び出してホスト一覧を自動生成する
・aws_ec2.yaml 1ファイルにリージョン・フィルター・グループ条件を定義できる
・タグ(Env/Role)のkeyed_groupsでhosts.ini不要の自動グループ化が実現できる
・ansible-inventory --graphで取得結果を確認してからPlaybookを実行するのが安全な手順


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

静的インベントリが崩れる理由 | クラウド時代の構成管理の限界

オンプレミスのサーバー環境では、hosts.iniに書いたホスト一覧はそう頻繁には変わらない。「web01.example.com」と書けば、よほどの障害がない限りそのサーバーは存在し続ける。手動管理でも乗り越えられる問題だった。

AWSでは話が違う。Auto Scalingグループが負荷に応じてインスタンスを増減させる。スポットインスタンスが中断されて別のIPで再起動する。ブルーグリーンデプロイでIPレンジが切り替わる。このたびに担当者がhosts.iniを開いて編集し、古いIPを消して新しいIPを追加する作業を繰り返す必要が生じる。

この手動管理が招く典型的な問題を整理する。

「unreachable」エラーの多発: 削除済みEC2インスタンスのIPがhosts.iniに残っていてPlaybookがエラーになる
新規インスタンスの見落とし: Auto Scalingで追加されたインスタンスがPlaybook対象に入らずソフトウェアが未設定のまま本番稼働する
IP管理台帳の二重管理: EC2コンソールとhosts.iniで別々に管理するためどちらが正しいかわからなくなる

動的インベントリはこの構造的な問題を解決するために設計された仕組みだ。

動的インベントリの仕組み | プラグインがEC2 APIを呼び出す構造

動的インベントリを理解するには「Ansibleはインベントリをどう読んでいるか」から入ると整理しやすい。

通常の静的インベントリでは、Ansibleはhosts.iniやhosts.yamlをファイルとして直接読む。動的インベントリでは、Ansibleは設定ファイルを読んだ後にインベントリプラグインを起動する。プラグインがEC2 APIへリクエストを投げて実行中のインスタンス一覧を取得し、その結果をAnsibleが使えるホスト一覧形式に変換する。

処理の流れを整理すると次のようになる。

・Ansibleがaws_ec2.yaml(設定ファイル)を検出
・amazon.aws.aws_ec2プラグインが起動する
・boto3経由でEC2 API(describe-instances)を呼び出す
・レスポンス(インスタンス情報)をAnsibleのホスト一覧形式に変換する
・変換結果がホスト一覧としてPlaybookに渡される

重要なのは「Playbook実行のたびにEC2 APIを叩く」点だ。静的ファイルのように「前回保存した状態」を持たない。Playbookを実行した瞬間のAWSインフラ状態が正確に反映される。

amazon.aws コレクションのインストール

aws_ec2プラグインは amazon.aws コレクションに含まれる。Ansible本体とは別にインストールが必要だ。

# amazon.aws コレクションのインストール ansible-galaxy collection install amazon.aws # バージョン確認 ansible-galaxy collection list | grep amazon.aws # amazon.aws 8.0.0 # boto3(PythonのAWS SDK)のインストール(未導入の場合) pip3 install boto3 botocore

ansible.cfg[inventory] セクションで動的インベントリを有効化する設定も必要だ(デフォルトで有効のバージョンもある)。

# ansible.cfg に追加する設定 [inventory] enable_plugins = amazon.aws.aws_ec2, host_list, script, auto, yaml, ini, toml

aws_ec2プラグインの設定ファイル(aws_ec2.yaml)を書く

動的インベントリの設定は拡張子が aws_ec2.yaml(または aws_ec2.yml)でなければならない。Ansibleがファイル名のサフィックスでプラグインを自動判定するためだ。ファイル名が違うと動的インベントリとして認識されないため注意が必要だ。

1. 最小構成のaws_ec2.yaml

# inventory/aws_ec2.yaml — 最小構成(東京リージョン・実行中インスタンスのみ) plugin: amazon.aws.aws_ec2 regions: - ap-northeast-1 filters: instance-state-name: - running

plugin(使用するプラグイン名)、regions(対象リージョン)、filters(EC2のdescribe-instancesと同じフィルター記法)の3項目がベースだ。filters を省略すると全リージョンの全ステート(停止中・終了済みを含む)のインスタンスが対象になる。通常は instance-state-name: running で実行中のみに絞るのが安全だ。

2. 本番構成のaws_ec2.yaml | タグフィルターとkeyed_groups

実務では「本番環境のWebサーバー群だけを対象にしたい」という要件がある。EC2のタグを使ったフィルタリングと、タグをグループに変換する keyed_groups を組み合わせると柔軟な設計が実現できる。

# inventory/aws_ec2.yaml — タグベースのフィルターとグループ化 plugin: amazon.aws.aws_ec2 regions: - ap-northeast-1 # AWSアクセス設定(IAMロールがある場合は不要、環境変数でも可) aws_profile: myapp-prod # 実行中インスタンスかつ Project=myapp タグのものだけ取得 filters: instance-state-name: - running tag:Project: - myapp # タグをAnsibleグループに変換するルール keyed_groups: # tag_Env_production, tag_Env_staging のようなグループを自動生成 - key: tags.Env prefix: tag_Env separator: _ # tag_Role_web, tag_Role_db のようなグループを自動生成 - key: tags.Role prefix: tag_Role separator: _ # SSH接続に使うホスト名の優先順(プライベートIPを最初に試す) hostnames: - private-ip-address - public-ip-address - dns-name # ansible_host変数に使用するアドレス compose: ansible_host: private_ip_address

keyed_groups セクションの動きを理解しておくことが設計の核になる。EC2インスタンスに Env=productionRole=web というタグが付いていると、そのインスタンスは自動的に tag_Env_productiontag_Role_web の2つのグループに所属する。Playbookで hosts: tag_Role_web と書けば、WebサーバーのEC2インスタンスだけが対象になる。

3. AWSアクセスの設定方法

aws_ec2プラグインがEC2 APIを呼び出すには有効なAWS認証情報が必要だ。優先順位の高い順に設定方法を示す。

IAMロール(最推奨): Ansibleを実行するEC2インスタンスにIAMロールをアタッチする。認証情報をファイルに持たない最も安全な方法
環境変数: AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_DEFAULT_REGION を設定する
AWSプロファイル: ~/.aws/credentials に書いたプロファイルを aws_profile: で指定する
aws_access_key / aws_secret_key(非推奨): yaml内に直書きする方法。Gitにコミットするリスクがあるため Ansible Vaultで暗号化するか、使わないこと

本番環境では「EC2のIAMロール」が最もシンプルで安全だ。Ansibleを実行するPC(コントロールノード)がEC2上にある場合はIAMロール経由のアクセスが自動的に使われる。

タグベースのホストグループとgroup_varsを組み合わせる

keyed_groupsで自動生成されるグループ名は、そのままgroup_varsのディレクトリ名として使える。この組み合わせが「ホストをグループに追加 → 変数が自動適用される」という設計を可能にする。

1. タグ設計の推奨パターン

動的インベントリを前提にEC2タグを設計する際、最低限付けておくタグを定義しておくことが重要だ。後からタグ設計を変えるとPlaybookのグループ名が変わり、group_varsとの対応関係が崩れる。

タグキー 値の例 Ansibleグループ名 用途
Project myapp (フィルターに使用) 対象インスタンスの絞り込み
Env production / staging tag_Env_production 環境別のPlaybook・変数分岐
Role web / db / cache tag_Role_web サーバー役割別のタスク適用

2. group_varsとの対応関係

# ディレクトリ構成の例 inventory/ aws_ec2.yaml ← 動的インベントリ設定 group_vars/ all.yml ← 全ホスト共通変数 tag_Role_web.yml ← Webサーバー共通変数(nginx_port等) tag_Role_db.yml ← DBサーバー共通変数(mysql_max_connections等) tag_Env_production.yml ← 本番環境専用変数(enable_ssl: true等) tag_Env_staging.yml ← ステージング専用変数(enable_ssl: false等) site.yml

keyed_groupsのグループ名とgroup_varsのファイル名を一致させることで、EC2インスタンスにタグを付けるだけで自動的に適切な変数セットが適用される。たとえば Role=web, Env=production のインスタンスには tag_Role_web.ymltag_Env_production.ymlall.ymlの3つの変数ファイルが適用される(後ろの宣言が上書き)。

Webサーバーの設定ファイル配布・handler設計の詳細は、前回の記事「Apache タイムアウト設定の詳細」のApache設定パターンも参考にしてほしい。

動的インベントリとgroup_varsの組み合わせを実機で試したい方は、>> Ansibleハンズオン講座の詳細を見る をご覧ください。

ansible-inventoryコマンドで動作確認する

Playbookを実行する前に、動的インベントリが正しくEC2インスタンスを取得しているかを確認する手順が重要だ。Playbookを実行しながら「なぜか対象外になっている」問題に気づくより、事前に確認した方が効率的だ。

1. --graph でグループとホストの全体像を確認する

# インベントリ構造をツリー形式で表示する ansible-inventory -i inventory/aws_ec2.yaml --graph # 実機での出力例(IPはマスク) @all: |--@aws_ec2: | |--@tag_Env_production: | | |--@tag_Role_web: | | | |--10.0.1.xxx | | | |--10.0.1.yyy | | |--@tag_Role_db: | | | |--10.0.2.xxx | |--@tag_Env_staging: | | |--10.0.10.xxx |--@ungrouped:

@tag_Env_production の下に @tag_Role_web が入れ子になっているのは、keyed_groupsで複数のタググループが割り当てられたからだ。Playbook側で hosts: tag_Role_web と書けば本番・ステージング両環境のWebサーバーが対象になる。本番だけ対象にしたい場合は hosts: tag_Env_production:&tag_Role_web(グループのAND条件)のように書く。

2. --host でホスト変数の詳細を確認する

# 特定ホストの変数をJSON形式で表示する ansible-inventory -i inventory/aws_ec2.yaml --host 10.0.1.xxx # 出力例(抜粋) { "ami_launch_index": 0, "ansible_host": "10.0.1.xxx", "instance_id": "i-0xxxxxxxxxxxx", "instance_type": "t3.medium", "placement": { "availability_zone": "ap-northeast-1a", "region": "ap-northeast-1" }, "tags": { "Env": "production", "Name": "web01", "Project": "myapp", "Role": "web" } }

このコマンドでEC2インスタンスのどの情報がAnsible変数として使えるかを確認できる。Playbookの compose: セクションでこれらの変数を ansible_hostansible_user にマッピングできる。

3. --list で全ホスト・変数をJSON出力する(デバッグ用)

# 全インベントリをJSON形式で出力する(スクリプト連携・デバッグ向け) ansible-inventory -i inventory/aws_ec2.yaml --list | python3 -m json.tool | head -50

静的インベントリとの併用パターン | オンプレとAWSが混在する現場向け

すべてのサーバーがAWSにあるわけではない現場では、静的インベントリ(オンプレミスサーバー)と動的インベントリ(EC2)を同じPlaybookで管理したい場面がある。Ansibleは inventory/ ディレクトリに複数のインベントリソースを置くことで対応できる。

1. ディレクトリ型インベントリの構成

# inventory/ディレクトリに複数ソースを共存させる inventory/ aws_ec2.yaml ← 動的インベントリ(EC2ホスト) onpre_hosts.ini ← 静的インベントリ(オンプレミスホスト) # 実行時はディレクトリ全体を指定する ansible-playbook -i inventory/ site.yml # または ansible.cfg に設定する [defaults] inventory = inventory/

2. オンプレとEC2を同じグループ変数で管理する

静的インベントリ(onpre_hosts.ini)でグループ名を動的インベントリのグループ名と合わせることで、group_vars を共有できる。

# onpre_hosts.ini [tag_Role_web] onpre-web01.example.com ansible_host=192.168.1.10 onpre-web02.example.com ansible_host=192.168.1.11 [tag_Env_production] onpre-web01.example.com onpre-web02.example.com

この設計では、EC2インスタンスもオンプレサーバーも同じ tag_Role_web グループに属する。group_vars/tag_Role_web.yml の変数は両方に適用される。Playbook側は「EC2かオンプレか」を意識せずに書ける。

オンプレミスサーバーのSSH接続確認には、Linux ポート確認の全コマンド(ss・lsof・netstat)も活用してほしい。Ansibleが接続できない場合はポート22が開いているかの確認が切り分けの第一歩になる。

トラブルシュート | ホストが表示されない・認証エラーの対処

1. 認証エラー(NoCredentialsError / AccessDenied)

症状: ansible-inventory コマンドを実行すると以下のエラーが出る。

# 認証情報が見つからない場合 botocore.exceptions.NoCredentialsError: Unable to locate credentials # 権限不足の場合 botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the DescribeInstances operation: User: arn:aws:iam::xxxx is not authorized

NoCredentialsError の対処法:
aws configure でアクセスキーを設定する(~/.aws/credentials が正しく書かれているか確認)
・EC2実行環境の場合はIAMロールがアタッチされているか確認する
・環境変数 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY が設定されているか確認する

AccessDenied の対処法:
aws_ec2プラグインが必要とするIAMポリシーは ec2:DescribeInstancesec2:DescribeRegionsec2:DescribeInstanceTypes だ。IAMロールまたはユーザーにこれらのアクションのAllow権限があるかを確認する。

# 必要最小限のIAMポリシー(例) { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ec2:DescribeInstances", "ec2:DescribeRegions", "ec2:DescribeInstanceTypes" ], "Resource": "*" } ] }

2. ホストが表示されない(フィルター条件の問題)

症状: 認証は通るが --graph に何も表示されない。

最も多い原因は filters の記述ミスだ。EC2のDescribeInstancesフィルターはキー名のフォーマットが厳密で、タグフィルターは tag:キー名(コロン区切り)だが、aws_ec2.yamlではキーに使えない文字をアンダースコアで代替する記法を使う場合がある。バージョンごとに記法が異なることもある。

確認の手順はまず filters を完全に削除して全インスタンスが表示されるか確認する。表示されるなら filters の条件を1つずつ追加して絞り込みの動作を確認する。

# デバッグ: filtersなしで全インスタンスを取得する # (aws_ec2_debug.yaml を別途作成して確認する) plugin: amazon.aws.aws_ec2 regions: - ap-northeast-1 # filters を省略すると全ステートのインスタンスが対象になる ansible-inventory -i aws_ec2_debug.yaml --graph

3. SSHアクセス失敗(ansible_user・秘密鍵の設定)

症状: ホストは表示されるが ansible -m ping で接続失敗する。

EC2インスタンスへのSSHには秘密鍵と正しいユーザー名が必要だ。group_vars または ansible.cfg で設定する。

# group_vars/all.yml での設定例 ansible_user: ec2-user # RHEL/Amazon Linux 2023の場合 # ubuntu の場合は ubuntu, Debianなら admin ansible_ssh_private_key_file: ~/.ssh/myapp-keypair.pem ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ConnectTimeout=10' # 接続確認コマンド(aws_ec2.yamlを使う場合) ansible -i inventory/ all -m ping

EC2のセキュリティグループでポート22(SSH)の受信ルールが、AnsibleコントロールノードのパブリックIPから許可されているかも確認する。また、プライベートサブネット内のEC2に接続する場合はVPNやSSHジャンプホストの設定が必要になる。

本記事のまとめ

やりたいこと 設定・コマンド ポイント
EC2ホストを自動取得する aws_ec2.yaml + amazon.aws.aws_ec2プラグイン ファイル名はaws_ec2.yamlまたはaws_ec2.yml固定
実行中インスタンスだけ対象にする filters: instance-state-name: running フィルターなしだと停止・終了済みも含まれる
タグをAnsibleグループに変換する keyed_groups(key: tags.Env / prefix: tag_Env) グループ名はgroup_varsのファイル名と一致させる
取得結果を事前確認する ansible-inventory -i inventory/ --graph Playbook実行前に必ず確認する習慣をつける
オンプレとEC2を混在管理する inventory/ディレクトリに静的・動的を共存 グループ名を合わせてgroup_varsを共有できる
認証エラーを解決する IAMロール / aws configure / 環境変数のいずれか 必要なIAM権限はec2:DescribeInstancesが最低限
Ansibleの動的インベントリを使うことで、「EC2の増減をPlaybookが自動で認識する」状態が実現できる。hosts.iniを手動で書き直す作業はなくなり、Auto Scalingや複数リージョンの展開も単一のPlaybookで対応できるようになる。

次のステップとして、複数リージョン対応や strict: false オプション(変数未定義でも継続実行)も検討してほしい。Ansibleを使ったクラウドインフラ自動化の設計は、静的→動的インベントリの移行を起点に大きく変わる。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、20年以上の運用経験を持つ現役エンジニアが基礎から教えます。
Ansible実践ハンズオンの詳細を見る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。