Pull Requestを作成したときにプレビュー用の環境を自動で作成してくれるGithub Actionsを作った。
こんな感じでプレビューURLを発行してくれて実際に動作確認ができるようになっている。
ローカルにブランチをpullしなくて済むので非常に便利である。
はじめに
Azure App Serviceではslotという概念があって、運用スロットから別環境を生成することができる。masterブランチからstagingブランチを切るイメージ。これを利用してPR作成時にプレビュースロットを作成してそこで動作確認をしようという試み。
こちらを死ぬほど参考にさせていただきました。上記の記事では必要最低限のことが非常によくまとまっており、試すならまずこちらからいくのがわかりやすい。Buy me a coffeeで思わずお布施してしまうほど。
上記の記事の内容に
- AppServiceのカスタムコンテナ(Docker)を利用した版
- CIがコケたあとの再pushへの対応
- actionsの共通化(Composite action)
をプラスしたものが今回の内容となる。
構成
.github ├── actions │ ├── ci │ │ └── action.yml │ ├── create_slot │ │ └── action.yml │ ├── deploy_slot │ │ └── action.yml │ ├── image_push │ │ └── action.yml │ └── is_exist_slot │ └── action.yml └── workflows └── create_preview.yml
コード
.github/workflows/create_preview.yml
これがメイン。PR作成時、更新時、削除時の3つの段落に分かれている。
name: Pull Request Preview on: pull_request: branches: # masterとstageは除外 - '**' - '!master' - '!stage' types: [opened, synchronize, closed] workflow_dispatch: jobs: ######## PR作成時 ######### create-deployment-preview: if: github.event.action == 'opened' runs-on: ubuntu-latest steps: - name: Checkout GitHub Action uses: actions/checkout@main # プレビュー環境作成中のコメント - name: Initial Deployment Preview Comment uses: peter-evans/create-or-update-comment@v1.4.5 id: pr-preview-comment with: issue-number: ${{ github.event.pull_request.number }} body: | ### Deployment Preview A preview of this Pull Request is being created. Hold tight while it's building ⚒️ This comment will be automatically updated when the preview is ready. # lint, test - name: CI uses: ./.github/actions/ci # Dockerイメージをビルド、デプロイ - name: Docker Build and Push uses: ./.github/actions/image_push with: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_ACR_PASSWORD: ${{ secrets.AZURE_ACR_PASSWORD }} DOCKER_IMAGE_TAG: '${{ secrets.AZURE_ACR_ID }}.azurecr.io/demo/webapp:preview-pr-${{ github.event.pull_request.number }}' # プレビューslot作成 - name: Create Preview Slot uses: ./.github/actions/create_slot with: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} AZURE_APP_NAME: '${{ secrets.AZURE_APP_NAME_STAGING }}' AZURE_RESOURCE_GROUP: '${{ secrets.AZURE_RESOURCE_GROUP_STAGING }}' SLOT_NAME: 'preview-pr-${{ github.event.pull_request.number }}' AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_ACR_PASSWORD: ${{ secrets.AZURE_ACR_PASSWORD }} # slotにイメージ反映 - name: Deploy Slot uses: ./.github/actions/deploy_slot with: AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_APP_NAME: ${{ secrets.AZURE_APP_NAME_STAGING }} # コメント更新 - name: Update PR Preview Comment uses: peter-evans/create-or-update-comment@v1.4.5 with: comment-id: ${{ steps.pr-preview-comment.outputs.comment-id }} edit-mode: replace body: | ### Deployment Preview 😎 Preview this PR: https://${{ secrets.AZURE_APP_NAME_STAGING }}-preview-pr-${{ github.event.pull_request.number }}.azurewebsites.net 👶 Commit SHA: ${{ github.sha }} reactions: 'rocket' ######## PR更新時(pushなど) ######### update-deployment-preview: if: github.event.action == 'synchronize' runs-on: ubuntu-latest steps: - name: Checkout GitHub Action uses: actions/checkout@main - name: Find PR Preview Comment uses: peter-evans/find-comment@v1 id: deploy-preview-comment with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Deployment Preview - name: Update PR Preview Comment if: steps.deploy-preview-comment.outputs.comment-id != '' uses: peter-evans/create-or-update-comment@v1.4.5 with: comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} edit-mode: replace body: | ### Deployment Preview The Pull Request preview is being updated. Hold tight while it's building ⚒️ This comment will be automatically updated when the new version is ready. # lint, test - name: CI uses: ./.github/actions/ci # Dockerイメージをビルド、デプロイ - name: Docker Build and Push uses: ./.github/actions/image_push with: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_ACR_PASSWORD: ${{ secrets.AZURE_ACR_PASSWORD }} DOCKER_IMAGE_TAG: '${{ secrets.AZURE_ACR_ID }}.azurecr.io/demo/webapp:preview-pr-${{ github.event.pull_request.number }}' # プレビューslotが作成されているかを確認 - name: Check Preview Slot Exists id: check-slot-exists uses: ./.github/actions/is_exist_slot with: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} AZURE_APP_NAME: '${{ secrets.AZURE_APP_NAME_STAGING }}' AZURE_RESOURCE_GROUP: '${{ secrets.AZURE_RESOURCE_GROUP_STAGING }}' SLOT_NAME: 'preview-pr-${{ github.event.pull_request.number }}' # プレビューslotが作成されていない場合、slotを作成する - name: Create Slot If Not Exists if: steps.check-slot-exists.outputs.exists_slot == '0' uses: ./.github/actions/create_slot with: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} AZURE_APP_NAME: '${{ secrets.AZURE_APP_NAME_STAGING }}' AZURE_RESOURCE_GROUP: '${{ secrets.AZURE_RESOURCE_GROUP_STAGING }}' SLOT_NAME: 'preview-pr-${{ github.event.pull_request.number }}' AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_ACR_PASSWORD: ${{ secrets.AZURE_ACR_PASSWORD }} # slotにイメージ反映 - name: Deploy Slot uses: ./.github/actions/deploy_slot with: AZURE_ACR_ID: ${{ secrets.AZURE_ACR_ID }} AZURE_APP_NAME: ${{ secrets.AZURE_APP_NAME_STAGING }} - name: Update PR Preview Comment uses: peter-evans/create-or-update-comment@v1.4.5 with: comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} edit-mode: replace body: | ### Deployment Preview 😎 Preview this PR: https://${{ secrets.AZURE_APP_NAME_STAGING }}-preview-pr-${{ github.event.pull_request.number }}.azurewebsites.net 👶 Commit SHA: ${{ github.sha }} ######## PR削除時 ######### delete-deployment-preview: if: github.event.action == 'closed' runs-on: ubuntu-latest steps: - name: Checkout GitHub Action uses: actions/checkout@main - name: Azure Login uses: Azure/login@v1.4.3 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Login to Azure Container Registry uses: azure/docker-login@v1 with: login-server: ${{ secrets.AZURE_ACR_ID }}.azurecr.io username: ${{ secrets.AZURE_ACR_ID }} password: ${{ secrets.AZURE_ACR_PASSWORD }} # Dockerイメージの削除 - name: Delete Docker Image uses: Azure/cli@v1 with: inlineScript: az acr repository delete --name ${{ secrets.AZURE_ACR_ID }} --image demo/webapp:preview-pr-${{ github.event.pull_request.number }} --username ${{ secrets.AZURE_ACR_ID }} --password ${{ secrets.AZURE_ACR_PASSWORD }} --yes # slotの削除 - name: Delete PR Deployment Slot uses: Azure/cli@v1 with: inlineScript: az webapp deployment slot delete --name ${{ secrets.AZURE_APP_NAME_STAGING }} --resource-group ${{ secrets.AZURE_RESOURCE_GROUP_STAGING }} --slot preview-pr-${{ github.event.pull_request.number }} - name: Find PR Preview Comment uses: peter-evans/find-comment@v1 id: deploy-preview-comment with: issue-number: ${{ github.event.pull_request.number }} comment-author: 'github-actions[bot]' body-includes: Deployment Preview - name: Update PR Preview Comment if: steps.deploy-preview-comment.outputs.comment-id != '' uses: peter-evans/create-or-update-comment@v1.4.5 with: comment-id: ${{ steps.deploy-preview-comment.outputs.comment-id }} edit-mode: replace body: | 🏁 This PR has been closed. No deployment preview is available. reactions: 'hooray'
actionsの共通化
PR作成時、更新時、削除時でいくつか共通のactionsがあるので共通化している。Composite action
と呼ばれているやつ。
今回共通化したactionsは下記
- ci
- create_slot
- deploy_slot
- image_push
- is_exist_slot
.github/actions/ci/action.yml
CIの設定
name: 'CI' runs: using: 'Composite' steps: - name: Set up Node.js version uses: actions/setup-node@v1 with: node-version: 14.x - name: yarn lint, test shell: bash run: | yarn install yarn lint yarn test
.github/actions/create_slot/action.yml
slotの作成。ポイントはACR認証の環境変数をセットしないとイメージのpullに失敗してしまうため、ここでセットする。
name: 'Create Slot' description: 'slot作成' inputs: AZURE_CREDENTIALS: required: true AZURE_APP_NAME: required: true AZURE_RESOURCE_GROUP: required: true SLOT_NAME: required: true AZURE_ACR_ID: required: true AZURE_ACR_PASSWORD: required: true runs: using: 'Composite' steps: - name: Azure Login uses: azure/login@v1 with: creds: ${{ inputs.AZURE_CREDENTIALS }} - name: Create PR Deployment Slot uses: Azure/cli@v1 with: inlineScript: | az webapp deployment slot create \ --name ${{ inputs.AZURE_APP_NAME }} \ --resource-group ${{ inputs.AZURE_RESOURCE_GROUP }} \ --configuration-source ${{ inputs.AZURE_APP_NAME }} \ --slot ${{ inputs.SLOT_NAME }} # AppServiceの環境変数をセット。ここでACR認証の環境変数をセットしないとImageのpullに失敗するため。 - name: Set Web App ACR authentication uses: Azure/appservice-settings@v1 with: app-name: '${{ inputs.AZURE_APP_NAME }}' slot-name: '${{ inputs.SLOT_NAME }}' app-settings-json: | [ { "name": "DOCKER_REGISTRY_SERVER_URL", "value": "${{ inputs.AZURE_ACR_ID }}.azurecr.io", "slotSetting": false }, { "name": "DOCKER_REGISTRY_SERVER_USERNAME", "value": "${{ inputs.AZURE_ACR_ID }}", "slotSetting": false }, { "name": "DOCKER_REGISTRY_SERVER_PASSWORD", "value": "${{ inputs.AZURE_ACR_PASSWORD }}", "slotSetting": false }, ]
.github/actions/deploy_slot/action.yml
slotにDockerイメージを反映
name: 'Deploy Slot' description: 'slotにイメージ反映' inputs: AZURE_APP_NAME: required: true AZURE_ACR_ID: required: true runs: using: 'Composite' steps: - name: Slot Update uses: azure/webapps-deploy@v2 with: app-name: '${{ inputs.AZURE_APP_NAME }}' images: ${{ inputs.AZURE_ACR_ID }}.azurecr.io/demo/webapp:preview-pr-${{ github.event.pull_request.number }} slot-name: preview-pr-${{ github.event.pull_request.number }}
.github/actions/image_push/action.yml
コンテナレジストリにイメージをpush
name: 'Docker Image Push' inputs: AZURE_CREDENTIALS: required: true AZURE_ACR_ID: required: true AZURE_ACR_PASSWORD: required: true DOCKER_IMAGE_TAG: required: true runs: using: 'Composite' steps: - name: Azure Login uses: azure/login@v1 with: creds: ${{ inputs.AZURE_CREDENTIALS }} - name: Login to Azure Container Registry uses: azure/docker-login@v1 with: login-server: ${{ inputs.AZURE_ACR_ID }}.azurecr.io username: ${{ inputs.AZURE_ACR_ID }} password: ${{ inputs.AZURE_ACR_PASSWORD }} # Dockerイメージをビルド、デプロイ - name: Docker Build and Push shell: bash run: | docker build -t demo-docker -f Dockerfile . \ && docker tag demo-docker:latest ${{ inputs.DOCKER_IMAGE_TAG }} \ && docker push ${{ inputs.DOCKER_IMAGE_TAG }}
.github/actions/is_exist_slot/action.yml
slotが作成済みかをチェック。
name: 'Exists Slot' description: 'slotの存在確認' inputs: AZURE_CREDENTIALS: required: true AZURE_APP_NAME: required: true AZURE_RESOURCE_GROUP: required: true SLOT_NAME: required: true outputs: exists_slot: description: "slotが存在している場合は1、存在していない場合は0を返す" value: ${{ steps.check-slot-exists.outputs.exists_slot }} runs: using: 'Composite' steps: - name: Azure Login uses: Azure/login@v1.4.3 with: creds: ${{ inputs.AZURE_CREDENTIALS }} # プレビューslotが作成されているかを確認 - name: Check Preview Slot Exists uses: Azure/cli@v1 id: check-slot-exists with: inlineScript: | az webapp config container show \ --resource-group ${{ inputs.AZURE_RESOURCE_GROUP }} \ --name ${{ inputs.AZURE_APP_NAME }} \ --slot ${{ inputs.SLOT_NAME }} \ > /dev/null 2>&1 && echo '::set-output name=exists_slot::1' || echo '::set-output name=exists_slot::0'
プレビュー環境の作成時間
大体5~6分で作成が完了する。ただここはアプリのbuild時間にもよるので各々。
slotの作成自体は2分ぐらい。
終わり
フロントエンドのPRレビューするときはプレビュー環境ないとやる気にならない身体になってしまった。