Udemyブラックフライデーセール開催中(11/29まで)教材が1,300円~

AWSboto3 RunCommandでEC2にシェルコマンドを実行する

AWSboto3 RunCommandでEC2にシェルコマンドを実行するアイキャッチ

AWS SystemsManager(SSM)のRun Commandを使用するとEC2にSSH接続しなくてもシェルコマンドを実行することができます。今回はboto3(Python)から実行してみたので設定手順とサンプルコマンドを紹介します。

Run Commandのアーキテクチャ図
Run Commandでできること
目次

結論(設定手順)

  1. EC2にSystemsManager(SSM)の権限をロールで付与する
  2. EC2のSystemsManagerエージェントを更新する(大体のEC2には初期インストールされているので更新のみ)
  3. boto3のsend_commandでRun Commandを実行する

次章から順を追って説明します。

準備 EC2にロールを設定する

EC2でRun Commandを実行するにはEC2にIAMロールをアタッチする必要があります。

IAMロールの作成

IAMコンソールからロールを作成します。EC2で使用するのでEC2にチェックを入れます。

マネジメントコンソールからIAMロールを作成する画面

次の画面でAWS管理ポリシーのAmazonEC2RoleforSSMを選択します。

マネジメントコンソールからIAMロールにポリシーをアタッチする画面

適当な名前を付けてロールを作成します。筆者はポリシーと同じ名前「AmazonEC2RoleforSSM」にしました。

IAMロールに名前を付ける

作成したポリシーをEC2にアタッチする

EC2のコンソールに移動し、対象のEC2にIAMロールをアタッチします。

マネジメントコンソールでIAMロールをEC2にアタッチする画面

ロールは先ほど作成したロールを選択します。

マネジメントコンソールでIAMロールをEC2にアタッチする画面

準備 EC2のSystemsManagerエージェントをアップデートする

SystemsManagerエージェントのアップデートもSystemsManager Run Commandで実行できます。
コンソールでSystemsManagerを開き、Run Commandを選択します。右上のRun commandを選択します。

マネジメントコンソールからSystemsManagerエージェントを更新する画面

フィルタにAWS-UpdateSSMAgentを入力し、AWS-UpdateSSMAgentを選択します。

マネジメントコンソールのコマンド実行画面

対象のEC2インスタンスを選択します。ここに出てこない場合はロールの設定が正しく実施されていない可能性があります。

ロールをアタッチしてもインスタンスの表示がすぐにはされないことがあります。そんな時はロールをアタッチ後にEC2インスタンスを再起動すると認識されることがあるようです。
また、EC2からのアウトバウンド通信が制限されているとインスタンスが表示されないことがあります。その際は外部サイトですが、こちらの記事が参考になります。

コマンド実行対象のEC2を選択する画面

他の項目はそのままでOKです。実行ボタンを押下します。

実行ボタンを押下する

少し待って更新すると成功します。

マネジメントコンソールで成功していることを確認する

boto3でRun Commandを実行する

実行ユーザの権限設定

Lambdaから実行する場合はLambdaロールの設定、ローカルから実行する場合はアクセスキーのユーザの権限を設定します。AdministratorAccessポリシーをアタッチしている場合は動作しますが、最低限SystemsManager Run Commandの権限とS3のPut権限は必要です。

S3の権限が必要なのはRun Commandの実行結果ログをS3バケットにPUTするからです。S3への実行結果配信が不要な場合はS3への権限とsend_commandへのS3関連の引数(OutputS3XXX)も不要です。


筆者動作確認ではAmazonS3FullAccessAmazonSSMFullAccessのポリシーをアタッチしたIAMユーザのアクセスキーを使ってプログラムを実行しました。(AWSのベストプラクティス的にはフルアクセスではなく、権限を絞ったほうが良いかと思いますが、ご容赦ください。)

2023/04追加 RunCommandに関しては以下の権限(IAMポリシー)で実行することができました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ssm:ListCommands",
                "ssm:SendCommand",
                "ssm:ListCommandInvocations"
            ],
            "Resource": "*"
        }
    ]
}

サンプルプログラムと実行

以下のようなプログラムでRun Commandを実行できます。冒頭4-7行目のインスタンスIDやS3情報は各々書き換えてください。
また、実行したいコマンドをcommandsの配列に記入してください。(17-19行目)サンプルコードでは適当にmariaDBの再起動とpwdコマンドとpsコマンドを実行しています。

import boto3
import time
# インスタンスIDやバケットの情報は各自書き換える。
instance_id = "i-xxxxxxxxxxxxx"
outputs3_region='ap-northeast-1'
outputs3_bucketname='S3buketname'
outputs3_keyprefix='keyprefix'

ssm = boto3.client('ssm')

# Run Command実行
response = ssm.send_command(
    InstanceIds = [instance_id],
    DocumentName = "AWS-RunShellScript",
    Parameters = {
        "commands": [
            "sudo systemctl restart mariadb", 
            "pwd",
            "ps"
        ]    
    },
    OutputS3Region = outputs3_region,
    OutputS3BucketName = outputs3_bucketname,
    OutputS3KeyPrefix = outputs3_keyprefix
)

# 処理待ち
time.sleep(5)

# Run Command実行結果からCommandId取得
command_id = response['Command']['CommandId']

# CommandIdからコマンドの実行結果取得
response = ssm.list_command_invocations(
    CommandId = command_id,
    Details = True
)

# 実行結果出力
print(response['CommandInvocations'][0]['Status'])
# 実行結果からコンソール出力をprint
print(response['CommandInvocations'][0]['CommandPlugins'][0]['Output'])

サンプルコマンドをそのまま実行すると以下のようにpwdの結果とpsコマンドの結果が返ります。(mariaDBの再起動はコンソール出力されないので出ていません。)

PS C:\Users\User\work\python> python3 .\runcommandTest.py
Success
/usr/bin
  PID TTY          TIME CMD
    1 ?        00:00:03 systemd
以下略

解説

boto3のsend_commandを使ってRun Command実行し、実行結果をlist_command_invocationsで取得しています。

以下はsend_commandでRun CommandでAWS-RunShellScriptドキュメントを実行している個所です。ドキュメントの引数に実行したいコマンドを指定できます。S3情報(OutputS3Region、OutputS3BucketName、OutputS3KeyPrefix)を指定することで出力をS3に格納することができます。

# Run Command実行
response = ssm.send_command(
    InstanceIds = [instance_id],
    DocumentName = "AWS-RunShellScript",
    Parameters = {
        "commands": [
            "sudo systemctl restart mariadb", 
            "pwd",
            "ps"
        ]    
    },
    OutputS3Region = outputs3_region,
    OutputS3BucketName = outputs3_bucketname,
    OutputS3KeyPrefix = outputs3_keyprefix
)

マネジメントコンソールからAWS-RunShellScriptを実行する際はコマンドのパラメータとしてシェルコマンドを実行できますが、boto3ではcommandsに配列で渡すイメージになります。

マネジメントコンソールでRun Commandを実行する画面


以下は実行したコマンドの実行結果を取得しています。

response = ssm.list_command_invocations(
    CommandId = command_id,
    Details = True
)

# 実行結果出力
print(response['CommandInvocations'][0]['Status'])

response[‘CommandInvocations’][0][‘Status’]には成功(Success)や失敗(Failed)が入ります。sleepが短すぎる場合は実行中(InProgress)が表示されたりします。
他にもステータスがありますが詳しくはlist_command_invocationsドキュメントをご確認ください。

AWS公式ドキュメントのStatusの種類についての説明
Statusの種類

さいごに(感想)

EC2を使用するシステムではRun Commandを用いることでソフトの更新やプロセスの修復、再起動もできて便利だと感じました。よくある外形監視プログラムで異常があったらEC2に入って特定のコマンドを実行するといった今まで人が行っていたことを自動化できそう。今後Run Commandの応用例も記事にできたらと思います。

PR
当ブログはWordPressテーマSWELLを使用しています。非常に使いやすく、簡単にプロのようなデザインを使えるのでお勧めです!!

SWELL – シンプル美と機能性両立を両立させた、圧巻のWordPressテーマ

ランキング

ランキングに参加しています。クリックして応援いただけると嬉しいです。
にほんブログ村 IT技術ブログ クラウドコンピューティングへ
にほんブログ村
AWSランキング
AWSランキング

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次