CDK 引用 CommandRunner 執行 AWS CLI 指令

POSTED BY   Chris
2020 年 12 月 20 日
CDK 引用 CommandRunner 執行 AWS CLI 指令

不管使用 CDK 或用 CloudFormation,如果想要在生成某些 AWS Resources 後,接著執行與這些 Resources 相關的指令或一些自訂指令時,大都需要手動執行而無法並自動化,這篇文章推薦使用 AWSUtility::CloudFormation::CommandRunner 這個 CloudFormation Custom Resource Type,以下就讓我們來看怎麼使用

 

應用情境

沒有應用情境可能沒感覺,這邊舉一個最近完成的 npm package cdk-aws-codedeploy-on-premises

這個 CDK Construct 的目的,就是在 IDC(地端) 使用 AWS CodeDeploy 的情境,CDK Construct 可以完成建置 AWS CodeDeploy Application、CodeDeploy Deployment Group 和 Instance,以及產生相關需要 AWS IAM Role 和 User

但最後需要一個動作,必需用 CLI 執行 aws deploy register 去註冊 instance 後,才能運作正常 (或許之後 CloudFormation 會支援,但目前沒有),所以才會需要用到 CommandRunner

 

註冊 CommandRunner

註冊 CloudFormation 的 AWSUtility::CloudFormation::CommandRunner,在本地執行,或是用現在很潮的 CloudShell 來執行也可以,那執行身份需要有以下這些權限

  • s3:CreateBucket
  • s3:DeleteBucket
  • s3:PutBucketPolicy
  • s3:PutObject
  • cloudformation:RegisterType
  • cloudformation:DescribeTypeRegistration
  • iam:createRole

AWS CLI Credential 準備好沒問題後,就可以來開始註冊

1. git clone

git clone https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner.git

2. 進入 repo 目錄內

cd aws-cloudformation-resource-providers-awsutilities-commandrunner

3. 下載預先編譯好的套件包

curl -LO https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner/releases/latest/download/awsutility-cloudformation-commandrunner.zip

如果不下載,應該也可以自己執行 scripts/build.sh 來編譯

4. 執行註冊

./scripts/register.sh

過程中,macos 的 console 會跳成編輯模式,只要按 q 鍵就可以,最後看到以下訊息,表示成功

AWSUtility::CloudFormation::CommandRunner is ready to use.

也可以再到 AWS Console Mangement -> CloudFormation -> Registry,下拉選單選 Private,Resource Type 看到AWSUtility::CloudFormation::CommandRunner,表示一切就緒

這邊再提一下,註冊的動作成功後,會在 CloudFormation 後台看到 awsutility-cloudformation-commandrunner-execution-role-stack 這個 stack,切記不要刪掉,如果真的不小心刪到,請用反註冊的 script 如下

./scripts/cleanup.sh

之後反註冊完後,再執行一次註冊的動作,應該就能正常

 

運作方式

先來看個流程圖

Hint: 點圖片可放大

圖片來源: AWS Blog

 

從圖片很清楚可以看到,CommandRunner 是會自動開啟一台 EC2 (t3.micro),並指定 EC2 instance profile 去 assume role 來執行指令,執行指令之後再自動刪除 EC2,非常的方便,可以自動化一些 CloudFormation 還沒支援的項目,或是自訂的流程等等…

 

在 CDK 中引用 CommandRunner

CDK 非常厲害,不僅可以使用 imperative programming 的方式完成 AWS Infra 的建置,更可以完美的使用 CloudFormation Template,官方文件 Import or migrate an existing AWS CloudFormation template 已經說明很清楚,這邊引用 CommandRunner 來實作一次

這邊一樣用在應用情境中說明的 npm package 來做說明,Command Runner 的 CloudFormation template 如下

Parameters:
  CommandRole:
    Type: String
    Description: 'https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner#role'

  Command:
    Type: String
    Description: 'https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner#command'

Resources:
  Command:
    Type: 'AWSUtility::CloudFormation::CommandRunner'
    Properties:
      Command: !Ref Command
      Role: !Ref CommandRole

 

這個 template 使用很簡單的設計,把要執行的 command 和 執行這個 command 需要的權限角色帶進參數來使用

在 CDK 中,可以很輕鬆的這樣引用

addCommandRunner(): CfnResource {
  const runCommandRole = this.createRunCommandRole();

  const template = new cfn_inc.CfnInclude(this, 'AddCommandRunner', {
    templateFile: `${__dirname}/../template/command-runner.yml`,
    preserveLogicalIds: false,
    parameters: {
      CommandRole: runCommandRole.roleName,
      Command: this.commands,
    }
  });

  return template.getResource('Command') as CfnResource;
}

完整的程式碼在這裡

 

可以很簡單的指定 template 路徑、用參數帶入要執行的指令和 role ,一切就搞定了!使用起來很舒服

 

Troubleshooting

使用上也有踩到一點雷,這邊也提醒一下

  • Command 結尾一定要使用 > /command-output.txt

不使用這個結尾導出輸出到檔案 command-output.txt,deploy 時就會出現類似以下錯誤

1 validation error detected: Value '' at 'value' failed to satisfy constraint: Member must have length greater than or equal to 1. (Service: AWSSimpleSystemsManagement; Status Code: 400; Error Code: ValidationExcept
ion; Request ID: 35d8c36c-dbaa-4cff-a7cf-dcce65bd53e5)

原因大概就是 CommandRunner 把輸出儲存在 SSM parameter,所以才需要這個檔案

 

  • 注意 Role 的權限

如果執行的指令是操作 AWS 資源的相關指令,記得要給予 EC2 相關的權限,否則會造成部署失敗

以應用情境的例子,我需要這樣指定權限

inlinePolicies: {
  'EC2RunCommandRole': new iam.PolicyDocument({
    statements: [
      new iam.PolicyStatement({
        actions: ['codedeploy:RegisterOnPremisesInstance'],
        resources: ['*'],
      }),
    ],
  }),
},

這樣才能順利執行註冊 instance 的指令

歡迎留言
0

您可能也想看

Workaround for AWS Grafana alerting
2023 年 8 月 3 日
AWS, DevOps
AWS VPC Endpoint 使用場景
2022 年 3 月 14 日
AWS, CDK, Network
CDK 指定 Physical names 運作方式
2021 年 12 月 4 日
AWS, CDK, Cloudformation