プライベートサブネット内のインスタンスにAWS-ApplyAnsiblePlaybooksドキュメントを実行する構成
以下のページで、EC2インスタンス(Amazon Linux 2)で初期化処理を実行する方法を4つご紹介しました。
今回はその中の、Ansibleを使用する方法を掘り下げます。前述のページでは、インスタンスがパブリックサブネットに設置されている構成でした。今回はインスタンスがプライベートサブネット内に設置されている構成で、AWS-ApplyAnsiblePlaybooksドキュメントを実行する方法について取り上げます。以下の2つのパターンをご紹介します。
- NATゲートウェイを使用するパターン
- VPCエンドポイントを使用するパターン
構築する環境
EC2インスタンス①はNATゲートウェイを経由してAnsibleを実行するパターンです。EC2インスタンス②はVPCエンドポイントを経由してAnsibleを実行するパターンです。両インスタンスで実行するPlaybookは共通で、S3バケットに設置します。Playbookの内容ですが、Apacheをインストールし、動作させるものとします。
CloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。以下のURLにCloudFormationテンプレートを配置してます。
https://github.com/awstut-an-r/awstut-fa/tree/main/025
テンプレートファイルのポイント解説
本ページでは、AWS-ApplyAnsiblePlaybooksドキュメント関係のリソースのみ解説します。AWS-ApplyAnsiblePlaybooksドキュメント実行に関する基本的な事項や、NATゲートウェイ用の設定、プライベートサブネット内でyumを実行する方法については、以下のページをご確認ください。
AWS-ApplyAnsiblePlaybooksドキュメント実行①(NATゲートウェイ経由)
まずNATゲートウェイ経由でAWS-ApplyAnsiblePlaybooksドキュメントを実行するための設定を確認します。fa-025-ssm.yamlでSSM関係のリソースを定義しています。
Resources:
ApplyAnsiblePlaybooksAssociation1:
Type: AWS::SSM::Association
DependsOn:
- RunShellScriptAssociation
Properties:
AssociationName: !Sub ${Prefix}-apply-ansible-playbook-association1
Name: AWS-ApplyAnsiblePlaybooks
OutputLocation:
S3Location:
OutputS3BucketName: !Ref PlaybookBucket
OutputS3KeyPrefix: !Sub "${Prefix}/playbook-association-log"
Parameters:
Check:
- "False"
ExtraVariables:
- SSM=True
InstallDependencies:
- "True"
PlaybookFile:
- !Ref PlaybookFileName
SourceInfo:
- !Sub '{"path": "https://${PlaybookBucket}.s3.${AWS::Region}.amazonaws.com/${Prefix}/${PlaybookPackageName}"}'
SourceType:
- S3
Verbose:
- -v
Targets:
- Key: InstanceIds
Values:
- !Ref Instance1
WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)
先述のパブリックサブネットにインスタンスが設置されている場合の設定と同様です。今回はプライベートサブネット内にインスタンスは設置されていますが、NATゲートウェイを経由して、インターネットにアクセス可能であるため、パブリックサブネットの場合と同様の設定で動作します。
今回の構成において、特に注目な設定は、InstallDependenciesプロパティです。このオプションはAWS-ApplyAnsiblePlaybooksドキュメントを実行する上で、依存関係にあるパッケージをインストールするためのオプションです。そもそもデフォルトのAmazon Linux 2では、Ansibleはインストールされていません。ですから本オプションを有効化し、ドキュメント実行時にAnsibleをインストールさせます。
AWS-ApplyAnsiblePlaybooksドキュメント実行②(VPCエンドポイント経由)
続いてVPCエンドポイント経由でAWS-ApplyAnsiblePlaybooksドキュメントを実行するための設定を確認します。今回は以下の2つのリソースを作成します。
- AWS-RunShellScript:Ansibleをインストールするために実行する。
- AWS-ApplyAnsiblePlaybooks:Ansible Playbookの内容を実行する。
処理を2つのドキュメントに分けて定義した理由は、インスタンスがプライベートサブネットに設置されているため、先述のオプションを使ってでは、正常にAnsibleをインストールすることができないためです。これはインスタンスがプライベートサブネット上にあるため、インターネット向けに自由な通信ができないことに起因します。その事象のワークアラウンドとして、先にAWS-RunShellScriptドキュメントでAnsibleをインストールした後に、AWS-ApplyAnsiblePlaybooksドキュメントを実行することで対処します。
AWS-RunShellScript
Resources:
RunShellScriptAssociation:
Type: AWS::SSM::Association
Properties:
AssociationName: !Sub ${Prefix}-run-shellscript-association
Name: AWS-RunShellScript
OutputLocation:
S3Location:
OutputS3BucketName: !Ref PlaybookBucket
OutputS3KeyPrefix: !Sub "${Prefix}/shellscript-association-log"
Parameters:
commands:
- "sudo amazon-linux-extras install -y ansible2"
Targets:
- Key: InstanceIds
Values:
- !Ref Instance2
WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)
commandsプロパティでAnsibleインストール用コマンドを実行します。今回はAmazon Linux Extrasを使用してインストールします。
Extras は、安定したオペレーティングシステムで新しいバージョンのアプリケーションソフトウェアを利用可能にする Amazon Linux 2 のメカニズムで、2023 年 6 月 30 日までサポートされます。 (中略) Extras の例には、Ansible 2.4.2、memcached 1.5、nginx 1.12、Postgresql 9.6、MariaDB 10.2、Go 1.9、Redis 4.0、R 3.4、Rust 1.22.1 などがあります。
Amazon Linux Extras
AWS-ApplyAnsiblePlaybooks
Resources:
ApplyAnsiblePlaybooksAssociation2:
Type: AWS::SSM::Association
DependsOn:
- RunShellScriptAssociation
Properties:
AssociationName: !Sub ${Prefix}-apply-ansible-playbook-association2
Name: AWS-ApplyAnsiblePlaybooks
OutputLocation:
S3Location:
OutputS3BucketName: !Ref PlaybookBucket
OutputS3KeyPrefix: !Sub "${Prefix}/playbook-association-log"
Parameters:
Check:
- "False"
ExtraVariables:
- SSM=True
InstallDependencies:
#- "True"
- "False"
PlaybookFile:
- !Ref PlaybookFileName
SourceInfo:
- !Sub '{"path": "https://${PlaybookBucket}.s3.${AWS::Region}.amazonaws.com/${Prefix}/${PlaybookPackageName}"}'
SourceType:
- S3
Verbose:
- -v
Targets:
- Key: InstanceIds
Values:
- !Ref Instance2
WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)
InstallDependenciesプロパティに注目してください。「False」を指定します。これは既にAWS-RunShellScriptドキュメントを実行してAnsibleをインストールしているため、依存関係の解決を図る必要がないためです。
(参考) Ansible Playbook
参考までに、今回実行するPlaybookの中身をご紹介します。
- hosts: all
gather_facts: no
become: yes
tasks:
- name: update yum
yum: name=*
- name: install the latest version of Apache
yum: name=httpd state=latest
- name: start and enable Apache
service: name=httpd state=started enabled=yes
- name: make index.html
shell: ec2-metadata -i > /var/www/html/index.html
Code language: YAML (yaml)
Apacheをインストール後、インスタンスIDをindex.htmlに書き込むという内容です。今回はこの1つのPlaybookに、NATゲートウェイ経由と、VPCエンドポイント経由でアクセスして実行することになります。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
Ansible Playbookの準備
CloudFormationスタックを作成する前に、Ansibleの準備を行います。具体的にはPlaybookをZip化し、S3バケットに設置します。具体的なコマンドは先述のページをご確認ください。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- Instance1:i-0a2d78121ee6dfd1f
- Instance2:i-057dde56603eebcf4
AWS Management Consoleからも、リソースの作成状況を確認します。まずEC2インスタンスを確認します。
2つのインスタンスが作成されていることがわかります。次にSSM State ManagerでSSMドキュメントの実行状況を確認します。
2つのインスタンスに対して、合計3つの関連付けが作成されています。Statusが「Success」とありますので、正常に実行されたことがわかります。
動作確認①
準備が整いましので、インスタンスにアクセスします。まずインスタンス①です。インスタンスへのアクセスはSSM Session Managerを使用します。詳細については以下のページをご確認ください。
% aws ssm start-session --target i-0a2d78121ee6dfd1f
Starting session with SessionId: root-0f62c0c5edc7d8e07
sh-4.2$
Code language: Bash (bash)
curlで自分自身にアクセスします。
sh-4.2$ curl http://localhost
instance-id: i-0a2d78121ee6dfd1f
Code language: Bash (bash)
自分のIDが返ってきました。Ansible Playbookの内容が正常に実行されてたことがわかります。
参考に、以下がPlaybook実行時のログの抜粋です。
Amazon Linux release 2 (Karoo)
...
Installed:
epel-release.noarch 0:7-14
...
Installed:
ansible.noarch 0:2.9.27-1.el7
...
PLAY [all] *********************************************************************
TASK [update yum] **************************************************************
...
TASK [install the latest version of Apache] ************************************
...
TASK [start and enable Apache] *************************************************
...
TASK [make index.html] *********************************************************
...
PLAY RECAP *********************************************************************
localhost : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Code language: plaintext (plaintext)
Playbookの内容を実行する前に、依存関係を解決するために、Ansibleをインストールしていることがわかります。
動作確認②
次にインスタンス②です。
% aws ssm start-session --target i-057dde56603eebcf4
Starting session with SessionId: root-083a1d2a50de3e64a
sh-4.2$
sh-4.2$ curl http://localhost
instance-id: i-057dde56603eebcf4
Code language: Bash (bash)
こちらも自身のIDが返ってきましたので、Ansible Playbookの内容が正常に実行されてたことがわかります。
こちらも実行時のログを確認します。まずAWS-RunShellScriptのログです。
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
...
Installed:
ansible.noarch 0:2.9.23-1.amzn2
...
Complete!
Code language: plaintext (plaintext)
テンプレートファイルで指定した通り、Ansibleをインストールしています。次にAWS-ApplyAnsiblePlaybooksのログです。
PLAY [all] *********************************************************************
TASK [update yum] **************************************************************
...
TASK [install the latest version of Apache] ************************************
...
TASK [start and enable Apache] *************************************************
...
TASK [make index.html] *********************************************************
...
PLAY RECAP *********************************************************************
localhost : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Code language: plaintext (plaintext)
こちらはAnsibleはインストールせず、最初からPlaybookを実行しています。
まとめ
プライベートサブネット内でAWS-ApplyAnsiblePlaybooksドキュメントを実行する方法を確認しました。具体的には、NATゲートウェイか、あるいはVPCエンドポイントを使用しました。