8
3

More than 3 years have passed since last update.

CIツールでecspressoを使いつつAWS CodePipelineの承認フローを通してECSへデプロイする

Last updated at Posted at 2021-01-03

はじめに

ecspressoを使いつつAWS CodePipeline上での承認フローステージを通してECSへデプロイする方法を検証しました。

前提

  • 既存ですでに以下のリソースが存在している前提になります。
    • Docker Image on ECR
    • ALB
    • ECS Cluster
    • ECS Task Definition
    • ECS Service
    • CodePipelineに付与するIAMサービスロール
    • 上記を構成するためのVPC、サブネット、セキュリティグループなど諸々
  • CIツールはGitLab CI
  • ECSはFargateタイプであり、ECS ServiceのデプロイではCodeDeploy(Blue/Green)を利用している。

ローカル環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.6
BuildVersion:   19G2021

$ ecspresso version
ecspresso v1.2.1

Contents

概要

概要として今回は全体として以下のようなアプリケーションのデプロイフローを構築しました。

CIツールであるGitLab CIにてECRへDockerイメージをPushすることとS3へecspressoからtaskdef.jsonとappspec.yamlを出力。
CodePipelineでは承認フローを設定し承認されたらECS(Blue/Green)にてタスク定義が反映されCodeDeployからアプリケーションがデプロイされます。

image.png

ecspressoの初期設定

ecspressoの初期設定を行います。

既存でECSには以下のようなECS ClusterとECS Serviceがあり、このアプリケーションのデプロイフローを構築する場合、以下のようなに実行します。1

image.png

$ ecspresso init --config config.yaml --region ap-northeast-1 --cluster ecspressopoc --service rjpf-ecspressopoc-service

上記を実行することで以下の3つのファイルが生成されます。

  • config.yaml -> ecspresso 設定ファイル
  • ecs-service-def.json -> ECSサービスの構成を定義するecspresso用ファイル
  • ecs-task-def.json -> aws cliで得られるのと同様なECSタスク定義ファイル

config.yamlecs-service-def.json

こちらの公式ドキュメントと同じ項目のファイルになっています。

config.yamlecs-service-def.jsonに関しては修正する部分は特にありません。

ecs-task-def.json

ecs-task-def.jsonこちらの公式ドキュメントと同様に出力されています。

ここでCIツールを使って継続的にECS Task Definitionバージョンを更新できるように修正します。

ecspressoのテンプレート機能を利用します。2

ECR上のImageバージョンのimmutable性を保証するためにも"Image"フィールドは以下のように修正します。

ecs-task-def.jsonの一部
      "image": "{{ must_env `ECR_IMAGE_URL` }}",

後述のCIツールのフロー内でECR_IMAGE_URL環境変数を設定しCIでのecspressoコマンドにてECRへPushしたURLに置換してECS Task Definitionへ更新します。

また、アプリケーションの環境変数をデプロイ先の環境ごとに変えるためにECS Task Definitionの環境変数を設定する箇所も以下のようにしています。CIツールのフローは後述します。

ecs-task-def.jsonの一部
      "environment": [
        {
          "name": "DB_HOST",
          "value": "{{ must_env `DB_HOST` }}"
        }
      ],

CodePipelineのトリガーとなるS3バケットの作成

今回はCodePipelineのSource ActionとしてS3を利用するのでそのためのS3バケットを作成します。3

このS3は後述するCDKにて管理対象のリソースとして作成しています。

CIツール(GitLab CI) + ecspresso

以下が今回利用したGitLab CIでのYamlファイルになります。

ステップとして以下になります。

  1. pushステージにて
    1. docker buildで対象アプリケーションをビルドする。
    2. AWS ECRへ対象イメージをタグ名(Gitコミットハッシュ)付きでDOCKER PUSHする。
  2. deployステージにて
    1. ecspresso renderでECS Task Definitionファイルのtaskdef.jsonをテンプレートから生成する。
    2. ecspresso appspecによりECS(Blue/Green)でのCodeDeployのためのappspec.yamlを生成する。
    3. 上記2つのファイルをZIP化し上述のS3バケットへアップロードする。
.gitlab-ci.yml
variables:
    IMAGE_TAG: ${CI_COMMIT_SHA}
    ECSPRESSO_VERSION: "v1.2.1"
    AWSCLI_VERSION: "1.18.134"
    ECR_NAME: "ecspressopoc"

stages:
    - push
    - deploy

.push_variables: &push_variables
    DOCKER_DRIVER: overlay2

.push_setup: &push_setup
    image: docker:stable
    services:
        - docker:18.09-dind
    before_script:
        - apk add git
        - apk -Uuv add groff less python3 py-pip
        - pip install awscli

.push: &push
    stage: push
    script:
        - docker build -t ${ECR_NAME} .
        - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
        - docker tag ${ECR_NAME}:latest ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${ECR_NAME}:${IMAGE_TAG}
        - docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${ECR_NAME}:${IMAGE_TAG}

.deploy_setup: &deploy_setup
    image: python:3.8
    before_script:
        # install AWS CLI
        - pip install --upgrade pip
        - pip install --upgrade awscli==${AWSCLI_VERSION}
        # install commands
        - apt-get update -y && apt-get install -y curl unzip zip
        # install ecspresso
        - curl -sL -o ecspresso-${ECSPRESSO_VERSION}-linux-amd64.zip https://github.com/kayac/ecspresso/releases/download/${ECSPRESSO_VERSION}/ecspresso-${ECSPRESSO_VERSION}-linux-amd64.zip
        - unzip ecspresso-${ECSPRESSO_VERSION}-linux-amd64.zip
        - install ecspresso-${ECSPRESSO_VERSION}-linux-amd64 /usr/local/bin/ecspresso
        - ecspresso version

.deploy: &deploy
    stage: deploy
    script:
        - export ECR_IMAGE_URL=${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${ECR_NAME}:${IMAGE_TAG} # For ecspresso
        - export DB_HOST=${DB_HOST}
        - ecspresso --config config.yaml render --task-definition > taskdef.json
        - ecspresso --config config.yaml appspec | sed -e '/TaskDefinition/ s/arn.*$/"<TASK_DEFINITION>"/' > appspec.yaml
        - zip ecspresso-deploy-poc.zip appspec.yaml taskdef.json
        - aws s3 cp ecspresso-deploy-poc.zip s3://dev-ecspresso-poc

.dev_variables: &dev_variables
    AWS_ENV: "dev"
    AWS_ACCOUNT_ID: "123456789012"
    DB_HOST: ${DEV_DB_HOST} # variable is in GitLab CI setting

.dev_config: &dev_config
    only:
        - develop
    tags:
        - my-platform_dev_docker
    allow_failure: false

dev-push:
    variables:
        <<: *dev_variables
        <<: *push_variables
    <<: *dev_config
    <<: *push_setup
    <<: *push
    dependencies:
        - dev-migrate-task

dev-deploy:
    variables:
        <<: *dev_variables
    <<: *dev_config
    <<: *deploy_setup
    <<: *deploy
    dependencies:
        - dev-push

ecspresso renderecs appspecのそれぞれのサブコマンドについてはそれぞれ以下のページで詳細を確認できます。

CodePipeline with 承認フロー

CodePipelineをAWS CDKを利用して構築しました。

注意 ただし注意点として今回対象にしていたCodePipelineのECS Blue/Green Action ProviderがCDKでは2021年1月時点で未対応なのでその部分に関しては、私は現状ではそれ以前のステージまではCDKで対応しcdk deploy後に手動で追加修正している状況です。GitHubでは https://github.com/aws/aws-cdk/issues/1559 のIssueが最新の動向になっています。

この記事ではCDKのインストール方法と基本的な利用方法には言及しません。

今回はCDKではTypeScriptを利用しました。対象のコードとしては以下になります。

lib/ecspressopoc-cpipe-stack.ts
import { Role } from "@aws-cdk/aws-iam";
import { Bucket, BlockPublicAccess } from "@aws-cdk/aws-s3";
import { Stack, Construct, StackProps } from "@aws-cdk/core";
import { Pipeline, Artifact } from "@aws-cdk/aws-codepipeline";
import {
  S3SourceAction,
  ManualApprovalAction
} from "@aws-cdk/aws-codepipeline-actions";

export class EcspressopocCpipeStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    // Source step
    //
    // S3 bucket as source
    const sourceBucket = new Bucket(this, 'ecspressopoc-bucket', {
      versioned: true, // a Bucket used as a source in CodePipeline must be versioned
      blockPublicAccess: BlockPublicAccess.BLOCK_ALL
    });
    // Source Action
    const sourceOutput = new Artifact();
    const sourceAction = new S3SourceAction({
            actionName: 'S3Source',
            bucket: sourceBucket,
            bucketKey: 'ecspresso-deploy-poc.zip',
            output: sourceOutput,
    });

    // Approval step
    //
    // Manual Approval Action
    const approvalAction = new ManualApprovalAction({
      actionName: 'ManualApproval',
    });

    // ECS Deploy step
    // TODO: Waiting for ECS Blue Green Deployment in CDK

    // Assemble pipeline
    new Pipeline(this, "Pipeline", {
      pipelineName: "ecspressopoc-cdk",
      role: Role.fromRoleArn(this, 'plRole', 'arn:aws:iam::12345678901:role/ecspresso-poc'); // role which can access to ECS Blue/Green Deployment,
      stages: [
        {
          stageName: "S3-Source",
          actions: [sourceAction],
        },
        {
          stageName: "Approval",
          actions: [approvalAction],
        }
      ],
    });
  }
}

上記では前述のようにGitLab CIがアップロードする先のS3バケットを以下の設定で作成しています。

  • versioned: true ← CodePipeline Source用のS3バケットは必ずVersioningをEnabledにしている必要がある。
  • blockPublicAccess: BlockPublicAccess.BLOCK_ALL ← 内部でしか利用しないのでPublicアクセスはすべてブロックにしておく。

手動承認に関して今回は最小限の設定です。より詳しい仕様は公式ドキュメントで確認できます。

上記をcdk deployによりデプロイした後に前述の理由から手動でECS(Blue/Green)でのデプロイ設定をします。以下スクショのようにしています。

image.png

CodePipelineでは以下のスクショのようになり、GitLab CIがS3へZIPファイルをアップロードすると処理が開始され、手動承認をするとアプリケーションがECSへデプロイされることを確認しました。

image.png

参考

8
3
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
8
3