GitHubActionsで環境ごとに異なるシークレットを使用するジョブを一つのワークフローファイルで構築する
はじめに
GitHubActionsでワークフローを組んでいるときに、本番環境とStaging環境に対するワークフローを組みたいがワークフロー自体は同一の内容で違うのはシークレットの値だけ、という場面があった。
ワークフローを共通化させて良い感じにするには、今まで使ったことのなかったReusable workflowというものが必要だったので残しておく。
方法
例として、本番環境とStaging環境へデプロイするためのワークフローがあり、デプロイ処理自体は同一だがシークレットの値によってデプロイ先を制御できるとする。それぞれのシークレットのキーは以下とする。
- 本番環境:
secrets.DEPLOY_KEY_PRODUCTION
- Staging環境:
secrets.DEPLOY_KEY_STAGING
このワークフローを素直に構築してしまうと以下のパターンが考えられる。
- 同一のワークフローファイル内で
if
を使いながらシークレットを使い分ける deploy-production.yml
、deploy-staging.yml
と環境ごとにワークフローファイルを作成する
どちらの方法でも実現できるが、前者は行数が長くなるし制御が複雑で可読性に欠ける。後者は環境ごとに処理内容が重複するファイルが増えてしまい変更時などの管理が煩雑になってしまう。
これらの問題に対応するには、同一のワークフローを利用しながら異なるシークレットを同じキーとして利用できるようにしたい。これを実現できるのがReusable workflowで、共通の処理を複数のワークフローで共有することができる仕組みだ。
まずはいつものようにワークフローを作成する。main
ブランチまたはdevelop
ブランチへのプッシュをトリガーとしている。
name: Deploy
on:
push:
branches:
- main
- develop
jobs:
staging:
if: github.ref == 'refs/heads/develop'
uses: ./.github/workflows/_deploy.yml
with:
environment: staging
secrets:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY_STAGING }}
production:
if: github.ref == 'refs/heads/main'
uses: ./.github/workflows/_deploy.yml
with:
environment: production
secrets:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY_PRODUCTION }}
staging
とproduction
という環境ごとのジョブを呼び出し、それぞれをif
で制御している。staging
のジョブはdevelop
ブランチへのプッシュがあったとき、production
のジョブはmain
ブランチへのプッシュがあったときに実行されるようにしている。そして、uses: ./.github/workflows/_deploy.yml
でReusable workflowを呼び出す。このときにそれぞれの環境ごとに利用する変数とシークレットをwith
とsecrets
でワークフローに渡す。
_deploy.yml
は以下のように設定する。
name: _Deploy
on:
workflow_call:
inputs:
environment:
type: string
description: Name of target environment
required: true
secrets:
DEPLOY_KEY:
description: Deploy key
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
run: |
echo ${{ inputs.environment }}
echo ${{ secrets.DEPLOY_KEY }}
workflow_call
で別のワークフローから呼び出せるようにトリガーを設定する。また、inputs
とsecrets
でワークフローから渡される変数とシークレットの定義を記述する。
これで別々のシークレットであるDEPLOY_KEY_PRODUCTION
とDEPLOY_KEY_STAGING
を同じワークフロー内でDEPLOY_KEY
として利用することができるようになった。
おわり
最初はoutputs
を使って環境ごとのシークレットの差異を吸収してワークフローの共通化を図ったが、ワークフローにシークレットを渡せなかったり、やるとしても暗号化して復号化してと処理が煩雑になったりと試行錯誤することになってしまった。
まだまだGitHubActionsの経験値が足りないことを実感した。