LoginSignup
10
8

More than 3 years have passed since last update.

AWS ECS でDBMigrationを自動化する

Posted at

はじめに

こんにちわ。wano株式会社エンジニアのnariと申します。
今回はECSのrun taskを利用した、CD pipeline上でのDBmigrationの実行について記事にしたいと思います。

システム全体像

スクリーンショット 2019-09-11 02.31.56.png

前提

  • 今回のprojectではCD pipelineをCodeシリーズで構築していたので、ついでにbuild終了時にoptionでdb migrateが走るようにもしてみた
  • 正直テーブルの変更は込み入った事象が多く、複雑なオペレーションが必要とされることが多いため、これだけのオペレーションで済むかは定かではない(その実験も兼ねた運用)
  • GitHub - golang-migrate/migrate: Database migrations. CLI and Golang library. をmigrationツールとして使用(Go製でバイナリーで取ってこれる)

どうオペレーションするか

1. ${PROJECT_DIR}/resources/db/migrations に変更したい内容のsqlを入れる

スキーマのアップグレード用のマイグレーションファイルはYYYYMMDD_$ファイル名.up.sqlというファイル名にする。逆にダウングレード用はYYYYMMDD_$ファイル名.down.sqlといった命名規則。ここのNはマイグレーションバージョンを意味する。

2.${PROJECT_DIR}/infra/build_ci/ad/buildspec.ymlのmigrate箇所のコメントアウトを外す

  post_build:
    commands:
      ...
      ## db migrationしたい場合は以下3行のコメントアウトを外す
      - aws ecs run-task --launch-type EC2 --cluster cluster-hoge-${ENV} --task-definition ${ENV}-db-migration-ecs  > run-task.log
      - TASK_ARN=$(jq -r '.tasks[0].taskArn' run-task.log)
      - aws ecs wait tasks-stopped --cluster arn:aws:ecs:ap-northeast-1:${ACCOUNT_ID}:cluster/cluster-${ENV} --tasks $TASK_ARN
      ...

3.stage環境ならremote(gitlab)のstage/xxxx,prod環境ならprod/xxxxにpushする(本番環境の場合要pullrequest)

  • 上記CD pipelineのcodebuildのpost_buildフェーズで、db migrateのtaskが実行される

4.結果をslack通知で確認する

スクリーンショット 2019-08-28 13.18.59.png

どう実装したか

  • アプリケーション用のイメージをtask_definitionでentrypointを上書きする事でdb-migration用タスクを定義する
  • この上書きするentrypointは、事前にコンテナ内でプロビジョニングしたentry_point.shを実行する
container_definition.json
[
  {
    "name": "db-migration",
    "image": "xxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/prod-app:latest",
    "essential": true,
    "secrets": [
      {
        "name": "MIGRATION_DB",
        "valueFrom": "/prod/migration"
      }
    ],
    "environment": [
      {
        "name": "ENV",
        "value": "prod"
      }
    ],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-region": "ap-northeast-1",
        "awslogs-stream-prefix": "prod",
        "awslogs-group": "/ecs/migration/"
      }
    },
    "entrypoint": ["./entry_point.sh"]
  }
]

  • entry_point.shでは、migrationの実行と、slackへの結果通知を行なっている
  • multi stage buildフェーズでmigrationツールのバイナリを入れている
  • migration downの実装は、expectで対話型コマンド自動化している。少し無理やりな気もするので、auto-approveフラグを是非実装追加した欲しい。。(プルリクしろって話ですね。。)
# アプリケーション用のイメージ
ARG GO_VERSION=1.12.4

FROM golang:${GO_VERSION}-alpine AS builder

RUN apk add --no-cache git

##### source build
WORKDIR /root/go/src/xxxxxxxxx/hoge/hoge/


# こうするとmodファイルに変更があった時しかdownload走らない
ENV GO111MODULE=on
ENV GOPROXY=https://proxy.golang.org
ENV GOPRIVATE=*.gitlab.hoge.co.jp

COPY go.mod .
COPY go.sum .
# Because of how the layer caching system works in Docker, the  go mod download
# command will _ only_ be re-run when the go.mod or go.sum file change
RUN go mod download

FROM builder AS app_builder
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install  ./server_src/app/ad_server


###### multi stage build
FROM alpine

RUN apk --update add tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    apk del tzdata && \
    rm -rf /var/cache/apk/*

# dbmigrateツールdownload
ENV MIGRATE_VERSION="v4.6.1"
RUN apk --update add curl expect && \
    curl -L https://github.com/golang-migrate/migrate/releases/download/$MIGRATE_VERSION/migrate.linux-amd64.tar.gz | tar xvz && \
    rm -rf /var/cache/apk/*

ARG ENV=stage
ARG MIGRATION=/resources/db/migrations/
ARG SLACK_SH=/script/migration_report_to_slack/migration_result_to_slack.sh

COPY --from=app_builder /go/bin/ad_server ad_server
COPY --from=app_builder ${MIGRATION} migrations/
COPY --from=app_builder ${SLACK_SH} migration_result_to_slack.sh
RUN chmod 755 migration_result_to_slack.sh

# dbmigrate用のentry_point.shを作成
RUN echo $'#!/bin/sh \n\
#migrate downしたかったら以下のexpect部分をコメントアウトすべし\n\
#expect -c "\n\
#spawn ./migrate.linux-amd64 -database $MIGRATION_DB -path ./migrations down\n\
#expect \\"Are you sure you want to apply all down migrations? \[y/N\]\\"\n\
#send -- \\"y\\n\\"\n\
#expect \\"Applying all down migrations\\"\n\
#expect {\n\
#    -regexp \"\\n.*\\r\" {\n\
#        send \"exit\\n\"\n\
#    }\n\
#}\n\
#"\n\
\n\
#migrate upと結果およびversionをslackに通知\n\
./migrate.linux-amd64 -database $MIGRATION_DB -path ./migrations up 2>> migration_result.log \n\
chmod 644 migration_result.log \n\
export MIGRATION_RESULT=$(cat migration_result.log) \n\
./migrate.linux-amd64 -database $MIGRATION_DB -path ./migrations version 2> migration_version.log \n\
chmod 644 migration_version.log \n\
export MIGRATION_VERSION=$(cat migration_version.log) \n\
./migration_result_to_slack.sh' >> entry_point.sh
RUN chmod 755 entry_point.sh

# 後でecs-taskの定義で上書きされる
ENTRYPOINT ["./ad_server"]


参考文献

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