増えすぎた GitHub Actions を「3層アーキテクチャ」でリファクタリング
シンプルフォーム株式会社 / Jun Irie
EM / EM / 従業員規模: 101名〜300名 / エンジニア組織: 11名〜50名
| 利用プラン | 利用機能 | ツールの利用規模 | ツールの利用開始時期 | 事業形態 |
|---|---|---|---|---|
Team | CI/CD | 51名〜100名 | 2022年6月 | B to B |
| 利用プラン | Team |
|---|---|
| 利用機能 | CI/CD |
| ツールの利用規模 | 51名〜100名 |
| ツールの利用開始時期 | 2022年6月 |
| 事業形態 | B to B |
アーキテクチャ

アーキテクチャの意図・工夫
長期的にメンテナンス、理解がしやすくなるよう、以下のような 責務を分離した 3 層アーキテクチャ で構成しました。
各層の役割と実装
1. Trigger 層 (トリガー層)
責務: 外部イベントを受け取り、環境固有のパラメータを設定する
Trigger 層は、GitHub のイベント (release, push, workflow_dispatch) を受け取るエントリーポイントです。デプロイロジックは一切含まず、パラメータの定義のみ を行います。
環境別トリガーの固定化
各環境で使用するトリガーを固定することで、一貫性を確保します。環境とトリガーとの対応は GitHub Flow をベースにしています。
| 環境 | トリガー | タイミング | ファイル名 |
|---|---|---|---|
| prod | release | GitHub リリース作成時 | on_release_deploy-xxx-prod.yml |
| stg | push | main ブランチへのマージ時 | on_push_deploy-xxx-stg.yml |
| dev | workflow_dispatch | 手動実行 | on_dispatch_deploy-xxx-dev.yml |
実装例: stg 環境の Trigger 層
name: "[app1/stg] Build & Deploy"
on:
push:
branches:
- main
paths:
- "services/app1/**"
env:
SERVICE: app1
ENVIRONMENT: stg
jobs:
vars:
runs-on: ubuntu-latest
outputs:
env: ${{ env.ENVIRONMENT }}
account_id: ${{ steps.get_account_config.outputs.account_id }}
deploy_role: ${{ steps.get_account_config.outputs.deploy_role }}
steps:
- uses: actions/checkout@v5
- id: get_account_config
uses: ./.github/actions/get_account_config
with:
service: ${{ env.SERVICE }}
env: ${{ env.ENVIRONMENT }}
deploy_app:
needs: vars
uses: ./.github/workflows/_deploy-app1.yml
with:
env: ${{ needs.vars.outputs.env }} # Reusable Workflow では inputs に環境変数を受け取れないため、前ジョブの出力にして渡している
account_id: ${{ needs.vars.outputs.account_id }}
deploy_role: ${{ needs.vars.outputs.deploy_role }}
ポイント:
- 環境固有の情報 (SERVICE, ENVIRONMENT) のみを定義
- Reusable Workflow への呼び出しに徹する
- デプロイロジックは一切含まない
2. Reusable Workflow 層 (再利用ワークフロー層)
責務: ビジネスロジックの実装と、差分チェックやビルド・デプロイのオーケストレーション
この層では、workflow_call で呼び出される再利用可能なワークフローを定義します。複数の環境から共通して利用されるため、環境に依存しない汎用的な実装 が重要です。
実装例: Reusable Workflow
name: "[app1] Build & Deploy (Reusable Workflow)"
on:
workflow_call:
inputs:
env:
required: true
type: string
description: "Environment name"
account_id:
required: true
type: string
description: "Account ID for deployment"
deploy_role:
required: true
type: string
description: "IAM role ARN for deploy app1"
deploy_all:
required: false
type: boolean
default: false
description: "Deploy all components regardless of diff"
jobs:
check_diff:
runs-on: ubuntu-latest
outputs:
diff_backend: ${{ steps.diff_backend.outputs.changed_files }}
diff_frontend: ${{ steps.diff_frontend.outputs.changed_files }}
steps:
- uses: actions/checkout@v5
# バックエンドの差分チェック
- id: diff_backend
if: ${{ !inputs.deploy_all }}
uses: ./.github/actions/get_diff
with:
file_patterns: |
services/backend/**
ignore_file_patterns: |
services/backend/**/*.md
# フロントエンドの差分チェック
- id: diff_frontend
if: ${{ !inputs.deploy_all }}
uses: ./.github/actions/get_diff
with:
file_patterns: |
services/frontend/**
ignore_file_patterns: |
services/frontend/**/*.md
# 差分がある場合のみバックエンドをデプロイ
deploy_backend:
needs: check_diff
# 前ジョブの一部がキャンセルされても実行できるように !(failure() || cancelled()) を指定
if: ${{ ! (failure() || cancelled()) && (needs.check_diff.outputs.diff_backend != '' || inputs.deploy_all) }}
uses: ./.github/workflows/_deploy_backend.yml
with:
env: ${{ inputs.env }}
account_id: ${{ inputs.account_id }}
# 差分がある場合のみフロントエンドをデプロイ
deploy_frontend:
needs: check_diff
if: ${{ ! (failure() || cancelled()) && (needs.check_diff.outputs.diff_frontend != '' || inputs.deploy_all) }}
uses: ./.github/workflows/_deploy_frontend.yml
with:
env: ${{ inputs.env }}
account_id: ${{ inputs.account_id }}
ポイント:
- 標準的な入力パラメータ (
env,account_id,deploy_allなど) を受け取る - 差分チェックの結果に基づいてデプロイを制御
- 環境に依存しない汎用的な実装
3. Composite Action 層 (コンポジットアクション層)
責務: 基本的な操作を組み合わせた再利用可能なアクションの提供
この層では、.github/actions/ 配下に配置される共通処理を Composite action として定義します。実装例については OSS として様々な action が提供されているため本記事では割愛します。
実装のポイント
1. 命名規則の統一
ワークフローファイルは、トリガー種別に応じたプレフィックスを付与します。
| トリガー種別 | プレフィックス | 例 |
|---|---|---|
| release | on_release_ | on_release_deploy-xxx-prod.yml |
| push | on_push_ | on_push_deploy-xxx-stg.yml |
| workflow_dispatch | on_dispatch_ | on_dispatch_deploy-xxx-dev.yml |
| workflow_call | _ | _deploy-xxx.yml |
この命名規則により、ファイル名から 役割とトリガーが一目で分かる ようになります。
2. 標準インターフェースの定義
Reusable Workflow は、以下の標準的な入力パラメータを受け取ります。AWS を対象としているため、アカウントや IAM, ARN といった用語は AWS のそれと対応しています。
on:
workflow_call:
inputs:
env:
required: true
type: string
description: "Environment name"
account_id:
required: true
type: string
description: "Account ID for deployment"
deploy_role:
required: true
type: string
description: "IAM role ARN for deploy app1"
deploy_all:
required: false
type: boolean
default: false
description: "Deploy all components regardless of diff"
この標準化により、新規サービス追加時のパターンが明確 になります。
3. ドキュメントの充実
ここまでの内容を開発ガイドラインとしてまとめ、チームメンバーに共有します。
- 3 層アーキテクチャの概要と各層の責務
- 環境別トリガー管理の方針
- 命名規則
- 差分ベースデプロイの仕組み
- 標準インターフェース
- 新規サービス追加方法
- 検証方法
これにより、チーム全体で 一貫した実装方針を共有 できます。
導入の背景・解決したかった問題
導入背景
ツール導入前の課題
シンプルフォームでは、プロダクトのコード管理に GitHub を利用しており、アプリケーション・インフラの自動テストやデプロイに GitHub Actions を CI/CD ツールとして使っています。プロダクトが成長するにつれコードも大きくなり、それに伴って GitHub Actions を構成するワークフロー、actions も増えてきました。GitHub Actions はこう構成すれば良い、といったようなプラクティスやフレームワークが無いので、思うがままに作ってしまうと複雑な構成となってしまいがちだと思います。
それにより、以下のような課題が発生していました。
- メンテナンス負荷・認知負荷の課題
- 環境ごとに似たようなワークフローが存在しており、bump up 等のちょっとした修正にもメンテナンス工数が掛かる。
- ワークフローの構造がアプリケーション・機能ごとに異なっており、認知負荷が高い。
- 環境 x アプリケーション・機能分のワークフローがあることで、結果かなりの数のワークフローが存在する状況で見通しが悪い (GitHub Actions のディレクトリ階層を作れない仕様が一層の拍車を掛ける)。
- トリガーが異なることにより安全なデプロイが保証されない課題
- ワークフローのトリガーが統一されておらず、意図しないタイミングでコードがデプロイされてしまう。
どのような状態を目指していたか
- 異なる環境であっても同じロジックでデプロイできるようになっており、最低限のメンテナンス工数で済む。
- アーキテクチャが統一されており、一つ理解すれば他も容易に理解できる。
- 上記 2 点により、結果見通しも良くなる。
- 環境ごとにトリガーが統一されており、安全な運用ができる。
導入の成果
改善したかった課題はどれくらい解決されたか
直接的な効果測定はできていませんが、このリファクタリングにより 57 ファイルあったワークフローファイルを 42 に減らして見通しを良くしたことに加え、共通構造を持つようにしてメンテナンス性は向上したと考えています。
どのような成果が得られたか
効果測定はまだですが、以下の効果を期待しています。
- 責務の明確な分離: 各層が単一の責務を持つ
- 再利用性の向上: Reusable Workflow と Composite Action による共通化
- 保守性の向上: 変更影響範囲が明確で、修正が容易
- 拡張性: 新規サービス追加時のパターンが明確
導入に向けた社内への説明
上長・チームへの説明
特定のリポジトリにおいては、ワークフローの数が多くメンテナンスが難しい状況であると同時に、ある時プロダクトの監視を行っているスクリプトを更新した際に意図しないタイミングでデプロイされしまいました。それを契機にエンジニアの中で再発防止が必要となり、説明と言うよりは必要性に応じ、根本的な対策として GitHub Actions のリファクタリングに着手しました。
活用方法
よく使う機能
3 層アーキテクチャのキーともなっている以下をよく使っています。
- Composite Action: 一連の処理、アクションを 1 つのアクションとしてまとめることができ、ワークフローから呼び出すことができます。3 層アーキテクチャの 3 層目で使用しており、汎用的な処理を定義するのに使っています。
- Reusable Workflows: 再利用可能なワークフローを 1 つのジョブとして定義することができ、他のワークフローから呼び出すことができます。3 層アーキテクチャの 2 層目で使用しており、各環境で共通する処理を定義するのに使っています。
- tj-actions/changed-files: デプロイ要否の判断やデプロイ対象の選別に重宝している action です。あらゆるトリガーで使用できるため、様々なトリガーから呼び出される Reusable Workflow 層の差分チェックで利用しており、3 層アーキテクチャを実現するための重要な要素の一つです。同様の action は他にもありますが、使い勝手が良く定期的にメンテナンスされていることから利用しています。
ツールの良い点
- コードと一緒に管理できる: コードと同じリポジトリで、同じくコードとして管理できる点が良いです。YAML ファイルを配置するだけで容易に使えるので、初めてでも習得がしやすいです。
- 実行進捗が可視化でき、実行時間が分かりやすい: 特別な設定をしなくても、ジョブの実行フローや依存関係が可視化され、進捗・実行時間を自動で出してくれるので分かりやすいです。
- 公開されている action が豊富で、他ツールとの連携がしやすい: AWS や Slack はもちろん、AI ツールも公開されている action 1 つで導入でき、様々なツールとの連携が簡単です。
ツールの課題点
- テストが困難: 本番環境向けのデプロイワークフローなどはそのままテストできないため、テストのためにデプロイ先を開発環境に書き換えたり、差分を発生させるためにダミーのコードを埋め込んだりとテストが面倒です。また、通常は main ブランチにマージしないと実行できない点もテストを困難にしている要因の一つです。テスト負荷を多少なりとも低減するために、以下を利用しています。
- act: GitHub Actions をローカルで実行するためのツールです。
- GitHub workflow dispatchをデフォルトブランチ以外で実行する: main ブランチにマージしなくても GitHub Actions を実行するための Tips です。
- ディレクトリで階層を作れない: コード整理の手段としてサブディレクトリでの構造化は単純かつ有効な方法ですが、GitHub Actions ではそれができません。全てのワークフローファイルを
.github/workflows直下に配置しなければならず、命名規則を駆使するしかない点が大変です。Discussions で議論されてはいますが、2026 年 1 月現在実装の目処は立っていません。
ツールを検討されている方へ
GitHub Actions は始めやすい一方で、整理手法は利用者に委ねられるため、アーキテクチャ設計をしておくことをお薦めします。このレビューがそのための一助になれば幸いです。
今後の展望
今回は特定のリポジトリを対象にリファクタリングを行いました。今後は、社内のリポジトリ全体にも同様の思想を展開するとともに、共通する処理を 1 つにまとめて CI/CD の運用容易性向上、認知負荷の低減を推進したいと考えています。
シンプルフォーム株式会社 / Jun Irie
EM / EM / 従業員規模: 101名〜300名 / エンジニア組織: 11名〜50名
2011年に日立製作所に入社。自社ソフト開発に携わったのち公共分野のSEとして主にクラウドのアーキテクト・コンサルを経験。約1年半の業務委託期間を経て、2024年3月より現職。
よく見られているレビュー
シンプルフォーム株式会社 / Jun Irie
EM / EM / 従業員規模: 101名〜300名 / エンジニア組織: 11名〜50名
2011年に日立製作所に入社。自社ソフト...
レビューしているツール
目次
- アーキテクチャ
- 導入の背景・解決したかった問題
- 活用方法



