AWS SSM を使って、Thor タスクを実行する

AWS SSM を使って、Thor タスクを実行する

id:eitoball です。Misoca では、減量ブームでそれに乗っかろうとしましたが、一生懸命、筋トレをしたためか、体重が増えてしまい途方に暮れているこのごろです。

先月、id:dominion525 に誘われて、AWS Summit Tokyo 2017 に1日だけ参加してきました。それ以来、AWS の様々なサービスに興味を持つようになっています。

Slackの発言

というのを見かけたので、少し早い夏の自由研究として、AWS SSM(EC2 System Manager)で、Run Command という機能を使って、EC2 インスタンスにログインすることなく、Rails アプリケーションの Thor タスクを実行するようにしてみました。

実行までの流れ

今回は、AWS SSM の Run Command を使って、特定のEC2インスタンスに対して、決められた Thor タスクを実行するようにします。Rails アプリケーションが動作する EC2 インスタンスを1つ準備して以下のような流れを実施しました。

  1. EC2インスタンスの設定
  2. ユーザーの作成・ロールの付与
  3. System Manager ドキュメントの作成・登録
  4. RunCommand によるタスクの実行・結果の閲覧

    1. EC2 インスタンスの設定

まず、EC2インスタンスに割り当てられている IAM ロールに「AmazonEC2RoleForSSM」というポリシーを付与します。インスタンスに IAM ロールが割り当てられていない場合は、新たにロールを作成して、割り当てて下さい。詳しくは、AWS EC2 のドキュメントなどを参考にして下さい。 そして、インスタンスに SSM エージェントをインストールします。Ubuntu 16.04 LTS (64 bit)の場合だと以下のようになります。他のOS等のインストール方法については、ドキュメントに記載されています。

$ curl -L -O https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb
$ sudo dpkg -i amazon-ssm-agent.deb
$ sudo systemctl enable amazon-ssm-agent

2. ユーザーの作成・ロールの付与

特定のインスタンスに対してのみタスクを実行するためだけのユーザーを作成します。今回は、作成したユーザーに以下のようなポリシーを直接、付与しました。「i-12345abcde67890fg」は、今回、使用している EC2 インスタンスのIDです。「RunThorTask」は、次のステップで作成する System Manager ドキュメントの名前です。ssm:SendCommand などを許可する場合、 System Manager ドキュメントと実行する EC2 インスタンスの両方を Resource に含める必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:ListCommandInvocations",
                "ssm:GetCommandInvocation",
            ],
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:*:instance/i-12345abcde67890fg",
                "arn:aws:ssm:ap-northeast-1:*:*",
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ssm:SendCommand",
                "ssm:DescribeDocument",
                "ssm:GetDocument"
            ],
            "Resource": [
                "arn:aws:ec2:ap-northeast-1:*:instance/i-12345abcde67890fg",
                "arn:aws:ssm:ap-northeast-1:*:document/RunThorTask"
            ]
        }
    ]
}

3. System Manager ドキュメントの作成・登録

特定の Thor タスクを実行するための コマンドの System Manager ドキュメントを作成します。今回は、あるユーザー(john.doe)が、 RVM(Ruby Version Manager)を使って、実行することとしています。Rails アプリケーションは、/var/www/vhosts/www.example.com/current にインストールされているとしています。 下記のような JSON ファイル(document.json)を作成します。今回は、allowedValues で、実行することのできる Thor タスクを listhelpversion の3つに制限しています。

{
    "schemaVersion": "2.0",
    "description": "Thor タスクを実行します。",
    "parameters": {
      "action": {
        "description": "Thor タスクを実行します。",
        "type": "String",
        "allowedValues": [
          "list",
          "help",
          "version"
        ]
      }
    },
    "mainSteps": [
      {
        "action": "aws:runShellScript",
        "name": "runThorTask",
        "inputs": {
          "runCommand": ["sudo -u john.doe /bin/bash -l -c \"source /home/john.doe/.rvm/scripts/rvm && rvm use . && RAILS_ENV=production bundle exec thor {{ action }}\""],
          "workingDirectory": "/var/www/vhosts/www.example.com/current"
        }
      }
    ]
}

作成したドキュメントを AWS CLI を使って登録します。

$ aws ssm create-document --content "file://document.json" --name "RunThorTask" --document-type "Command"

4. RunCommand によるタスクの実行・結果の閲覧

全ステップで登録した System Manager ドキュメントを使って、タスクを実行します。

$ aws ssm send-command --document-name "RunThorTask" --instance-ids "i-12345abcde67890fg" --parameters '{"action":["list"]}' --region ap-northeast-1

上記のコマンドを実行するとJSONが出力されます。結果の閲覧に必要な CommandId 以外は、省略しています。

{
    "Command": {
        "CommandId": "abcd1234-ab12-ab12-ab12-abcdef123456",
    }
}

CommandId を使って、実行結果を確認します。

$ aws ssm get-command-invocation --command-id "abcd1234-ab12-ab12-ab12-abcdef123456" --instance-id "i-12345abcde67890fg"

実行が成功している場合、以下のような結果が出力されます。

{
    "Comment": "",
    "ExecutionElapsedTime": "PT11.275S",
    "ExecutionEndDateTime": "2017-07-01T00:00:00.000Z",
    "StandardErrorContent": "",
    "InstanceId": "i-12345abcde67890fg",
    "StandardErrorUrl": "",
    "DocumentName": "RunThorTask",
    "StandardOutputContent": "...",
    "Status": "Success",
    "StatusDetails": "Success",
    "PluginName": "runThorTask",
    "ResponseCode": 0,
    "ExecutionStartDateTime": "2017-07-01T00:00:00.000Z",
    "CommandId": "abcd1234-ab12-ab12-ab12-abcdef123456",
    "StandardOutputUrl": ""
}

感想

  • EC2 System Manager で、色々なコマンドをログインしないで実行できるのは便利だと思います。また、IAM を使って、細かい実行権限の管理ができそうなのも便利だと思います。
  • 今回は使いませんでしたが、System Manager ドキュメントの作成には、 rezept を使ってみるのもいいなぁと思いました。

    採用

Misoca では、AWS の様々なサービスの活用に興味あるエンジニアも募集しています。