/dev/null

脳みそのL1キャッシュ

Lambda 関数から ECS Task を起動する

プロジェクト構造

成果物は https://github.com/d2verb/lambda-golang-terraform/tree/run-ecs-task にあります。前回の記事のものをベースに使っています。AWS リソースは Terraform で管理しています。

$ tree .
.
├── ecs.tf
├── golang
│   ├── artifacts
│   │   ├── sample.exe
│   │   └── sample.zip
│   └── src
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── lambda.tf
├── provider.tf
└── terraform.tfstate

RunTask する

AWSAPI には RunTask というものがあります。今回はこの API を Lambda 関数から叩いて ECS Task を実行します。

func HandleRequest() error {
    awsConfig, err := config.LoadDefaultConfig(context.TODO())
    if err != nil {
        return err
    }

    client := ecs.NewFromConfig(awsConfig)

    var count int32 = 1
    cluster := "sample-cluster"
    taskDef := "sample"
    containerName := "sample"

    _, err = client.RunTask(
        context.TODO(),
        &ecs.RunTaskInput{
            Cluster:        &cluster,
            TaskDefinition: &taskDef,
            Count:          &count,
            LaunchType:     ecsTypes.LaunchTypeFargate,
            NetworkConfiguration: &ecsTypes.NetworkConfiguration{
                AwsvpcConfiguration: &ecsTypes.AwsVpcConfiguration{
                    Subnets:        []string{"subnet-02ad4be365c5f37f6"},
                    SecurityGroups: []string{"sg-0501b0a3793ddabc7"},
                    AssignPublicIp: ecsTypes.AssignPublicIpEnabled,
                },
            },
            Overrides: &ecsTypes.TaskOverride{
                ContainerOverrides: []ecsTypes.ContainerOverride{
                    ecsTypes.ContainerOverride{
                        Name: &containerName,
                    },
                },
            },
        },
    )

    if err != nil {
        fmt.Printf("ecs run task: error: %s\n", err.Error())
    } else {
        fmt.Println("ecs run task: ok")
    }

    return err
}

特筆すべきものはないのですが、前準備として

  • ECS Cluster
  • ECS Task Definition

を準備しておく必要があります。(ECS Service は必要ないです)

ポリシー周り

ここが重要です。作成した Lambda 関数から RunTask するためには以下のポリシーが必要です。

data "aws_iam_policy_document" "lambda" {
  statement {
    effect = "Allow"
    actions = [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "ecs:RunTask"
    ]
    resources = ["*"]
  }

  statement {
    effect = "Allow"
    actions = [
      "iam:PassRole",
    ]
    resources = ["*"]
    condition {
      test     = "StringLike"
      variable = "iam:PassedToService"
      values = [
        "ecs-tasks.amazonaws.com"
      ]
    }
  }
}

ecs:RunTask が必要なのはもちろんですが、iam:PassRole も必要です。ECS Task の実行には Execution Role が必要で、Lambda 側から ECS Task を生成し実行するには、Execution Role を渡してあげる必要があります。

Pass Role に関しては以下の資料を参考にしてください。

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html https://blog.rowanudell.com/iam-passrole-explained/

動作確認

terraform apply でリソースを作成して、マネジメントコンソールから Lambda 関数を叩きます。

ECS Cluster 側で Task が走っており、ログに以下が出力されていれば成功です。