GitHub Actionsのworkflow_callイベントを使用してワークフローファイルを分割する

はじめに

エキサイト株式会社 バックエンドエンジニアの山縣(@zsp2088dev)です。

エキサイトホールディングス Advent Calendar 2023の6日目を担当します。

私の担当するエキサイトブログでは、アプリケーションのテスト、ビルド、デプロイにGitHub Actionsを使用しています。 GitHub Actionsを使用するにあたり、ワークフローファイルを.github/workflowsに定義していますが、 初回に定義したワークフローファイルのメンテナスが中々できていませんでした。 このような中で、GitHub Actionsでワークフローを再利用できることを知り、これを適用できそうだと判断し、実際にワークフローファイルを分割することにしました。

本記事では、workflow_callイベントを使用したワークフローの分割とその際にハマった箇所、今後取り組みたいことについて紹介します。

概要

ワークフローファイルを分割する前のファイル一覧です。

❯ tree .github/workflows 
.github/workflows
├── deploy_production.yml
├── deploy_staging.yml
└── deploy_test.yml

それぞれのワークフローファイルで、以下の処理を定義しています。 このように、共通の処理が多く存在し、コピペでワークフローファイルを作成することが常態化していました。

テスト環境

  1. コンテナをビルド
  2. Amazon ECRにビルドしたイメージをプッシュ
  3. Amazon ECSにデプロイ

ステージング環境/本番環境

  1. 静的ファイル(CSS/JavaScript)をAmazon S3にアップロード
  2. コンテナをビルド
  3. Amazon ECRにビルドしたイメージをプッシュ
  4. Amazon ECSにデプロイ

ワークフローファイルの分割

GitHub Actionsでワークフローを再利用できることを知り、早速ワークフローファイルを分割することにしました。 ワークフローを再利用するには、workflow_callイベントを使用します。 これにより、別のワークフローからワークフローを呼び出すことができるようになります。

docs.github.com

以下に分割後のワークフローファイルの一例を示します。

今回のケースでは、workflow_dispatchイベントからworkflow_callイベントを呼び出しており、静的ファイルのアップロードとコンテナデプロイの処理を、それぞれworkflow_callイベントに切り出しました。 これにより、それぞれの処理が一箇所にまとまり、タスクの追加や修正の手間を低減することができるようになります。

静的ファイルのアップロード (upload_to_s3.yml)

on:
  workflow_call:
    inputs:
      aws-s3-path:
        type: string
        required: true
    secrets:
      sample-secret-value:
        required: true

jobs:
  upload-to-s3:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
       # 以下で、静的ファイルのアップロード処理

コンテナデプロイの処理 (deploy_to_ecs.yml)

on:
  workflow_call:
    inputs:
      image-name:
        type: string
        required: true
      cluster-name:
        type: string
        required: true
      service-name:
        type: string
        required: true
    secrets:
      sample-secret-value:
        required: true

jobs:
  deploy-to-ecs:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      # 以下で、コンテナビルド→コンテナデプロイの処理

テスト環境のデプロイ (deploy_test.yml)

name: 'deploy test'
on:
  workflow_dispatch:

jobs:
  skip-upload:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Skip upload"

  deploy:
    needs: skip-upload
    uses: ./.github/workflows/deploy_to_ecs.yml
    with:
      image-name: sample-test
      cluster-name: sample-test-cluster
      service-name: sample-test-service
    secrets:
      sample-secret-value: ${{ secrets.SAMPLE_SECRET_VALUE_TEST }}

ステージング環境のデプロイ (deploy_staging.yml)

name: 'deploy staging'
on:
  workflow_dispatch:

jobs:
  upload:
    uses: ./.github/workflows/upload_to_s3.yml
    with:
      aws-s3-path: s3://sample/staging/path
    secrets:
      sample-secret-value: ${{ secrets.SAMPLE_SECRET_VALUE_STAGING }}

  deploy:
    needs: upload
    uses: ./.github/workflows/deploy_to_ecs.yml
    with:
      image-name: sample-staging
      cluster-name: sample-stating-cluster
      service-name: sample-staging-service
    secrets:
      sample-secret-value: ${{ secrets.SAMPLE_SECRET_VALUE_STAGING }}

本番環境のデプロイ (deploy_production.yml)

name: 'deploy production'
on:
  workflow_dispatch:

jobs:
  upload:
    uses: ./.github/workflows/upload_to_s3.yml
    with:
      aws-s3-path: s3://sample/production/path
    secrets:
      sample-secret-value: ${{ secrets.SAMPLE_SECRET_VALUE_PRODUCTION }}

  deploy:
    needs: upload
    uses: ./.github/workflows/deploy_to_ecs.yml
    with:
      image-name: sample-production
      cluster-name: sample-production-cluster
      service-name: sample-production-service
    secrets:
      sample-secret-value: ${{ secrets.SAMPLE_SECRET_VALUE_PRODUCTION }}

ハマった箇所

workflow_callイベントを使用するにあたり、ハマった箇所について2つ紹介します。

stepsでワークフローファイルを呼び出すとエラーになる

再利用可能なワークフローを呼び出すときに、steps内で呼び出していたところエラーになりました。 jobs内で呼び出さないといけないようです。

以下の通り、公式ドキュメントの制約事項にも記述がありました。

Reusable workflows are called directly within a job, and not from within a job step. You cannot, therefore, use GITHUB_ENV to pass values to job steps in the caller workflow.

1つだけ別のワークフローを呼び出すとエラーになる

テスト環境のデプロイで使用するワークフローには、skip-uploadジョブを定義しています。 これは、以下のエラー文の通り、workflow_callイベントのみを使用したジョブを定義することができないため使用しています。

The workflow must contain at least one job with no dependencies.

今後取り組みたいこと

ワークフローファイルで、workflow_callイベントを使用したワークフローファイルの分割以外にも取り組みたいことについて、以下にまとめます。

Environments secretsの活用

GitHub Actionsでは、Environments欄より環境を設定できます。 さらに、環境ごとに環境変数とシークレット変数を定義できます。

現状では、リポジトリ単位でシークレット変数を定義しており、変数名の末尾に_TEST_PRODUCTIONといった環境名を定義しています。 Environments secretsを活用して、それぞれの環境ごとにシークレット変数を用意したいと考えています。

docs.github.com

on.workflow_dispatch.inputsの活用

workflow_dispatchイベントを使用して手動実行するときに、inputsを使用することで、セレクトボックスを配置できます。 例えば、以下のように環境名を選択肢に入れることで、その値をワークフローファイル内で使用することができます。 また、上記のEnvironments secretsと併用することで、より使いやすいワークフローファイルを定義できそうです。

on:
  workflow_dispatch:
    inputs:
      ENV:
        description: 環境を指定します
        default: test
        required: true
        type: choice
        options:
          - test
          - staging
          - production

docs.github.com

おわりに

本記事では、workflow_callイベントを使用したワークフローの分割とその際にハマった箇所、今後取り組みたいことについて紹介しました。 エキサイトブログでは、既存機能の改修や新機能の開発などに取り組みやすい環境を作るために、CI/CDの整備にも力を入れていきます。

採用アナウンス

エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しています。 また、長期インターンも歓迎しています。

カジュアル面談からもOKです。少しでもご興味がございましたら、お気軽にご連絡頂ければ幸いです。

▼ 募集職種一覧 ▼ recruit.jobcan.jp