contents

code Buildやcircleciで実行する、ECSのタスク定義作成、停止スクリプトサンプル。
例えば、dev(開発)環境であれば、ecsを問答無用で更新、停止。
本番環境であればタスク定義のみ更新し、リリース判断時にecsのblue green deploymentなどの使い分けをする場合を想定

対象者

CICDに興味がある、code Buildの実行イメージを掴みたい人

ECSタスク定義作成スクリプト makeNewECSTaskDefinition.sh

bash ./.circleci/makeNewECSTaskDefinition.sh --SERVICE_NAME ${SERVICE_NAME_WEB} --PORT_NUM "hoge" --CPU_VOLUME "2048" --MEMORY_VOLUME "4096" --IMAGE_TAG_NAME $CIRCLE_SHA1 --ENVIRONMENT_NAME ${ENVIRONMENT_NAME} --ENVIRONMENT_FULL_NAME ${ENVIRONMENT_FULL_NAME} --AWS_ACCOUNT_ID ${AWS_ACCOUNT_ID}

makeNewECSTaskDefinition.sh

#!bin/bash

# shの使用方法説明関数
function usage() {
    cat <<EOS
  Usage: $0 [REQUIRED OPTIONS]
  [REQUIRED OPTIONS]
    --IMAGE_TAG_NAME                  : IMAGE_TAG_NAME
    --ENVIRONMENT_FULL_NAME           : ENVIRONMENT_FULL_NAME
    --AWS_ACCOUNT_ID                  : AWS_ACCOUNT_ID
    --ENVIRONMENT_NAME                : ENVIRONMENT_NAME
    --SERVICE_NAME                    : SERVICE_NAME
    --PORT_NUM                        : PORT_NUM
    --CPU_VOLUME                      : CPU_VOLUME
    --MEMORY_VOLUME                   : MEMORY_VOLUME
EOS
    exit 1
}

# 引数から変数への格納部分 --** という引数を明示するために必要
ARGS=($@)
for ((i = 0; i < ${#ARGS[@]}; i++)); do
    case "${ARGS[$i]}" in
    "--IMAGE_TAG_NAME")
        i=$(expr $i + 1)
        readonly IMAGE_TAG_NAME="${ARGS[$i]}"
        ;;
    "--ENVIRONMENT_FULL_NAME")
        i=$(expr $i + 1)
        readonly ENVIRONMENT_FULL_NAME="${ARGS[$i]}"
        ;;
    "--AWS_ACCOUNT_ID")
        i=$(expr $i + 1)
        readonly AWS_ACCOUNT_ID="${ARGS[$i]}"
        ;;
    "--ENVIRONMENT_NAME")
        i=$(expr $i + 1)
        readonly ENVIRONMENT_NAME="${ARGS[$i]}"
        ;;
    "--SERVICE_NAME")
        i=$(expr $i + 1)
        readonly SERVICE_NAME="${ARGS[$i]}"
        ;;
    "--PORT_NUM")
        i=$(expr $i + 1)
        readonly PORT_NUM="${ARGS[$i]}"
        ;;
    "--CPU_VOLUME")
        i=$(expr $i + 1)
        readonly CPU_VOLUME="${ARGS[$i]}"
        ;;
    "--MEMORY_VOLUME")
        i=$(expr $i + 1)
        readonly MEMORY_VOLUME="${ARGS[$i]}"
        ;;
    *)
        usage
        ;;
    esac
done

# 引数をチェック。必要な引数がない場合は使用方法を説明
if [ -z "${IMAGE_TAG_NAME}" -o -z "${ENVIRONMENT_FULL_NAME}" -o -z "${AWS_ACCOUNT_ID}" -o -z "${ENVIRONMENT_NAME}" -o -z "${SERVICE_NAME}" -o -z "${PORT_NUM}" -o -z "${CPU_VOLUME}" -o -z "${MEMORY_VOLUME}" ]; then
    usage
fi
#jqのinstall箇所
JQ_URL="https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/jq-latest"
sudo curl --silent --show-error --location --fail --retry 3 --output /usr/bin/jq $JQ_URL
sudo chmod +x /usr/bin/jq

# 環境変数設定部分
readonly ECR_DOMAIN="${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com"
readonly ECS_CLUSTER_NAME="sample-${ENVIRONMENT_NAME}-cluster"
readonly ECS_SERVICE_NAME="sample-${ENVIRONMENT_NAME}-${SERVICE_NAME}"
readonly ECS_ROLE_NAME="sample-${ENVIRONMENT_NAME}-rehouse-web"

# タスク定義のパラメータに関して、IMAGE_TAG_NAMEの情報を置換しデータを取得
TASK_JSON_DATA=$(cat << EOS | jq
{
  "containerDefinitions": [
    {
      "name": "${SERVICE_NAME}",
      "image": "${ECR_DOMAIN}/${SERVICE_NAME}:${IMAGE_TAG_NAME}",
      "cpu": 0,
      "portMappings": [
        {
          "containerPort": ${PORT_NUM},
          "hostPort": ${PORT_NUM},
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "environment": [],
      "secrets": [{   
        "valueFrom": "google-map-api-key",
        "name": "GOOGLE_MAP_API_KEY"
        }
      ],
      "mountPoints": [],
      "volumesFrom": [],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/${ECS_ROLE_NAME}",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": [
          "CMD-SHELL",
          "curl -f http://localhost:${PORT_NUM}/healthcheck || exit 1"
        ],
        "interval": 30,
        "timeout": 8,
        "retries": 3,
        "startPeriod": 240
      }
    }
  ],
  "family": "${ECS_SERVICE_NAME}",
  "taskRoleArn": "arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ECS_ROLE_NAME}-task-role",
  "executionRoleArn": "arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ECS_ROLE_NAME}-task-role",
  "networkMode": "awsvpc",
  "volumes": [],
  "placementConstraints": [],
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "${CPU_VOLUME}",
  "memory": "${MEMORY_VOLUME}"
}
EOS
)

# aws cliで使用するため一度ファイル出力
echo "$TASK_JSON_DATA" > .circleci/TASK_JSON_DATA.json

# aws cliでタスク登録
aws ecs register-task-definition --family ${ECS_SERVICE_NAME} --cli-input-json fileb://.circleci/TASK_JSON_DATA.json


ECSタスク停止スクリプト stopECSTasks.sh

bash ./.circleci/stopECSTasks.sh --CLUSTER_NAME ${ECS_CLUSTER_NAME} --SERVICE_NAME sample-${ENVIRONMENT_NAME}-${SERVICE_NAME_WEB}

stopECSTasks.sh

#!bin/bash

# shの使用方法説明関数
function usage() {
    cat <<EOS
  Usage: $0 [REQUIRED OPTIONS]
  [REQUIRED OPTIONS]
    --CLUSTER_NAME                  : CLUSTER_NAME
    --SERVICE_NAME                  : SERVICE_NAME
EOS
    exit 1
}

# 引数から変数への格納部分 --** という引数を明示するために必要
ARGS=($@)
for ((i = 0; i < ${#ARGS[@]}; i++)); do
    case "${ARGS[$i]}" in
    "--CLUSTER_NAME")
        i=$(expr $i + 1)
        readonly CLUSTER_NAME="${ARGS[$i]}"
        ;;
    "--SERVICE_NAME")
        i=$(expr $i + 1)
        readonly SERVICE_NAME="${ARGS[$i]}"
        ;;
    *)
        usage
        ;;
    esac
done

# 引数をチェック。必要な引数がない場合は使用方法を説明
# 停止する条件を絞るためのクラスター名とサービス名(マッチしたタスクを停止する)
if [ -z "${CLUSTER_NAME}" -o -z "${SERVICE_NAME}" ]; then
    usage
fi

#jqのinstall箇所
JQ_URL="https://circle-downloads.s3.amazonaws.com/circleci-images/cache/linux-amd64/jq-latest"
sudo curl --silent --show-error --location --fail --retry 3 --output /usr/bin/jq $JQ_URL
sudo chmod +x /usr/bin/jq

#停止するタスク情報を上記の変数名から取得
json_data=$(aws ecs list-tasks --cluster ${CLUSTER_NAME} --query "taskArns" --service-name ${SERVICE_NAME})
json_length=`echo ${json_data} | jq length`

for i in `seq 0 $(expr ${json_length} - 1)`
do
    #アカウントに紐付き、該当するタスクの名前を全て取得
    taskname=`echo ${json_data} | jq .[${i}] | sed "s/\"//g"`
    echo ${taskname}
    #タスク消去、apiの戻り値を消去するために--query 'noResponse'を設定
    aws ecs stop-task --cluster ${CLUSTER_NAME} --task ${taskname} --query 'noResponse'
done

関連記事

AWS CodeDeployを用いたblue green deploymentイメージおよびscript例