6
4

More than 3 years have passed since last update.

ecsをデプロイする際にCodedeploy用のtaskdef.jsonをCodebuild内で生成する

Posted at

はじめに

最近CodePipelineを使ってecsのデプロイを自動化する仕事をしていました。
その中でCodeDeployを使用することになったのですが、
CodeDeployを使ってデプロイするためにはアプリケーションコードがあるリポジトリ内にtaskdef.jsonファイルを作成してそこにタスク定義を書く必要があります。

しかし、プロジェクトではterraformでインフラを管理していたため、タスク定義がterraformとアプリケーションコードの両方に存在しているのは避けたいと思い、Codebuild内でtaskdef.jsonを作成することにした。

概略

方法
1. ecsからtask定義を持ってきてそれをもとにtaskdef.jsonを作成するコマンドをbuildspec.ymlに記述する
2. 作成したtaskdef.jsonをcodebuildのアーティファクトに出力
3. terraform側でtask定義のアーティファクトをcodebuildからのものを指定

Codebuild内で生成

aws ecs describe-task-definition \
--task-definition $ECS_TASK_DEFINITION_ARN \
--query taskDefinition \
| jq '.containerDefinitions[0].image="<IMAGE1_NAME>"' > taskdef.json

以上のようなコマンドをコードビルド内で実行します。
やっていることとしては、arnを指定してタスク定義を持ってきて、タスク定義ないのイメージの部分だけ<IMAGE1_NAME>に変えて、taskdef.jsonとして保存しています。

以下を参考にしました。
https://ngyuki.hatenablog.com/entry/2021/04/07/043415

buildspec.yamlでは以下のように記述しました

version: 0.2
env:
  variables:
    IMAGE_NAME: 'imagename'
phases:
  install:
    runtime-versions:
      docker: 18
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email --region ${AWS_DEFAULT_REGION})
      - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
      - URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME}
      - $(aws ecs describe-task-definition --task-definition $ECS_TASK_DEFINITION_ARN --query taskDefinition | jq '.containerDefinitions[0].image="<IMAGE1_NAME>"' > taskdef.json)
  build:
    commands:
      - docker build -f ./ecs/Dockerfile -t $URI:$CODEBUILD_RESOLVED_SOURCE_VERSION .
      - docker push $URI:$CODEBUILD_RESOLVED_SOURCE_VERSION
      - printf '{"Version":"1.0","ImageURI":"%s"}' $URI:$CODEBUILD_RESOLVED_SOURCE_VERSION > imageDetail.json
artifacts:
  files: 
    - imageDetail.json
    - taskdef.json

prebuildのコマンドとして上述のコマンドを実行し、作成したtaskdef.jsonartifactsfilesに指定しています。

ちなみに、$ECS_TASK_DEFINITION_ARNに関しては自分でCodebuild内の環境変数として設定する必要があります。
自分の場合はterraformにて以下のように設定いたしました。

resource "aws_codebuild_project" "main" {
# 省略
  environment {
    # 省略
    environment_variable {
      name  = "ECS_TASK_DEFINITION_ARN"
      value = aws_ecs_task_definition.task_def_name.arn
    }
  }
}

taksdef.jsonのアーティファクトを指定

taksdef.jsonのArtifactをCodebuild時に出力した場所を指定します。
自分の場合は、Sourceステージの出力先をsource、Buildステージはbuildとしていたので以下のよう にTaskDefinitionTemplateArtifactbuildに設定をしました。

resource "aws_codepipeline" "main" {
# 省略
  stage {
    name = "Deploy"
# 省略
    action {
      name            = "Deploy"
      input_artifacts = ["build", "source"]
      configuration = {
# 省略
        TaskDefinitionTemplateArtifact = "build"
        TaskDefinitionTemplatePath     = "taskdef.json"

        AppSpecTemplateArtifact        = "source"
        AppSpecTemplatePath            = "appspec.yml"
        Image1ArtifactName             = "build"
        Image1ContainerName            = "IMAGE1_NAME"
      }
    }
  }
}

環境変数にマルチバイト文字を使用した際のエラー

このような方法でタスク定義を実行するとCodedeployにて以下のようなエラーが出る場合があります。

Failed to validate the task definition. Check the task definition in the
"TaskDefinitionTemplateArtifact" parameter for your pipeline action
and verify the configuration details for the ECS service.

これはECSのタスク定義内でコンテナに設定している環境変数内にマルチバイト文字が使われているのが原因のようです。
なのでコンテナの環境変数にはシングルバイト文字だけにしましょう。

以下を参考にしました。
https://zuntan02.hateblo.jp/entry/2020/12/28/204325

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4