1. はじめに
複数リポジトリで似たような CI/CD を書き続けていると、修正のたびに同じ YAML を何箇所もコピペしているはずです。GitHub Actions の Reusable Workflows(再利用可能ワークフロー) は、ワークフロー全体を「外から呼べる関数」のように扱える仕組みで、組織横断のテンプレート化と運用統一に最適です。本記事では、Composite Action との違い、呼び出し構文、inputs / secrets / outputs の設計、matrix との併用、ネストとセキュリティの注意点までを公式仕様に沿って整理します。
GitHub Actions 全般の使い所は Flutter アプリの CI/CD をどう組むか でも触れていますので、合わせてご覧ください。
2. Reusable Workflow とは
Reusable Workflow は、on: workflow_call: トリガを持つ通常のワークフロー YAML です。他のワークフロー(caller)から job の uses: キーで呼び出される側 として動作し、入力 (inputs)、シークレット (secrets)、出力 (outputs) を介してデータをやり取りします。
主な特徴を整理します。
- 再利用の単位: ワークフロー全体(複数 job、matrix、permissions、runner 指定を含む)。
- 呼び出し位置: caller 側の job レベルで
uses:を書く(step ではない)。 - 隔離性: reusable 側は独立したワークフロー実行として走り、ログも別ビューで確認できる。
- 配置場所:
.github/workflows/直下のみ。サブディレクトリに置いたファイルは呼び出せません。
3. Composite Action との違い
「再利用」というと Composite Action と混同しがちですが、抽象化のレイヤが違うため、使い分けが必要です。
| 観点 | Reusable Workflow | Composite Action |
|---|---|---|
| 再利用の単位 | ワークフロー(複数 job) | 1 つの step に展開される一連の手順 |
| 呼び出し場所 | caller の job 直下 uses: |
caller の step 直下 uses: |
自前の runs-on |
持てる(job ごとに指定) | 持てない(caller の runner を使う) |
strategy.matrix |
内部の job で使える | 不可(caller 側 job が持つ matrix に従う) |
permissions |
自前で指定可(caller より同等以下のみ) | 不可(caller の job 設定を継承) |
secrets |
on.workflow_call.secrets で受け取り |
inputs として明示的に渡す必要あり |
secrets: inherit |
使える | 使えない |
| 配置パス | .github/workflows/ 直下のみ |
リポジトリ内任意(通常 .github/actions/*/) |
| 典型用途 | 「ビルド〜デプロイ」など大きな job の塊 | 「依存セットアップ」「キャッシュ」等の手順束 |
使い分けの目安: matrix・複数 job・別 runner・OIDC を含む大粒度の処理は Reusable Workflow、共通の数ステップを束ねたいだけなら Composite Action、と分けるとシンプルです。
4. 作成方法 — 呼ばれる側 YAML
呼ばれる側は .github/workflows/ 直下に置き、on: workflow_call セクションで inputs / secrets / outputs を宣言します。以下は Azure 環境にデプロイする実用サンプルです。
# .github/workflows/reusable-deploy.yml
name: Reusable Deploy
on:
workflow_call:
inputs:
environment:
description: "デプロイ先環境名 (dev / stage / prod)"
required: true
type: string
enable-smoke-test:
description: "デプロイ後にスモークテストを実行するか"
required: false
type: boolean
default: true
secrets:
AZURE_CREDENTIALS:
description: "azure/login で使うサービスプリンシパル JSON"
required: true
outputs:
deploy-url:
description: "デプロイされたアプリの URL"
value: ${{ jobs.deploy.outputs.deploy-url }}
permissions:
contents: read
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
deploy-url: ${{ steps.do-deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Azure login
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to ${{ inputs.environment }}
id: do-deploy
run: |
echo "Deploying to ${{ inputs.environment }} ..."
# 実際のデプロイコマンドに置き換える
URL="https://app-${{ inputs.environment }}.example.com"
echo "url=$URL" >> "$GITHUB_OUTPUT"
- name: Smoke test
if: ${{ inputs.enable-smoke-test }}
run: curl -fsS "${{ steps.do-deploy.outputs.url }}/health"
ポイント:
inputsのtypeはboolean/number/stringを指定できます。outputsは step output → job output → workflow_call output の三段で持ち上げます。permissionsは caller から渡された権限以下に絞り込みます(昇格は不可)。on.workflow_callのトリガー定義自体にはenvironment:キーを指定できません。ただし呼ばれる側の job レベルでenvironment:を指定すること自体は可能で、その場合は caller から渡されたシークレットではなく、その environment 自身に設定されたシークレットが優先される点に注意してください。
5. 呼び出し方 — 呼ぶ側 YAML
caller 側は job の直下に uses: を書きます。step の uses: ではない点が最大のハマりどころです。
# .github/workflows/caller.yml
name: Deploy pipeline
on:
push:
branches: [main]
permissions:
contents: read
id-token: write
jobs:
deploy:
strategy:
fail-fast: false
matrix:
target: [dev, stage, prod]
# SHA ピン留めで再現性とサプライチェーンの安全性を確保
uses: my-org/platform-workflows/.github/workflows/reusable-deploy.yml@2f1c4a9d8b6e0f3c5a7d9e2b4c6f8a0d1e3b5c7d
with:
environment: ${{ matrix.target }}
enable-smoke-test: true
secrets: inherit
notify:
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Show deployed URLs
run: |
echo "Last deploy URL: ${{ needs.deploy.outputs.deploy-url }}"
呼び出し構文は 2 通りです。
| 呼び出し先 | 構文 | ref の扱い |
|---|---|---|
| 他リポジトリ | {owner}/{repo}/.github/workflows/{file}.yml@{ref} |
SHA / tag / branch。タグとブランチ同名はタグ優先 |
| 同一リポジトリ | ./.github/workflows/{file}.yml |
@ref 不可・式不可。caller の commit から読まれる |
secrets: inherit は同じ org / enterprise 内の reusable に対し、caller が持つシークレットをそのまま渡せる便利な指定です。ただし伝播するのは 直接の呼び先 1 段のみで、さらに先の reusable に渡したい場合は明示的に secrets: で再パスする必要があります。
6. matrix との併用
strategy.matrix を caller 側の job に書くと、matrix の各組み合わせごとに reusable workflow が並列起動します。上記サンプルでは target: [dev, stage, prod] の 3 環境が独立してデプロイされます。
注意点として、matrix 経由で並列起動した場合の needs.<job>.outputs.<name> は「最後に成功した job の値」が入ります。環境ごとの URL を個別に保持したい場合は、各 matrix の出力をファイルや artifact、または GitHub の Deployment API に書き出す設計にしておくと安全です。
7. ネストとセキュリティの注意点
Reusable Workflow は最大 10 階層まで入れ子にできます(caller + reusable 9 段)。ただし以下の制約があります。
- ループ不可: A → B → A のような循環は禁止。
- 権限は維持または縮小のみ: 子側で
permissionsを昇格させることはできません。 - secrets: inherit は 1 段のみ: 深いネストでは各段で明示的に渡し直す。
- 同一リポジトリの reusable:
./.github/workflows/file.yml形式は caller のコミットから読み込まれるため、ref を別に指定することはできません。
セキュリティ運用のベストプラクティスは以下の通りです。
- SHA ピン留め:
@<40 桁 SHA>を基本にし、サプライチェーン攻撃面を狭める。 - タグ/リリースでのバージョニング: 内製の platform リポジトリ側で
v1/v1.2.3を発行し、利用側は SHA で参照する運用が現実的。 - 最小
permissions: caller 側でpermissions: {}から始め、必要分だけ追加。 - Enterprise Cloud では audit log API で reusable workflow の利用状況を可視化できる。
- 組織テンプレート:
.githubリポジトリのworkflow-templates/に置いて、新規リポジトリ作成時に推奨できるようにする。
8. まとめ
Reusable Workflow は、Composite Action では届かない「job 単位・複数環境・OIDC を含む大粒度の自動化」を共通化する手段として強力です。本記事のサンプル(reusable-deploy.yml / caller.yml)をたたき台に、まずは社内のデプロイ系ワークフローを 1 本 reusable 化するところから始めるのがおすすめです。
GitHub Actions の他の活用事例は Flutter アプリの CI/CD をどう組むか も参考になります。
9. 参考リンク
- Reusing workflows — GitHub Docs
- Events that trigger workflows —
workflow_call - Creating a composite action
- Security hardening for GitHub Actions
この記事の執筆にあたり、AI の支援を受けています。






