継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

プルリクマージ後に AWS SAM と GitHub Actions を使った差分デプロイフローを作ってみた

タダです.

以前モノリポに格納されているコードの中で変更があったコードのみ AWS SAM と GitHub Actions のデプロイフローを検証した記事を書いたのですが,投入したところプルリクをマージした後にデプロイがうまくいきませんでした.この記事でうまくいかなかったところとどう回避したかを書いていきます.

sadayoshi-tada.hatenablog.com

どこがうまくいかなかったのか

早速どの辺がうまくいかなかったのかなんですが,プルリクのマージ後にBuild & Deployのセクションの処理が差分を検知せずに処理が終わってしまいました.恐らくプルリクが発生した段階ではマージ先とマージ元の差分があるが,マージされた後だとその差分がなくなるため差分検知がなくなったため下記の定義では差分デプロイができなくなったと推測しました.

on:
  pull_request:
      types: closed
    paths:
      - '**app.py'

env:
  TARGET_BRANCH: ${{ github.base_ref }}

jobs:
  sam-test:
    runs-on: ubuntu-latest
    steps:
      - name: 'Checkout'
        uses: actions/checkout@v2

     - name: 'Fetch'
        run: git fetch --depth 1 origin ${TARGET_BRANCH}

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: '3.7'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install awscli
          pip install aws-sam-cli

      - name: Configure AWS credentials for prod
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION}}

      - name: Build & Deploy
        run: |
          for FILE in $(git diff origin/${TARGET_BRANCH} HEAD --diff-filter=AM --name-only -- "*app.py") ; do
            cd $(dirname ${FILE}); cd ../
            STACK_NAME=`pwd | awk -F "/" '{ print $NF }'`
            sam build --use-container
            sam package --template-file template.yaml --output-template-file packaged.yaml --s3-bucket ${{ secrets.AWS_SAM_BUCKET }} --region ${{ secrets.AWS_REGION}}
            sam deploy --template-file packaged.yaml --stack-name ${STACK_NAME} --s3-bucket ${{ secrets.AWS_SAM_BUCKET }} --region ${{ secrets.AWS_REGION}} --capabilities CAPABILITY_IAM
            cd ../
          done

どのように問題を回避したか

うまくいかなかった差分デプロイを2つのステップに分割して問題を回避するようにしました.以下 YAML ファイルで変更した部分だけ抜粋して記載します.

on:
  push:
    branches:
      - master
  pull_request:

jobs:
  sam-tes:
    runs-on: ubuntu-latest
    steps:
      ~中略~
      - name: Package
        if: contains(github.event_name, 'pull_request')
        env:
          TZ: 'Asia/Tokyo'
        run: |
          # Set variables
          DATE=`date +"%Y%m%d"`
          # sam packaged
          for FILE in $(git diff origin/${TARGET_BRANCH} HEAD --diff-filter=AM --name-only -- "*app.py") ; do
            cd $(dirname ${FILE}); cd ../
            STACK_NAME=`pwd | awk -F "/" '{ print $NF }'`
            sam package --template-file template.yaml --output-template-file ${DATE}-${STACK_NAME}.yaml --s3-bucket ${{ secrets.AWS_SAM_BUCKET }} --region ${{ secrets.AWS_REGION}}
            aws s3 cp ${DATE}-${STACK_NAME}.yaml s3://${{ secrets.AWS_SAM_BUCKET }}
            cd ../
          done

      - name: Deploy
        if: contains(github.event_name, 'push')
        env:
          TZ: 'Asia/Tokyo'
        run: |
          # Set variables
          DATE=`date +"%Y%m%d"`
          aws s3 cp s3://${{ secrets.AWS_SAM_BUCKET }} . --recursive --exclude '*' --include "${DATE}*.yaml"
          for FILE in `\find . -name "${DATE}*.yaml"` ; do
            echo ${FILE}
            STACK_NAME=`echo ${FILE} | cut -c12- | sed 's/\.[^\.]*$//'`
            sam deploy --template-file ${FILE} --stack-name ${STACK_NAME} --s3-bucket ${{ secrets.AWS_SAM_BUCKET }} --region ${{ secrets.AWS_REGION}} --capabilities CAPABILITY_IAM
          done
          aws s3 rm s3://${{ secrets.AWS_SAM_BUCKET }} --recursive --exclude '*' --include "${DATE}*.yaml"

YAML で行った変更ですが,ざっくり次の対応をしています.この変更を行うことで差分デプロイを通すことができました.

  1. onセクションで,プルリクイベント発生時とマージ後のイベントを検知するようにした
  2. sam packagesam deployの処理をプルリクイベント発生時とマージ後に分けて処理するようにして,sam packageで生成したファイルを一時的に S3 にアップロード/ダウンロードしてデプロイし,デプロイ後に S3 にアップロードしたファイルを削除

まとめ

モノリポにおける AWS SAM と GitHub Actions を使った差分デプロイでうまくいかなかったこととその回避したアプローチを書きました.もっと良い方法があるかもしれないとは思っているのですが,自分の中で解がでなかったのでもしより良い方法あったら教えていただけると幸いです🙇‍♂️