AWS CodeBuildでRidgepoleをdry-runで動かしてMigration予定のDDLをGithubのPullRequestコメントに追記してReviewしやすくする

ANDPAD バックエンド担当の原田(@tomtwinkle)です。

普段はGolangでモリモリコードを書いていますがDevOps関連の記事ばかり書いてます。

お察しの通りなんですが、今回もDevOps関連の記事だったりします。

やり方だけ知りたい人は Motivation の部分は読み飛ばして貰っても問題ないです。

Motivation

私が担当しているANDPADボードではRDS(MySQL)を利用しています。 そして、DBのschemaはRidgepoleのschemaファイルで定義され、変更がある場合はRidgepoleでMigrationを行っています。

Ridgepoleはバージョンにより挙動が若干変わるので例えばRidgepoleのバージョンを上げただけで予期せぬschema変更が走るかもしれません。

schemaファイルのReviewだけで、Migrationを走らせるのは怖いですね? なので最終的にDBに流し込むDDLをGithubのPRの段階で確認したくなります。

と、ここまで読んで「あれ?その話どっかで見覚えがあるぞ?」と思った方は流石ですね。普段からよく技術記事を読まれている方だと思います。

実は私も去年のkamillleさんの↓この記事↓を見て良さそう!と思い、実際にやってみた口です。

zenn.dev

ただし、今回はAWS CodeBuildで動かしている点が違うため対応の内容も結構変わってきています。

何故Github ActionsではなくAWS CodeBuild なのか……

DBは機密情報の塊、アクセスできる方法は極力制限すべきです。

そのためDBにdry-runを実行するためにアクセスできる環境が限られてきます。

特にGithubのSecretsに本番DBへのアクセスが可能になる情報は載せたくない、RDSを操作できる口をVPCの外に出したくないとなると必然的にAWSの内部でどうにかMigrationを行う必要が出てきます。

そのため今回、AWS CodeBuildでdry-runを走らせてCodeBuildからGithubに対してPRコメントを出す方法を取りました。

AWS CodeBuild側の準備

GithubのPrivate Access Tokenを発行する

CodebuildからGithubに対してPRコメントを書き込むためにはGithubのPrivate Access Tokenを使用する必要があります。 これは個人のアカウントではなく会社で管理するbot用の専用のユーザーを作ったほうが良いと思います。

Github Private Access Tokenを発行する手順は ここらへんを参考にして下さい。

AWS Systems ManagerのParameter StoreにDBとGithubへのアクセス情報を記述

AWS Systems ManagerのParameter StoreにCodeBuildの環境変数で渡すパラメータを作成します。

作成が必要なパラメータは

  • DBのユーザー
  • DBのパスワード
  • Github Private Access Token

TokenやUser/Passwordは勿論Secret情報ですので Type: SecureString で作成していきます。

ちなみにCodeBuild用のParameterの名前は「/CodeBuild/」で始まることが推奨されています

Parameter Store

CodeBuildを作成

まずはCodeBuildのソースをGithubに指定 Repository in my GitHub account から 対象のRepositoryを選択します。

まだAWSとGithub を連携していない場合は ここらへん を参考にして連携を行って下さい。

SourceVersion は手動でCodeBuildを走らせた時に見る内容なので手動で走らせることがない限り中身無くても良いと思います。

codebuild Source

次にWebHookの設定

codebuild Webhook

PullRequestの作成/更新時に動いて欲しいので Event type には PULL_REQUEST_CREATEDPULL_REQUEST_UPDATED を指定します。 BASE_REFPRをmergeする先のリリースbranch をrefsから指定します 今回の例では仮にmain branchをリリースbranchとするので ^/refs/heads/main$ にしておきます。 ここの値は正規表現を解釈するので特に末尾 $ を指定しないと予期せぬbranchで動いてしまうかもしれません。

FILE_PATH を指定すると指定されたファイルが変更された場合にCodeBuildが動いてくれるようになります………が、このパラメータは検証の結果ファイルの変更が多すぎる場合どうも無視されるようです。 指定したら必ず動かないという訳でも無さそうなのでそこだけ注意が必要そうです。

ここらへんの設定は後でCodeBuild内で取得できるSystem環境変数の値にも響いてくるので別のWebHookを設定する場合は別途検証が必要です。

お次は Environment の設定。

codebuild Environment variables

OS Image は特に理由がない場合は Amazon Linux 2 で良いでしょう。

Role は特に理由がない場合新規に作成するのが一番楽です。既存のRoleを使用したい場合は追加でAction許可する必要があるかもしれません。少なくとも ssm:GetParameters の追加は必要になります。

Timeout の値はdefaultでも良いですが、今回の場合はどんなに長くても10分超えたら何かおかしいのでその程度に設定しておくのが良さそうです。

VPCの設定は環境によって異なるので省きます。

Environment variables には

  • DBのエンドポイント
  • DBのデータベース名
  • DBのユーザー
  • DBのパスワード
  • Github Private Access Token

を設定します。 AWS Systems ManagerのParameter Storeを使用する環境変数はTypeに Secrets Manager を指定します。

Buildspec には実際にCodeBuildの動作を定義するyamlファイルを指定します。 ここには対象Repositoryにあるbuildspecファイルのパスを指定します。

codebuild buildspec

Logs はaudit的な意味で記録しておいた方が良いでしょう、必要かどうかは各自の判断で。

Github Repository側の用意

Buildspecの記載

ここからが本題。

Ridgepoleを dry-run して 変更がある場合にのみ GithubのPullRequestコメントにDDLを追記させていきます。

CodeBuildの Buildspec で指定したパスに以下のbuildspec yamlファイルを配置します。 今回の例では .codebuild/buildspec.dryrun-db-migrate.yml ですね。

schema変更はDBREにレビューして欲しい!みたいな事があるかもしれないので GITHUB_PR_REVIEWER が指定されていればその人を Reviewerに追加するみたいな処理も入っています。

version: 0.2

env:
  variables:
    GITHUB_ORGANIZATION: <GithubのOrganization>
    GITHUB_REPOSITORY: <GithubのRepository>
    GITHUB_PR_APPEND_WORDS: "このPRで以下のDDLがDBに反映されるよ!しっかり確認してね!"
    GITHUB_PR_REVIEWER: ""
    RIDGEPOLE_VERSION: 1.2.0
    RIDGEPOLE_SCHEMA_FILE: <RidgepoleのSchemafileパス>

phases:
  install:
    commands:
      - gem -v
      - gem install ridgepole:${RIDGEPOLE_VERSION} mysql2
      - yum update -y -q --skip-broken
      - yum install -y -q mariadb-server
      - ridgepole --version

  build:
    commands:
      - mysql -u${RDS_USER} -p${RDS_PASS} -h${RDS_ENDPOINT} ${RDS_DATABASE} -vvv -e "show databases;"
      - |
        result=$(ridgepole \
            -c '{database: "'${RDS_DATABASE}'", adapter: mysql2, username: "'${RDS_USER}'", password: "'${RDS_PASS}'", host: "'${RDS_ENDPOINT}'"}' \
            -f ${RIDGEPOLE_SCHEMA_FILE} \
            --apply --dry-run)
      # GithubのPull request numberを取得
      - GITHUB_PR_NUMBER=${CODEBUILD_WEBHOOK_TRIGGER#pr/}
      - echo ${GITHUB_PR_NUMBER}
      # Ridgepoleのdry-runの結果からDDLのみをgrep
      - result=$(echo "${result}" | grep "# " || exit 0)
      - |
        # Ridgepoleのdry-runの結果で変更がある場合のみ動作するようにする
        if [ "${result}" != "" ]; then
          result=$(echo -e "${GITHUB_PR_APPEND_WORDS}\n\`\`\`\n${result//# /}\n\`\`\`")
          jq -n \
          --arg result "$result" \
          '{
            "body":$result,
          }' > body.json
          cat body.json
          # GithubのPull requestにdry-runの結果のDDLをコメントする
          curl \
          -X POST \
          -H "Accept: application/vnd.github+json" \
          -H "Authorization: token ${GITHUB_API_TOKEN}" \
          -H "Content-Type: application/json" \
          -d @body.json \
          "https://api.github.com/repos/${GITHUB_ORGANIZATION}/${GITHUB_REPOSITORY}/issues/${GITHUB_PR_NUMBER}/comments"
          # schema変更がある場合にレビュアーを追加して欲しい場合
          if [ "${GITHUB_PR_REVIEWER}" != "" ]; then
           jq -n \
           --arg team_reviewers "${GITHUB_PR_REVIEWER}" \
           '{
             "team_reviewers": [$team_reviewers]
           }' > body2.json
           cat body2.json
           curl \
            -X POST \
            -H "Accept: application/vnd.github+json" \
            -H "Authorization: token ${GITHUB_API_TOKEN}" \
            -H "Content-Type: application/json" \
            -d @body2.json \
            "https://api.github.com/repos/${GITHUB_ORGANIZATION}/${GITHUB_REPOSITORY}/pulls/${GITHUB_PR_NUMBER}/requested_reviewers"
          fi
        fi

動作結果

ここまでの設定で特に問題がなければPull requestを作成したタイミングでCodeBuildのWebHookが動作し、DBの変更がある場合は以下のようにPull Requestにコメントが付くようになりました。

Github PR DDL Change Comment

これでPull RequestのReviewも捗りますね! めでたしめでたし

謝辞

今回の環境構築に辺りSREチームのDanさんに設定の検証のためお世話になりました。ありがとうございました! 変更箇所がない場合にPRコメントしない修正を加えていただいた bushiyama さんにも感謝!

さいごに

当社アンドパッドでは日々協力しながらDevOps活動に取り組んでいます。 ご興味を持って頂けましたら、下記よりお気軽にカジュアル面談や採用職種についてお問い合わせください!

engineer.andpad.co.jp