ECS Fargateのタスク定義の取得→更新→反映をShellとjqで自動化

2021.07.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンテナベースで開発作業していて、更新したコンテナイメージを、ECS(Fargate)上で稼働しているサービスに反映したいという時、ちゃんとした開発ラインならCI/CDパイプライン組んで自動デプロイするトコロですが、諸事情もありますよね?
じゃあ、と手作業でやってみるとこれが結構面倒なので、シェルにしました。

概要

サービスへの反映までに至る流れは、以下のようになります。

  1. 対象となるサービスにアタッチされているタスク定義を特定し、取得する
  2. それを基に新たなタスク定義を作成する
  3. 新たに作成したタスク定義を、元のサービスにアタッチする

なお、所謂Latest運用はここでは想定していません。
では、何はさておきコードです

スクリプト

#!/bin/bash

ECS_CLUSTER_NAME=your-cluster-name
ECS_SERVICE_NAME_KEY=your-service-name
REPOSITORY_URL=your-ecr-url_or_somewhere
TASKDEF_CONTAINER_NAME=your-container-name
TASKDEF_CONTAINER_IMAGE="$1"

# 1. get target service arn
echo "cluster: ${ECS_CLUSTER_NAME}"
echo "service key: ${ECS_SERVICE_NAME_KEY}"
SERVICE_ARN=$(aws ecs list-services --cluster ${ECS_CLUSTER_NAME} | jq -r '.serviceArns[] | select(. | test("'${ECS_SERVICE_NAME_KEY}'"))')
echo "service: $SERVICE_ARN"
if [[ -z "${SERVICE_ARN}" ]]; then
  echo "[ERROR] Service missing."
  exit 1
fi
if [ $(echo "${SERVICE_ARN}" | wc -l) -ne 1 ];then
  echo "[ERROR] More than one services found."
  exit 1
fi

# 2. get current task-def arn
SRC_TASKDEF=$(aws ecs describe-services --cluster ${ECS_CLUSTER_NAME} --services ${SERVICE_ARN} | jq -r '.services[0].taskDefinition')
echo "current taskdef: ${SRC_TASKDEF}"

# 3. get task-def details and modify it
# remove unneeded props and else
# override container's image
aws ecs describe-task-definition --task-definition ${SRC_TASKDEF} \
  | jq '.taskDefinition | del(.taskDefinitionArn, .status, .requiresAttributes, .compatibilities, .revision)' \
  | jq '(.containerDefinitions[] | select(.name == "'${TASKDEF_CONTAINER_NAME}'")).image = "'${REPOSITORY_URL}/${TASKDEF_CONTAINER_IMAGE}'"' > /tmp/taskdef.json

# 4. register new task-definition
NEW_TASKDEF=$(aws ecs register-task-definition --cli-input-json file:///tmp/taskdef.json | jq -r '.taskDefinition.taskDefinitionArn')
echo "new taskdef: ${NEW_TASKDEF}"

# 5. update service
aws ecs update-service --cluster ${ECS_CLUSTER_NAME} --service ${SERVICE_ARN} --task-definition ${NEW_TASKDEF}

echo "Done! (wait a while to rolling update..."

仕様

  • 埋め込み変数
    • 対象サービスの属するクラスタの名前
    • 対象サービスの名前(部分一致)
    • 対象コンテナの名前: タスク定義の中で、複数のコンテナが定義可能です。対象コンテナを特定するために必要です。
    • イメージのあるリポジトリのベースURL
      • ex: xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com
  • 引数
    • コンテナに指定する、新しいイメージのTag
      • ex: $ ./this.sh my-app:0.1.0
  • 不正終了
    • 指定されたクラスタに紐付くサービス群から、対象サービスを部分一致検索します。サービスを一意に特定できなかった場合は不正終了します。

要所でjqを使っています。jqは上手く使えば相当強力ですが、あまり職人的な域まで頑張ってしまうと、将来の自分が苦労するので程々にしました(シェルも同様)。

タスク定義のJsonを加工するところは、ニーズ次第で色々あろうと思うので、分かりやすさ優先で書いてます。処理追加等して楽しんで頂ければと思います。jq使ってスッキリ実現できると大変気持ちよいです♪