Closed4

CommandRunner を触ってみる

5hintaro5hintaro

これいいんじゃない?

CDK とか serverless framework とかでだいぶ CloudFormation もデプロイが簡単になってきた昨今、個人的に嬉しい機能が CloudFormation でできるようになっていました。

それが CommandRunner です。

正式な機能ではないため、サポートされていませんが、CloudFormation のデプロイ前後にBashコマンドを実行することができます。なので例えば、CloudFormationのデプロイ後に Lambda を実行したいといったニーズに答えてくれます。

ちなみに仕組みは Amazon Linux 2 を動かしているだけなので、コマンドの自由度は高いです。なお、Lambdaじゃない理由は、Lambda が Bash の使用をネイティブにサポートしていないからだそうです。

5hintaro5hintaro

実際に使ってみる

Install

git clone https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner.git
cd aws-cloudformation-resource-providers-awsutilities-commandrunner
curl -LO https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner/releases/latest/download/awsutility-cloudformation-commandrunner.zip
./scripts/register.sh --set-default

Github に記載の通りに上記コマンドを実行します。

--set-default こちらのオプションの部分で、AWS CLIのユーザーを指定しています。なおこのスクリプト、AWS SSOユーザーには対応していなかったので、CommandRunner用のIAMユーザーを用意してもいいのかもしれません(SSOユーザーとIAMユーザーは、/.aws ディレクトリ配下にある認証情報の場所が違うことが原因かと思います)。

このスクリプトを実行すると、CommandRunner に必要なIAMロールが作成されます。

そのあとに CommandRunner が利用する ec2.amazonaws.com を信頼関係としたIAMロールを作成します。このIAMロールは CommandRunner が立ち上げたEC2インスタンスにて使用されるロールのため、テンプレートのロール部分にはこちらのARNを記載します。

なおこの IAMロール には以下のポリシーが必要です。

"logs:CreateLogStream",
"logs:CreateLogGroup",
"logs:PutLogEvents"

これで準備完了です。

実際に使ってみる

Serverless Framework を使ってデプロイしてみました。

service: commandrunner-demo
frameworkVersion: '2'

provider:
  name: aws
  region: ap-northeast-1

resources:
  Resources:
    MySNSTopic:
      # リソースの前にコマンドを実行する場合はここに DependsOn を追記する
      # DependsOn: Command  
      Type: AWS::SNS::Topic
      Properties:
        TopicName: "SampleTopic"

    Command:
      # リソースの後にコマンドを実行する場合はここに DependsOn を追記する
      # DependsOn: MySNSTopic  
      Type: AWSUtility::CloudFormation::CommandRunner
      Properties:
        Command: 'aws sns list-topics --region ap-northeast-1 > /command-output.txt'
        Role: arn:aws:iam::${AWS_ACCOUNT_ID}:role/CommandRunnerRole

  Outputs:
      Output:
          Description: The output of the CommandRunner.
          Value: !GetAtt Command.Output

Role の部分はインストール時にデプロイされたIAMロールを使用してください。

実際に sls deploy コマンドを実行してデプロイすると、CommandRunnerが実行されます。

以下、わかったことや特徴をまとめています。

  • AWS CLIコマンドの実行は --region オプションを使用してください。S3のようなグローバルサービスはなくてもいいです。
  • ロググループやサブネット、セキュリティグループがオプションで指定することができます。
  • デプロイしたスタックとは別に、CommandRunner用のスタックが起動します。
  • CommandRunner用のスタックは、EC2作ったりいろいろしたりしているので1行のコマンドでも実行完了までが長い。
  • サブネットを指定しなければ、デフォルトのVPCにEC2が使用されます。
  • サブネットを指定する場合は、セキュリティグループも指定しなければなりません。

Output

Resources:
  Command:
    Type: AWSUtility::CloudFormation::CommandRunner
    Properties:
      Command: aws s3 ls > /command-output.txt
      Role: String

Outputs:
    Output:
        Description: The output of the CommandRunner.
        Value: !GetAtt Command.Output

コマンドの結果は、上記のように /command-output.txt を出力先にすることで、CloudFormation の出力部分に残すことができます。

5hintaro5hintaro

上記のやつをデプロイしてみると、なぜか以下のエラーが出ます。

WaitCondition timed out. Received 0 conditions when expecting 1

CommandRunner がEC2を作成できていないみたいです。なぜでしょうか。

このスクラップは2022/01/15にクローズされました