こういった悩みを持つLinuxエンジニアは少なくありません。
実は、すでにAnsibleを使っているなら、同じPlaybookの構造でEC2インスタンスの作成・起動・停止・削除まで自動化できます。
amazon.awsコレクションのec2_instanceモジュールを使えば、Terraformを導入しなくてもAWSインフラのコード管理が始められるのです。
この記事では、AnsibleのEC2プロビジョニング設計を基礎から解説します。
認証設計・Playbookの基本パターン・プロビジョニング直後の接続設計まで、現場で再現できるレベルで説明します。
動作確認環境: RHEL 9.4 / Amazon Linux 2023(コントロールノード)、Ansible 2.16、amazon.aws 8.x。
この記事のポイント
・amazon.aws.ec2_instanceモジュール1つでEC2を冪等に作成・管理できる
・IAM認証は環境変数またはIAMロールで設定し、Playbookに認証情報を書かない
・group_varsでdev・prod環境を分離するとPlaybookを使いまわせる
・add_hostでプロビジョニング直後から設定Playbookを続けて流せる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AnsibleによるEC2プロビジョニングとは|Terraform・AWS CLIとの役割分担
Ansibleはもともとサーバーの設定を自動化するツールですが、amazon.awsコレクションを使えばAWSリソース自体の作成・管理(プロビジョニング)も担えます。よく比較されるTerraformとの違いはこうです。
・Terraform: 状態ファイル(tfstate)でインフラ全体の状態を管理する。複雑なVPC設計・依存関係の解決が得意
・Ansible: Playbookの実行ごとに「現在の状態」を確認して冪等に動作する。すでにAnsibleを使っているチームがAWSリソース管理も一元化したい場合に向く
・AWS CLI: アドホックな操作に向くが冪等性がなく、同じコマンドを2度実行すると2台のEC2が立つ
「すでにAnsibleでLinuxサーバーを管理しているが、EC2の起動だけAWS CLIで手動でやっている」という現場は多いです。
そこにAnsibleのEC2プロビジョニングを組み込むと、インフラ構築から設定管理まで1本のPlaybookで完結させられます。
amazon.awsコレクションのインストールと認証設計
1. boto3・botocore・amazon.awsコレクションのインストール
ec2_instanceモジュールを使うにはPythonのAWS SDKであるboto3とbotocoreが必要です。Ansibleと同じPython環境(通常はvenv内)にインストールしてください。
# boto3・botocoreをインストールする pip install boto3 botocore # amazon.awsコレクションをインストールする(バージョン8.x系) ansible-galaxy collection install amazon.aws # インストール確認 ansible-galaxy collection list | grep amazon.aws
プロジェクト内で固定したい場合は `collections/requirements.yml` に記載して `ansible-galaxy collection install -r requirements.yml` で管理します。
2. AWS認証情報の設計|IAMロール・環境変数・credentialsファイル
認証情報をPlaybook内にベタ書きするのは厳禁です。以下の3つから現場に合った方法を選んでください。・IAMロール(推奨): Ansibleコントロールノード自体がEC2なら、インスタンスにIAMロールを付けるだけで認証情報の設定が不要になる
・環境変数(CI/CDや開発環境向け): `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_DEFAULT_REGION` を設定する
・credentialsファイル: `~/.aws/credentials` に複数プロファイルを持つ場合、`AWS_PROFILE` 変数でプロファイルを切り替える
# 環境変数で認証する場合(.envファイルなどで管理する) export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY export AWS_DEFAULT_REGION=ap-northeast-1 # credentialsファイルのプロファイルを切り替える場合 export AWS_PROFILE=myproject-prod
・`ec2:RunInstances`(インスタンス起動)
・`ec2:DescribeInstances`(一覧取得・状態確認)
・`ec2:StopInstances` / `ec2:StartInstances` / `ec2:TerminateInstances`
・`ec2:CreateTags`(Nameタグ付与)
「ec2:*」で全許可するよりも上記の必要権限のみに絞るのが現場のセキュリティ基準です。
ec2_instanceモジュールの基本設計|AMI・インスタンスタイプ・VPCの設定パターン
1. 必須パラメータとstateによる冪等制御
ec2_instanceモジュールの主なパラメータを整理します。| パラメータ | 説明 | 設定例 |
|---|---|---|
name |
インスタンス名(Nameタグ)冪等性のキー | web-prod-01 |
image_id |
起動するAMIのID(リージョンごとに異なる) | ami-0abc12345678abcde |
instance_type |
インスタンスタイプ | t3.micro |
key_name |
SSH接続用キーペア名(AWSに登録済みのもの) | my-ec2-keypair |
security_groups |
セキュリティグループ名またはID(リスト) | ['web-sg'] |
vpc_subnet_id |
起動先サブネットID | subnet-0abc12345678 |
state |
操作の種類(present/stopped/absent/terminated) | present |
region |
AWSリージョン | ap-northeast-1 |
`state`の値で操作が変わります。
・present: インスタンスが存在しない場合は作成、停止中なら起動する
・stopped: 起動中なら停止する。存在しない場合は作成後に停止状態にする
・absent / terminated: インスタンスを削除する。存在しない場合は何もしない(冪等)
`name`パラメータがNameタグに使われ、これが冪等性のキーになります。
同じ`name`のインスタンスがすでに起動中なら「changed: false」で何もしません。
2. 最小構成の動作確認Playbook
まず1台のEC2を起動する最小構成のPlaybookで動作を確認します。# playbooks/provision_ec2.yml --- - name: EC2インスタンスを1台起動する(動作確認用) hosts: localhost connection: local gather_facts: false tasks: - name: Webサーバー用EC2インスタンスを作成・起動する amazon.aws.ec2_instance: name: "web-test-01" image_id: "ami-0a0000000000aaaaa" # Amazon Linux 2023 ap-northeast-1 instance_type: "t3.micro" key_name: "my-ec2-keypair" security_groups: - "default" vpc_subnet_id: "subnet-0abc12345678" state: present region: ap-northeast-1 tags: Environment: test Role: webserver register: ec2_result - name: 起動結果のIPアドレスを表示する ansible.builtin.debug: msg: "インスタンスID: {{ ec2_result.instances[0].instance_id }} プライベートIP: {{ ec2_result.instances[0].private_ip_address }}"
$ ansible-playbook playbooks/provision_ec2.yml PLAY [EC2インスタンスを1台起動する(動作確認用)] *** TASK [Webサーバー用EC2インスタンスを作成・起動する] *** changed: [localhost] TASK [起動結果のIPアドレスを表示する] *** ok: [localhost] => { "msg": "インスタンスID: i-0abc12345678abcde プライベートIP: 10.0.1.50" } PLAY RECAP *** localhost : ok=2 changed=1
実践Playbook|開発・本番環境のEC2を冪等に管理する設計
1. group_varsで環境別パラメータを分離する
dev・prod環境でインスタンスタイプやサブネットが違う場合は、group_varsに分離するのが定石です。# ディレクトリ構成 provision/ ├── playbooks/ │ └── provision_ec2.yml ├── group_vars/ │ ├── all.yml # 共通設定(AMI ID、リージョン、キーペア名) │ ├── development.yml # dev環境: t3.micro、devサブネット │ └── production.yml # prod環境: t3.medium、prodサブネット └── inventory/ └── localhost.yml
# group_vars/all.yml aws_region: ap-northeast-1 ec2_ami_id: "ami-0a0000000000aaaaa" # Amazon Linux 2023 ec2_key_name: "my-ec2-keypair" ec2_security_groups: - "web-sg" # group_vars/development.yml env_name: development ec2_instance_type: t3.micro ec2_subnet_id: "subnet-0dev123456789" # group_vars/production.yml env_name: production ec2_instance_type: t3.medium ec2_subnet_id: "subnet-0prod12345678"
2. 環境を引数で切り替えるPlaybook設計
# playbooks/provision_ec2.yml --- - name: EC2インスタンスを環境別にプロビジョニングする hosts: localhost connection: local gather_facts: false # 実行時に -e "env=development" または -e "env=production" で切り替える vars: env: "{{ lookup('env', 'TARGET_ENV') | default('development') }}" tasks: - name: 環境別のgroup_varsを読み込む ansible.builtin.include_vars: file: "group_vars/{{ env }}.yml" - name: Webサーバー用EC2インスタンスを作成する amazon.aws.ec2_instance: name: "web-{{ env_name }}-01" image_id: "{{ ec2_ami_id }}" instance_type: "{{ ec2_instance_type }}" key_name: "{{ ec2_key_name }}" security_groups: "{{ ec2_security_groups }}" vpc_subnet_id: "{{ ec2_subnet_id }}" state: present region: "{{ aws_region }}" tags: Environment: "{{ env_name }}" Role: webserver ManagedBy: ansible register: ec2_result - name: インスタンス情報を変数に保持する ansible.builtin.set_fact: provisioned_private_ip: "{{ ec2_result.instances[0].private_ip_address }}" provisioned_instance_id: "{{ ec2_result.instances[0].instance_id }}" - name: 起動結果を表示する ansible.builtin.debug: msg: - "環境: {{ env_name }}" - "インスタンスID: {{ provisioned_instance_id }}" - "プライベートIP: {{ provisioned_private_ip }}"
# 開発環境のEC2を起動する ansible-playbook playbooks/provision_ec2.yml -e "env=development" # 本番環境のEC2を起動する ansible-playbook playbooks/provision_ec2.yml -e "env=production" # 本番環境のEC2を停止する(stateをstopped に変更) ansible-playbook playbooks/provision_ec2.yml -e "env=production" -e "ec2_state=stopped"
AnsibleでAWS構築を体系的に学びたい方へ
Playbookの書き方・Role設計・Vault暗号化・CI/CD連携まで、実機環境で手を動かしながら習得できます。
独学でつまずいている方は、現役エンジニアが指導するハンズオンセミナーで一気に理解を深めましょう。
>> Ansible実践セミナーの詳細・申込はこちら
プロビジョニング後に接続するadd_host設計|EC2作成から設定適用まで1本のPlaybookで完結させる
EC2を作成したら、すぐにそのIPに接続してパッケージインストールや設定ファイル配布を行いたいケースがほとんどです。`add_host`モジュールを使うと、Playbookの実行中に動的にホストを追加できます。
# EC2プロビジョニング → 初期設定まで1本で流すPlaybook例 --- - name: フェーズ1:EC2インスタンスを作成する hosts: localhost connection: local gather_facts: false tasks: - name: EC2を起動する amazon.aws.ec2_instance: name: "web-prod-01" image_id: "ami-0a0000000000aaaaa" instance_type: t3.medium key_name: my-ec2-keypair security_groups: - web-sg vpc_subnet_id: subnet-0prod12345678 state: present region: ap-northeast-1 tags: Environment: production register: ec2_result - name: EC2が起動完了するまで待つ amazon.aws.ec2_instance_info: instance_ids: "{{ ec2_result.instances[0].instance_id }}" region: ap-northeast-1 register: instance_info until: instance_info.instances[0].state.name == 'running' retries: 10 delay: 15 - name: 新しいEC2をインベントリに追加する ansible.builtin.add_host: name: "{{ ec2_result.instances[0].private_ip_address }}" groups: newly_provisioned ansible_user: ec2-user ansible_ssh_private_key_file: "~/.ssh/my-ec2-keypair.pem" - name: フェーズ2:新しいEC2に初期設定を流す hosts: newly_provisioned gather_facts: true tasks: - name: SSHが応答できる状態になるまで待つ ansible.builtin.wait_for_connection: delay: 10 timeout: 120 - name: パッケージを最新化する ansible.builtin.dnf: name: "*" state: latest become: true - name: Nginxをインストールする ansible.builtin.dnf: name: nginx state: present become: true
このタスクを省くと「SSH connection refused」でPlaybookがエラー終了することがあります。
よくあるエラーとトラブルシュート
| エラーメッセージ | 原因 | 対処 |
|---|---|---|
An error occurred (AuthFailure) |
IAM権限が不足、または認証情報が未設定 | IAMポリシーにec2:RunInstances等が含まれているか確認。環境変数が正しくエクスポートされているか確認する |
InvalidAMIID.NotFound |
AMI IDが誤り、またはリージョンが違う | aws ec2 describe-images --image-ids ami-XXXX --region ap-northeast-1 で確認する |
InvalidSubnetID.NotFound |
Subnet IDが誤り、または別リージョンのID | aws ec2 describe-subnets --region ap-northeast-1 でサブネット一覧を確認する |
ModuleNotFoundError: No module named 'boto3' |
boto3がインストールされていない | Ansibleを実行するPython環境にpip install boto3 botocoreを実行する |
unreachable: SSH connection refused |
EC2起動直後でSSHデーモンが未起動 | add_hostの前にwait_for_connectionタスクを追加する |
You need to install the amazon.aws collection |
コレクションが未インストール | ansible-galaxy collection install amazon.awsを実行する |
セキュリティグループでSSH(22番ポート)が開いていない場合も接続できません。
ポートの開放状況はLinux側から確認する場合はssコマンドやlsofによるポート確認の方法も参考にしてください。
【注意】state: absent は本番環境での誤実行に注意
`state: absent` または `state: terminated` を指定したPlaybookを本番環境で誤って実行すると、EC2インスタンスが削除されます。
削除されたインスタンスはストレージも含めて失われ、復元はできません。
本番Playbook実行前には必ず `--check`(ドライランモード)で変更内容を確認する習慣をつけてください。
また、本番環境用のPlaybookには `when: env_name == 'production'` の条件ガードを設けて、誤った環境への適用を防ぐ設計が重要です。
まとめ
この記事では、AnsibleのEC2プロビジョニング設計を解説しました。| やりたいこと | Ansible設定・操作 |
|---|---|
| EC2インスタンスを作成・起動する | amazon.aws.ec2_instance: state: present |
| EC2インスタンスを停止する | amazon.aws.ec2_instance: state: stopped |
| EC2インスタンスを削除する | amazon.aws.ec2_instance: state: absent |
| インスタンスIPを取得して後続タスクに渡す | register: ec2_result → ec2_result.instances[0].private_ip_address |
| 起動後に動的に接続する | ansible.builtin.add_host + wait_for_connection |
| dev・prod環境を1本のPlaybookで管理する | group_vars/development.yml / group_vars/production.yml に分離する |
次のステップとして、以下のような応用を検討してみてください。
・Ansible Vault: AWSのアクセスキーをVaultで暗号化してリポジトリに安全にコミットする
・動的Inventory: aws_ec2プラグインを使えば既存EC2を自動で拾えるため、add_hostなしで管理できる
・Role化: EC2プロビジョニング部分をroleとして分離すると複数プロジェクトで再利用しやすくなる
関連記事:
・Linux ポート確認の全コマンド(ss・lsof・netstat)
・Linux DNS 設定の基本(resolv.conf・nmcliの設定方法)
AnsibleでAWS構築を体系的に学びたい方へ
Playbookの書き方・Role設計・Vault暗号化・CI/CD連携まで、実機環境で手を動かしながら習得できます。
独学でつまずいている方は、現役エンジニアが指導するハンズオンセミナーで一気に理解を深めましょう。
>> Ansible実践セミナーの詳細・申込はこちら
Linux無料マニュアルを受け取る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Ansibleのcopy・fileモジュールでファイル管理を自動化する方法|バックアップ・権限設定・シンボリックリンクの実践パターン
- この記事の属するカテゴリ:Ansibleへ戻る

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