AWS ECS에서 DDBMigration 자동화

소개



안녕하세요. wano 주식회사 엔지니어의 nari라고 합니다.
이번에는 ECS의 run task를 이용한 CD pipeline상에서의 DBmigration의 실행에 대해 기사로 하고 싶습니다.

전체 시스템 이미지





전제


  • 이번 프로젝트에서는 CD pipeline을 Code 시리즈로 구축하고 있었으므로, 드디어 build 종료시에 option에서 db migrate가 달리도록 해 보았다
  • 정직 테이블의 변경은 혼입된 사건이 ​​많고, 복잡한 오퍼레이션이 필요하게 되는 경우가 많기 때문에, 이만큼의 오퍼레이션으로 끝나는지는 확실하지 않다 (그 실험도 겸한 운용)

  • GitHub - golang-migrate/migrate: Database migrations. CLI and Golang library.을 마이그레이션 도구로 사용

    어떻게 작동합니까?



    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한다


  • CD pipeline의 codebuild post_build 단계에서 db migrate task가 실행됩니다

  • 4. 결과를 슬랙 알림으로 확인





    어떻게 구현했는지


  • 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"]
    
    
    

    참고문헌


  • EC2 시작 유형을 사용하여 작업 수행 - Amazon Elastic Container Service

  • 운영중인 시스템에도 도입 가능한 Go 마이그레이션 도구 "mattes/migrate" - Qiita
  • Laravel을 Elastic Beanstalk에서 Fargate로 마이그레이션했습니다.
  • 좋은 웹페이지 즐겨찾기