GitHub上のAnsiblePlaybookをSystems Managerで実行する
はじめに
中山(順)です
以前、弊社の大栗より、「EC2の管理を行えるSystems ManagerでgithubやS3に配置したファイルをローカルにダウンロードして実行することが可能になりました。」という内容をご紹介しました。
今回、これを応用してGitHub上のAnsiblePlaybookをEC2インスタンス上で実行させてみました。
おさらい
"AWS-RunRemoteScript"でやっていることは、以下の2つです。
- コンテンツ(スクリプトなど)のダウンロード
- コマンドの実行
やってみた
これを使用して、以下の処理を実行します。
- 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は以下のコマンドでインストールしました。
1 | sudo pip install ansible |
Playbookの作成
今回は、以下のタスクを実行するだけの簡単なPlaybookを作成します。
- yum update
- httpdのインストールおよび起動
その際、それぞれを別のロールで定義します。
Playbookは以下の手順で作成しました。
- GitHubにリポジトリーを作成
- 作業環境にリポジトリーをクローン
- ディレクトリの作成
- Playbookの作成
- GitHubにリポジトリーをプッシュ
GitHubにリポジトリーを作成
GitHubにリポジトリを作成します。
以降の手順で作成されるPlaybookはこちらにありますので、ご参考までに。
nakayamanobuhiro/example-ansible-playbook-ssm
作業環境にリポジトリーをクローン
作業用ディレクトリを作成します。
1 2 | mkdir ~/tmp_deviocd ~/tmp_devio |
リポジトリーをクローンします
1 2 | cd ./example-ansible-playbook-ssm |
ディレクトリの作成
ロールを配置するディレクトリを作成します。
今回はansible-galaxyコマンドを利用してディレクトリと(空の)ファイルを作成します。(地味に便利)
1 2 3 4 5 6 | mkdir ./rolesansible-galaxy init --init-path=roles commonansible-galaxy init --init-path=roles webls -R |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | .: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のファイル名を指定します。
1 | FILE_NAME_TOP="playbook.yml" |
Playbookを生成します。
リモートホストで実行することも想定し、hosts: allとします。
(Playbookを実行する際に、ansible-playbook -i "localhost," -c local playbook.ymlのように実行します。)
1 2 3 4 5 6 7 8 9 10 11 | cat << EOF > ${FILE_NAME_TOP}---- name: httpd hosts: all remote_user: ec2-user become: yes roles: - common - webEOF |
yum updateを実行するためのPlaybookを作成します。
1 2 3 4 5 6 7 8 9 | FILE_NAME_COMMON="./roles/common/tasks/main.yml"cat << EOF > ${FILE_NAME_COMMON}---- name: upgrade all packages yum: name: '*' state: latestEOF |
httpdをインストールするためのPlaybookを作成します。
1 2 3 4 5 6 7 8 9 10 | 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=yesEOF |
GitHubにリポジトリーをプッシュ
リポジトリーにPlaybookをプッシュします。
1 2 3 | 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で暗号化して保存し、それを参照することも可能です。
1 2 3 4 5 6 7 | 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} |
1 | {"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を実行してみます。
1 2 3 4 | aws ssm send-command \ --document-name "AWS-RunRemoteScript" \ --instance-ids ${INSTANCE_ID} \ --parameters "${PARAMETERS}" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | { "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のステータスを確認します。
以下のように、成功していることを確認できました。
1 2 3 | aws ssm list-command-invocations \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { "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"ドキュメントに含まれるプラグイン名を確認します。
1 2 3 4 5 | aws ssm get-document \ --name AWS-RunRemoteScript \ --query "Content" \ --output text \ | jq -r .mainSteps[].name |
1 2 3 | downloadContentrunPowerShellScriptrunShellScript |
"runPowerShellScript"はLinux上ではスキップされるようにドキュメントが定義されているので、"downloadContent"および"runShellScript"のログを確認します。
まずは、"downloadContent"を確認します。
1 2 3 4 5 6 | aws ssm get-command-invocation \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID} \ --plugin-name downloadContent \ --query "StandardOutputContent" \ --output text |
1 | Content downloaded to /var/lib/amazon/ssm/i-097a8923a6beb618a/document/orchestration/4da78de8-5287-408d-8bd3-d7ab1a5411c4/downloads/ |
次に、"runShellScript"を確認します。
1 2 3 4 5 6 | aws ssm get-command-invocation \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID} \ --plugin-name runShellScript \ --query "StandardOutputContent" \ --output text |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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が取得できることが確認できました。
1 | curl xx.xx.xx.xx | head |
1 2 3 4 5 6 7 8 9 10 11 12 13 | % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 3839 100 3839 0 0 159k 0 --:--:-- --:--:-- --:--:-- 163k<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Test Page for the Apache HTTP Server on Amazon Linux AMI</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style type="text/css"> /*<![CDATA[*/ body { background-color: #fff; |
留意事項
この記事を作成するにあたり、何度かGitHubからのPlaybookダウンロード時にエラーが発生しました。
リクエスト数の上限に抵触するものでした。
お試しの際にはお気をつけください。
まとめ
このように、gitで管理されたAnsible PlaybookをSystems Managerを使って実行してみました。
Systems Managerを利用することで簡単に作業の証跡を残せますし、ドキュメントを独自に作成してより使いやすくすることもできると思います。
「おっ!」と思った方は是非試してみてください。