初めまして。2025年にSCSKに入社した新人の大原悠利と申します。現在、所属部署の伝統であるクラウド研修に参加しています。
今回はその研修の中で、自分が特に苦戦した「AWS CloudFormationの出力をAnsibleで利用する方法」についてご紹介します。この記事が、同じように悩む方の助けになれば嬉しいです。
実装する要件
概要
AWS CloudFormationと構成管理ツール(Ansible)を用いて、Amazon EC2上にアプリケーションを自動デプロイします。
プライベートネットワーク環境のPCからEC2にアクセスし、Webページが表示されることを確認します。
Ansible® は、プロビジョニング、構成管理、アプリケーションのデプロイメント、オーケストレーション、その他多くの IT プロセスを自動化する、オープンソースの IT 自動化ツールまたは自動化エンジンのこと
参照:Ansible (アンシブル) とは?をわかりやすく解説
アーキテクチャ
本構成は以下の2つの観点で示します。
アーキテクチャ全体像
ユーザーはSCSK PCからRoute53を介してELBにアクセスし、プライベートサブネット内のEC2に接続します。
EC2はElastiCacheと連携し、HTTPS通信はCertificate Managerで管理します。
EC2インスタンス詳細
EC2にはJavaアプリケーションをホストし、Ansibleでデプロイを自動化します。
S3からアプリケーションを取得し、Systems Managerで運用管理、IAMで権限を制御します。
苦戦したところ
細かい要件はいろいろありますが、実装するにあたり特に苦戦した要件は次の1点です。
この要件を満たすために、私はAnsibleの amazon.aws.cloudformation_info モジュールを使う方法が良いと考えました。
amazon.aws.cloudformation_infoモジュールとは
Ansible公式ドキュメントには、以下のように記載されています。
Obtain information about an AWS CloudFormation stack
(AWS CloudFormationスタックに関する情報の取得)
つまり、amazon.aws.cloudformation_infoモジュール(以降 CloudFormation_infoモジュール)を使えば、CloudFormationスタックの情報(Outputsなど)をAnsible上で取得できるということです。
使用例(抜粋)
- name: Get summary information about a stack
amazon.aws.cloudformation_info: # amazon.aws.cloudformation_infoモジュールを使用
stack_name: my-cloudformation-stack # 取得したいCloudFormationスタック名
register: output # 実行結果をoutput変数に格納
Outputsを取得するには以下のようにします。
- set_fact:
stack_name: my-awesome-stack # 対象のCloudFormationスタック名を指定
- amazon.aws.cloudformation_info: # amazon.aws.cloudformation_infoモジュールを使用
stack_name: "{{ stack_name }}" # stack_name変数を参照して情報を取得し、my_stack変数に格納
register: my_stack
- debug:
msg: "{{ my_stack.cloudformation[stack_name].stack_outputs }}" # my_stack.cloudformation[stack_name].stack_outputsでOutputsを取得
CloudFormation_infoモジュールの戻り値では、Outputsはstack_outputsキーに格納されます。例えば、registerでmy_stackとした場合、my_stack.cloudformation[stack_name].stack_outputs.ElastiCacheEndpointで取得できます。
このように、CloudFormation_infoモジュールを使えば、CloudFormationのOutputsをAnsibleで取得できることがわかります。
実装手順
実際には、CloudFormationのOutputsセクションンの設定とAnsible Playbookの設定を行いました。
CloudFormationのOutputs設定
まず、CloudFormationテンプレートの Outputs セクションにElastiCacheのエンドポイントを記述します。
Outputs:
ElastiCacheEndpoint:
Value: !GetAtt ElastiCacheCluster.ConfigurationEndpoint.Address # ElastiCacheのエンドポイントを取得
Export:
Name: ElastiCacheEndpoint # CloudFormation_infoモジュールで参照するための名前
Ansible Playbookの設定
次に、Ansibleでこの出力を取得するために、以下のようなPlaybookを作成しました。
- name: Get ElastiCache endpoint from CloudFormation
amazon.aws.cloudformation_info: # amazon.aws.cloudformation_infoモジュールを使用
stack_name: my-app-stack # 子スタックの名前(仮にmy-app-stackとおく)
region: 'ap-northeast-1' # リージョンの指定
register: cf_output # 実行結果を変数に格納
- name: Set ElastiCache endpoint as a fact
set_fact:
elasticache_endpoint: "{{ cf_output.cloudformation['my-app-stack'].stack_outputs.ElastiCacheEndpoint }}" # CloudFormation Outputsで定義したElastiCacheEndpointを取得
この elasticache_endpointをJVM引数としてアプリに渡すことで、動的にエンドポイントを設定することができると予想しました。
しかし結果はうまくいきませんでした。
なぜうまくいかなかったか
CloudFormation_infoモジュールを使うには、対象のスタック名が必要です。親スタックの名前は作成時に指定できるため問題ありませんが、ネストされた子スタックはCloudFormationが自動で名前を生成するため、事前に把握するのが難しく、結果としてCloudFormationのOutputsを取得できませんでした。
Amazon Linux 2では、デフォルトで古いバージョンのAnsibleやbotocoreがインストールされているため、使用要件に満たさずCloudFormation_infoモジュールが正常に動作しませんでした。研修の要件でAMIを変更できなかったため、ここも大きな制約でした。
実際にCloudFormation_infoモジュールを使うには、以下の環境が必要です
Ansible amazon awsコレクション: 10.1.2以上
Python:3.6以上
boto3:1.34.0以上
botocore:1.34.0以上
研修環境ではAmazon Linux 2を使用していたため、これらのバージョンが古く、モジュールがうまく動作しませんでした。
Ansible-core:2.9.25
Ansible amazon awsコレクション:未インストール
Python:3.7.16
boto3:未インストール
botocore:1.18.6
そこで、対策としてEC2インスタンスにログインして環境を修正しました。その後、再度Ansible Playbookを実行してアプリをデプロイしました。
対策
一度スタックを作成した後に、直接マネジメントコンソール上で確認したスタック名をAnsible Playbook内に記載しました。
- name: Get ElastiCache endpoint from CloudFormation
amazon.aws.cloudformation_info: # amazon.aws.cloudformation_infoモジュールを使用
stack_name: hrd-d0-cfs-y-oohara-ApplicationquickstartStack-1902NZ480MKZ8 # 子スタックの名前
region: 'ap-northeast-1' # リージョンの指定
register: cf_output # 実行結果を変数に格納
- name: Set ElastiCache endpoint as a fact
set_fact:
elasticache_endpoint: "{{ cf_output.cloudformation['hrd-d0-cfs-y-oohara-ApplicationquickstartStack-1902NZ480MKZ8'].stack_outputs.ElastiCacheEndpoint }}" # CloudFormation Outputsで定義したElastiCacheEndpointを取得
CloudFormation_infoモジュールの使用要件を満たすために、EC2インスタンスへ接続し古いAnsibleを削除し、各ソフトウェア (Ansible, Python3, boto3, botocore, Ansible amazon awsコレクション)をインストールしました。その後、Ansible Playbookを実行しました。
sudo yum remove ansible # 古いAnsibleを削除 sudo yum install python3 -y # Python3をインストール sudo python3 -m pip install ansible boto3 botocore # 最新のAnsibleとAWS SDK(boto3, botocore)をpipでグローバルインストール ansible-galaxy collection install amazon.aws # Ansible amazon awsコレクションのインストール ansible-playbook -c local /home/ssm-user/ansible/web_ui_startup.yml # AnsibleのPlaybookをローカルモードで実行
改善した結果、Webページが表示されることを確認することができました。
別解(ペアのyabuさんの方法)
実際に研修中は、自分の方法では実装がかないませんでした。研修ではペアで作業しており、ペアのyabuさんが別のアプローチでこの問題を解決してくれました。自分とは考え方が違っていて、非常に勉強になったのでご紹介します。

大原の考え方
- CloudFormationのOutputsからElastiCacheのエンドポイントを取得
- Ansibleでその出力を受け取り、JVM引数としてアプリに渡す
この方法は理論上は正しいのですが、環境の制約(バージョンやスタック名の取得)でうまくいきませんでした。
yabuさんの考え方
- CloudFormationのUserDataで、EC2インスタンスの環境変数にElastiCacheのエンドポイントを直接出力
- その環境変数をAnsibleで参照してアプリに渡す
EC2インスタンスのUserData設定
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum install -y aws-cfn-bootstrap # CloudFormationのcfn-initやcfn-signalを利用するためにインストール
echo ENDPOINT=${ElastiCache.RedisEndpoint.Address} | sudo tee -a /etc/environment # ElastiCacheのRedisエンドポイントを環境変数に設定
/opt/aws/bin/cfn-init -v \ # CloudFormationのMetadataに基づいて設定を適用
--stack ${AWS::StackName} \ # 現在のスタック名を指定
--resource EC2Instance \ # テンプレート内のEC2リソース論理ID
--region ${AWS::Region} \ # デプロイ先リージョン
--configsets Default # 適用するConfigSet名(Ansible Playbookに記載)
Ansible Playbookの設定
- name: Run Spring Boot application
shell: |
source /etc/environment \ # ElastiCacheのエンドポイントなど環境変数を利用するため /etc/environmentを読み込み
java -jar \
-Dspring.profiles.active=d0 \
-Dspring.data.redis.host=$ENDPOINT \ # Redis接続先を環境変数から設定
/home/appuser/my-spring-app.jar
この方法なら、CloudFormation_infoモジュールのバージョン制約を気にする必要がなく、環境変数として扱えるため非常にシンプルです。
感想
このコードを見たとき、「なるほど!」と目から鱗でした。自分がモジュールにこだわりすぎていたことに気づき、柔軟な発想の大切さを学びました。この考え方を踏まえると、環境変数に子スタック名を記載すると、CloudFormation_infoモジュールが利用できるのかなと思います。
参考:yabuさんの記事
https://blog.usize-tech.com/aws-certification-five-study-methods/
実際のユースケース
今回の研修を通じて、「CloudFormation_infoモジュールを使う方法」と「EC2のUserDataで環境変数として渡す方法」の2つのアプローチを学びました。それぞれのユースケースを整理してみると、使い分けのポイントが見えてきました。そこで、Microsoft Copilotに二つのユースケースの違いを聞いてみました。以下回答になります。
Copilotによる回答
| 方法 | 向いているケース | メリット | デメリット |
| CloudFormation_infoモジュール |
|
|
|
| UserDataで環境変数を渡す方法 |
|
|
|
このように、CloudFormation_infoはAnsible中心の構成管理に向いていて、UserDataはインスタンス起動時の初期設定に向いているという違いがあります。
この回答を踏まえて、どちらが優れているというよりは、目的に応じて使い分けることが重要だと感じました。
最後に
この経験から得た教訓は次の2つです。
バージョンや前提条件は、必ず確認する習慣をつけるべき
新人としてまだまだ未熟ですが、こうした試行錯誤を積み重ねて、少しずつ成長していきたいと思っています。
この記事が、同じように悩んでいる方のヒントになれば幸いです。ここまで読んでいただき、ありがとうございました!


