この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
中山(順)です
以前、弊社の大栗より、「EC2の管理を行えるSystems ManagerでgithubやS3に配置したファイルをローカルにダウンロードして実行することが可能になりました。」という内容をご紹介しました。
今回、これを応用してGitHub上のAnsiblePlaybookをEC2インスタンス上で実行させてみました。
おさらい
"AWS-RunRemoteScript"でやっていることは、以下の2つです。
- コンテンツ(スクリプトなど)のダウンロード
- https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-downloadContent
- コマンドの実行
- (Windows) https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-runPowerShellScript
- (Linux) https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-runShellScript
やってみた
これを使用して、以下の処理を実行します。
- Ansible Playbook一式のダウンロード
- Ansible Playbookのローカル実行
手順は以下の公式ドキュメントにもあるので、適宜参照してください。
Run Ansible Playbooks from GitHub
事前準備
Systems Managerを利用するための準備作業および動作要件は、公式ドキュメントもしくは弊社ブログをご確認ください。
Setting Up AWS Systems Manager
EC2 Systems Manager – 特集カテゴリー –
前提条件
今回の検証は以下の前提のもとで実施します。
- 以下のようなのEC2インスタンスを用意
- Ansibleをインストール
- Public Subnetに配置
- Linuxインスタンス (Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type - ami-19910c7f) を利用
- Run Commandを実行できる必要最低限の権限をインスタンスに付与(インスタンスプロファイル)
Ansibleは以下のコマンドでインストールしました。
sudo pip install ansible
Playbookの作成
今回は、以下のタスクを実行するだけの簡単なPlaybookを作成します。
- yum update
- httpdのインストールおよび起動
その際、それぞれを別のロールで定義します。
Playbookは以下の手順で作成しました。
- GitHubにリポジトリーを作成
- 作業環境にリポジトリーをクローン
- ディレクトリの作成
- Playbookの作成
- GitHubにリポジトリーをプッシュ
GitHubにリポジトリーを作成
GitHubにリポジトリを作成します。
以降の手順で作成されるPlaybookはこちらにありますので、ご参考までに。
nakayamanobuhiro/example-ansible-playbook-ssm
作業環境にリポジトリーをクローン
作業用ディレクトリを作成します。
mkdir ~/tmp_devio
cd ~/tmp_devio
リポジトリーをクローンします
git clone https://github.com/nakayamanobuhiro/example-ansible-playbook-ssm.git
cd ./example-ansible-playbook-ssm
ディレクトリの作成
ロールを配置するディレクトリを作成します。 今回はansible-galaxyコマンドを利用してディレクトリと(空の)ファイルを作成します。(地味に便利)
mkdir ./roles
ansible-galaxy init --init-path=roles common
ansible-galaxy init --init-path=roles web
ls -R
.:
README.md roles
./roles:
common web
./roles/common:
README.md defaults files handlers meta tasks templates tests vars
./roles/common/defaults:
main.yml
./roles/common/files:
./roles/common/handlers:
main.yml
./roles/common/meta:
main.yml
./roles/common/tasks:
main.yml
./roles/common/templates:
./roles/common/tests:
inventory test.yml
./roles/common/vars:
main.yml
./roles/web:
README.md defaults files handlers meta tasks templates tests vars
./roles/web/defaults:
main.yml
./roles/web/files:
./roles/web/handlers:
main.yml
./roles/web/meta:
main.yml
./roles/web/tasks:
main.yml
./roles/web/templates:
./roles/web/tests:
inventory test.yml
./roles/web/vars:
main.yml
Playbookの作成
ansible-playbookコマンドを実行する際に指定するPlaybookのファイル名を指定します。
FILE_NAME_TOP="playbook.yml"
Playbookを生成します。
リモートホストで実行することも想定し、hosts: all
とします。
(Playbookを実行する際に、ansible-playbook -i "localhost," -c local playbook.yml
のように実行します。)
cat << EOF > ${FILE_NAME_TOP}
---
- name: httpd
hosts: all
remote_user: ec2-user
become: yes
roles:
- common
- web
EOF
yum updateを実行するためのPlaybookを作成します。
FILE_NAME_COMMON="./roles/common/tasks/main.yml"
cat << EOF > ${FILE_NAME_COMMON}
---
- name: upgrade all packages
yum:
name: '*'
state: latest
EOF
httpdをインストールするためのPlaybookを作成します。
FILE_NAME_WEB="./roles/web/tasks/main.yml"
cat << EOF > ${FILE_NAME_WEB}
---
- name: install the latest version of httpd
yum: name=httpd state=latest
- name: httpd service state
service: name=httpd state=started enabled=yes
EOF
GitHubにリポジトリーをプッシュ
リポジトリーにPlaybookをプッシュします。
git add .
git commit -m "First commit"
git push origin master
Playbookの実行
パラメーターの準備
"AWS-RunRemoteScript"ドキュメントを実行するにあたり、以下のパラメーターを決定する必要があります。
- 実行対象のインスタンスIDもしくはタグ
- 今回はインスタンスIDで対象を指定します
- owner
- リポジトリーのオーナー名
- repository
- リポジトリー名
- path
- ダウンロードしたいファイルもしくはディレクトリのパス
- 今回はリポジトリー上のファイルをすべて取得します
- getOptions
- ブランチ名もしくはコミットID
- 指定は任意(デフォルトはbranch:master,commitID:head)
プライベートリポジトリーを利用する場合は、これらに加えてtokenInfoにGitHubのアクセストークンを指定する必要があります。 パラメーターストアにKMSで暗号化して保存し、それを参照することも可能です。
INSTANCE_ID="i-0xxxxxxxxxxxxxxxx"
OWNER="nakayamanobuhiro"
REPOSITORY="example-ansible-playbook-ssm"
DOWNLOAD_PATH="/"
GET_OPTIONS="branch:master"
PARAMETERS="{\"sourceType\":[\"GitHub\"],\"sourceInfo\":[\"{\\\"owner\\\":\\\"${OWNER}\\\", \\\"repository\\\": \\\"${REPOSITORY}\\\", \\\"path\\\": \\\"${DOWNLOAD_PATH}\\\", \\\"getOptions\\\": \\\"${GET_OPTIONS}\\\"}\"],\"commandLine\":[\"ansible-playbook -i \\\"localhost,\\\" -c local playbook.yml\"]}" && echo ${PARAMETERS}
{"sourceType":["GitHub"],"sourceInfo":["{\"owner\":\"nakayamanobuhiro\", \"repository\": \"example-ansible-playbook-ssm\", \"path\": \"/\", \"getOptions\": \"branch:master\"}"],"commandLine":["ansible-playbook -i \"localhost,\" -c local playbook.yml"]}
Playbookの実行
Playbook(GitHubリポジトリー)とRunCommand実行時に必要なパラメーターが準備できました。 Ansibe Playbookを実行してみます。
aws ssm send-command \
--document-name "AWS-RunRemoteScript" \
--instance-ids ${INSTANCE_ID} \
--parameters "${PARAMETERS}"
{
"Command": {
"Comment": "",
"Status": "Pending",
"MaxErrors": "0",
"Parameters": {
"commandLine": [
"ansible-playbook -i \"localhost,\" -c local playbook.yml"
],
"sourceInfo": [
"{\"owner\":\"nakayamanobuhiro\", \"repository\": \"example-ansible-playbook-ssm\", \"path\": \"/\", \"getOptions\": \"branch:master\"}"
],
"sourceType": [
"GitHub"
]
},
"ExpiresAfter": 1515183224.362,
"ServiceRole": "",
"DocumentName": "AWS-RunRemoteScript",
"TargetCount": 1,
"OutputS3BucketName": "",
"NotificationConfig": {
"NotificationArn": "",
"NotificationEvents": [],
"NotificationType": ""
},
"CompletedCount": 0,
"Targets": [],
"StatusDetails": "Pending",
"ErrorCount": 0,
"OutputS3KeyPrefix": "",
"RequestedDateTime": 1515176024.362,
"CommandId": "4da78de8-5287-408d-8bd3-d7ab1a5411c4",
"InstanceIds": [
"i-097a8923a6beb618a"
],
"MaxConcurrency": "50"
}
}
動作確認
RunCommandの実行結果を確認します。 "AWS-RunRemoteScript"ドキュメントでは複数のプラグインが実行されるため、まずはlist-command-invocationsでRunCommandのステータスを確認します。 以下のように、成功していることを確認できました。
aws ssm list-command-invocations \
--command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \
--instance-id ${INSTANCE_ID}
{
"CommandInvocations": [
{
"Comment": "",
"Status": "Success",
"CommandPlugins": [],
"ServiceRole": "",
"InstanceId": "i-097a8923a6beb618a",
"DocumentName": "AWS-RunRemoteScript",
"NotificationConfig": {
"NotificationArn": "",
"NotificationEvents": [],
"NotificationType": ""
},
"StatusDetails": "Success",
"StandardOutputUrl": "",
"StandardErrorUrl": "",
"InstanceName": "",
"CommandId": "4da78de8-5287-408d-8bd3-d7ab1a5411c4",
"RequestedDateTime": 1515176024.547
}
]
}
RunCommandの実行ログを確認します。 まずは"AWS-RunRemoteScript"ドキュメントに含まれるプラグイン名を確認します。
aws ssm get-document \
--name AWS-RunRemoteScript \
--query "Content" \
--output text \
| jq -r .mainSteps[].name
downloadContent
runPowerShellScript
runShellScript
"runPowerShellScript"はLinux上ではスキップされるようにドキュメントが定義されているので、"downloadContent"および"runShellScript"のログを確認します。
まずは、"downloadContent"を確認します。
aws ssm get-command-invocation \
--command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \
--instance-id ${INSTANCE_ID} \
--plugin-name downloadContent \
--query "StandardOutputContent" \
--output text
Content downloaded to /var/lib/amazon/ssm/i-097a8923a6beb618a/document/orchestration/4da78de8-5287-408d-8bd3-d7ab1a5411c4/downloads/
次に、"runShellScript"を確認します。
aws ssm get-command-invocation \
--command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \
--instance-id ${INSTANCE_ID} \
--plugin-name runShellScript \
--query "StandardOutputContent" \
--output text
PLAY [nginx] *******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [common : upgrade all packages] *******************************************
ok: [localhost]
TASK [web : install the latest version of httpd] *******************************
changed: [localhost]
TASK [web : httpd service state] ***********************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0
意図したとおり機能しているかを確認します。 今回はhttpdをインストールしただけなので、デフォルトのコンテンツが表示されるか確認します。 以下の通り、httpdからTest Pageが取得できることが確認できました。
curl xx.xx.xx.xx | head
``` % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3839 100 3839 0 0 159k 0 --:--:-- --:--:-- --:--:-- 163k