はじめに
最近CodePipelineを使ってecsのデプロイを自動化する仕事をしていました。
その中でCodeDeployを使用することになったのですが、
CodeDeployを使ってデプロイするためにはアプリケーションコードがあるリポジトリ内にtaskdef.json
ファイルを作成してそこにタスク定義を書く必要があります。
しかし、プロジェクトではterraformでインフラを管理していたため、タスク定義がterraformとアプリケーションコードの両方に存在しているのは避けたいと思い、Codebuild内でtaskdef.jsonを作成することにした。
概略
方法
- ecsからtask定義を持ってきてそれをもとにtaskdef.jsonを作成するコマンドをbuildspec.ymlに記述する
- 作成したtaskdef.jsonをcodebuildのアーティファクトに出力
- 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.json
をartifacts
のfiles
に指定しています。
ちなみに、$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
としていたので以下のよう にTaskDefinitionTemplateArtifact
をbuild
に設定をしました。
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