GitHub Actionsのモジュール化とは?
GitHub Actionsのモジュール化とは、繰り返し使用されるワークフローの処理を独立したパーツに分割し、再利用可能にする技術です。これにより、コードの重複を減らし、メンテナンスを簡単にし、チーム全体で効率的な開発を実現できます。
例えば、複数のプロジェクトで同じテスト手順やデプロイ処理を行う場合、毎回同じコードを書く代わりに、一度作成したモジュールを呼び出すだけで済むようになります。
なぜモジュール化が重要なのか?
1. コードの重複を削減
複数のワークフローで同じ処理を書く必要がなくなり、開発効率が向上します。
2. メンテナンスの簡素化
修正が必要になった場合、モジュール化された部分を一箇所修正するだけで、すべての利用箇所に反映されます。
3. チーム間での共有
作成したモジュールをチームメンバーと共有することで、開発の標準化と品質向上が図れます。
4. エラーの削減
テスト済みのモジュールを再利用することで、新しいワークフローでのエラー発生率を低減できます。
GitHub Actionsモジュール化の主な手法
1. Composite Actions(複合アクション)
複数のステップをまとめて一つのアクションとして定義する方法です。最も基本的で理解しやすいモジュール化手法です。
基本的な複合アクションの作成例
# .github/actions/setup-node/action.yml
name: 'Node.js セットアップ'
description: 'Node.jsとパッケージのインストールを行います'
inputs:
node-version:
description: 'Node.jsのバージョン'
required: false
default: '18'
cache-key:
description: 'キャッシュキー'
required: false
default: 'npm-cache'
runs:
using: 'composite'
steps:
- name: Node.jsセットアップ
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: 'npm'
- name: 依存関係インストール
run: npm ci
shell: bash
- name: キャッシュ保存
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ inputs.cache-key }}-${{ hashFiles('**/package-lock.json') }}
複合アクションの使用例
# .github/workflows/test.yml
name: テスト実行
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: コードチェックアウト
uses: actions/checkout@v4
- name: Node.js環境構築
uses: ./.github/actions/setup-node
with:
node-version: '20'
cache-key: 'test-cache'
- name: テスト実行
run: npm test
2. Reusable Workflows(再利用可能ワークフロー)
ワークフロー全体を再利用可能にする手法です。複数のジョブを含む複雑な処理を標準化したい場合に適しています。
再利用可能ワークフローの作成例
# .github/workflows/reusable-test.yml
name: 再利用可能テストワークフロー
on:
workflow_call:
inputs:
environment:
required: true
type: string
description: '実行環境'
node-version:
required: false
type: string
default: '18'
description: 'Node.jsバージョン'
outputs:
test-result:
description: 'テスト結果'
value: ${{ jobs.test.outputs.result }}
jobs:
test:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
outputs:
result: ${{ steps.test.outputs.result }}
steps:
- name: コードチェックアウト
uses: actions/checkout@v4
- name: Node.js環境構築
uses: ./.github/actions/setup-node
with:
node-version: ${{ inputs.node-version }}
- name: リント実行
run: npm run lint
- name: テスト実行
id: test
run: |
npm test
echo "result=success" >> $GITHUB_OUTPUT
- name: カバレッジレポート生成
run: npm run coverage
- name: テスト結果アップロード
uses: actions/upload-artifact@v3
with:
name: test-results-${{ inputs.environment }}
path: coverage/
再利用可能ワークフローの呼び出し例
# .github/workflows/ci.yml
name: CI パイプライン
on: [push, pull_request]
jobs:
test-development:
uses: ./.github/workflows/reusable-test.yml
with:
environment: 'development'
node-version: '18'
test-production:
uses: ./.github/workflows/reusable-test.yml
with:
environment: 'production'
node-version: '20'
deploy:
needs: [test-development, test-production]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: デプロイ実行
run: echo "テスト完了、デプロイを実行します"
3. External Actions(外部アクション)
独立したリポジトリでアクションを作成し、複数のプロジェクトから利用する方法です。組織全体での標準化に最適です。
外部アクションの作成例
# 独立リポジトリ:my-org/common-actions
# action.yml
name: 'データベースセットアップ'
description: 'テスト用データベースの起動と初期化'
inputs:
database-type:
description: 'データベースタイプ (mysql, postgres)'
required: true
database-version:
description: 'データベースバージョン'
required: false
default: 'latest'
runs:
using: 'composite'
steps:
- name: データベース起動
run: |
if [ "${{ inputs.database-type }}" == "mysql" ]; then
docker run -d --name test-db \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=testdb \
-p 3306:3306 \
mysql:${{ inputs.database-version }}
elif [ "${{ inputs.database-type }}" == "postgres" ]; then
docker run -d --name test-db \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=testdb \
-p 5432:5432 \
postgres:${{ inputs.database-version }}
fi
shell: bash
- name: データベース接続待機
run: |
for i in {1..30}; do
if [ "${{ inputs.database-type }}" == "mysql" ]; then
if docker exec test-db mysql -uroot -proot -e "SELECT 1" >/dev/null 2>&1; then
echo "MySQLが利用可能になりました"
break
fi
elif [ "${{ inputs.database-type }}" == "postgres" ]; then
if docker exec test-db pg_isready >/dev/null 2>&1; then
echo "PostgreSQLが利用可能になりました"
break
fi
fi
echo "データベース起動を待機中... ($i/30)"
sleep 2
done
shell: bash
外部アクションの使用例
# 任意のプロジェクトから使用
name: アプリケーションテスト
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: データベース環境構築
uses: my-org/common-actions@v1
with:
database-type: 'postgres'
database-version: '15'
- name: アプリケーションテスト
run: npm test
実践的なモジュール化戦略
1. 段階的なモジュール化アプローチ
いきなり全てをモジュール化するのではなく、段階的に進めることが成功の鍵です。
フェーズ1:重複処理の特定
# 現在のワークフローで重複している処理を特定
- Node.js セットアップ + npm install
- Docker イメージビルド
- テスト実行 + カバレッジ生成
- Slack通知
フェーズ2:複合アクション化
# .github/actions/notify-slack/action.yml
name: 'Slack通知'
description: 'ビルド結果をSlackに通知します'
inputs:
webhook-url:
description: 'Slack Webhook URL'
required: true
status:
description: 'ビルドステータス (success, failure, cancelled)'
required: true
job-name:
description: 'ジョブ名'
required: false
default: 'ビルド'
runs:
using: 'composite'
steps:
- name: Slack通知送信
run: |
if [ "${{ inputs.status }}" == "success" ]; then
COLOR="good"
EMOJI=":white_check_mark:"
MESSAGE="${{ inputs.job-name }}が成功しました"
elif [ "${{ inputs.status }}" == "failure" ]; then
COLOR="danger"
EMOJI=":x:"
MESSAGE="${{ inputs.job-name }}が失敗しました"
else
COLOR="warning"
EMOJI=":warning:"
MESSAGE="${{ inputs.job-name }}がキャンセルされました"
fi
curl -X POST -H 'Content-type: application/json' \
--data "{
\"attachments\": [{
\"color\": \"$COLOR\",
\"text\": \"$EMOJI $MESSAGE\"
}]
}" \
${{ inputs.webhook-url }}
shell: bash
フェーズ3:再利用可能ワークフロー化
# .github/workflows/deploy-template.yml
name: デプロイテンプレート
on:
workflow_call:
inputs:
environment:
required: true
type: string
app-name:
required: true
type: string
docker-tag:
required: false
type: string
default: 'latest'
secrets:
DEPLOY_TOKEN:
required: true
SLACK_WEBHOOK:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Docker ログイン
run: echo ${{ secrets.DEPLOY_TOKEN }} | docker login -u oauth2accesstoken --password-stdin
- name: アプリケーションデプロイ
run: |
docker pull myregistry/${{ inputs.app-name }}:${{ inputs.docker-tag }}
docker run -d --name ${{ inputs.app-name }}-${{ inputs.environment }} \
myregistry/${{ inputs.app-name }}:${{ inputs.docker-tag }}
- name: デプロイ結果通知
if: always()
uses: ./.github/actions/notify-slack
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
status: ${{ job.status }}
job-name: '${{ inputs.app-name }} デプロイ (${{ inputs.environment }})'
2. パラメータ化による柔軟性の確保
モジュールを作成する際は、適切なパラメータを設定することで、様々な状況に対応できるようにします。
# .github/actions/build-and-push/action.yml
name: 'Docker ビルド & プッシュ'
description: 'Dockerイメージのビルドとレジストリへのプッシュ'
inputs:
dockerfile:
description: 'Dockerfileのパス'
required: false
default: './Dockerfile'
context:
description: 'ビルドコンテキスト'
required: false
default: '.'
registry:
description: 'コンテナレジストリURL'
required: true
image-name:
description: 'イメージ名'
required: true
tags:
description: 'イメージタグ (カンマ区切り)'
required: false
default: 'latest'
build-args:
description: 'ビルド引数 (KEY=VALUE形式、改行区切り)'
required: false
push:
description: 'レジストリにプッシュするか'
required: false
default: 'true'
outputs:
image-digest:
description: 'ビルドしたイメージのダイジェスト'
value: ${{ steps.build.outputs.digest }}
runs:
using: 'composite'
steps:
- name: Dockerビルドセットアップ
uses: docker/setup-buildx-action@v3
- name: イメージビルド
id: build
uses: docker/build-push-action@v5
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile }}
push: ${{ inputs.push }}
tags: ${{ inputs.registry }}/${{ inputs.image-name }}:${{ inputs.tags }}
build-args: ${{ inputs.build-args }}
cache-from: type=gha
cache-to: type=gha,mode=max
ベストプラクティス
1. 命名規則の統一
- アクション名: 動詞-名詞形式(例:setup-node, build-docker, deploy-app)
- 入力パラメータ: ケバブケース(例:node-version, database-type)
- 出力: 結果を表す名詞(例:test-result, image-digest)
2. ドキュメント化の徹底
# README.mdの例
# Setup Node.js Action
## 概要
Node.js環境のセットアップと依存関係のインストールを行います。
## 使用方法
```yaml
- name: Node.js環境構築
uses: ./.github/actions/setup-node
with:
node-version: '18' # Node.jsバージョン (デフォルト: 18)
package-manager: 'npm' # パッケージマネージャー (npm, yarn, pnpm)
cache-key: 'my-cache' # キャッシュキー (デフォルト: auto-generated)
```
## 入力パラメータ
| パラメータ | 必須 | デフォルト | 説明 |
|------------|------|------------|------|
| node-version | いいえ | '18' | 使用するNode.jsのバージョン |
| package-manager | いいえ | 'npm' | パッケージマネージャー (npm/yarn/pnpm) |
| cache-key | いいえ | auto | キャッシュキー |
## 出力
| 出力名 | 説明 |
|--------|------|
| cache-hit | キャッシュがヒットした場合はtrue |
3. バージョン管理戦略
- セマンティックバージョニングを採用
- メジャーバージョンのタグを並行で管理
- 変更ログの維持
# バージョンタグの例
git tag v1.0.0 # 初回リリース
git tag v1 # メジャーバージョンタグ
git tag v1.1.0 # 機能追加
git tag v1 # メジャーバージョンタグ更新
git tag v2.0.0 # 破壊的変更
git tag v2 # 新しいメジャーバージョンタグ
4. エラーハンドリング
# エラーハンドリングの例
- name: テスト実行
id: test
run: |
set -e # エラー時に即座に終了
if ! npm test; then
echo "テストが失敗しました"
echo "::error::テスト実行中にエラーが発生しました"
exit 1
fi
echo "::notice::すべてのテストが正常に完了しました"
echo "result=success" >> $GITHUB_OUTPUT
shell: bash
- name: エラー時の通知
if: failure()
uses: ./.github/actions/notify-slack
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
status: 'failure'
job-name: 'テスト実行'
まとめ
GitHub Actionsのモジュール化は、開発チームの生産性を大幅に向上させる重要な技術です。この記事で紹介した手法を参考に、以下のステップで段階的にモジュール化を進めてください:
- 現在のワークフローを分析し、重複する処理を特定する
- 複合アクションから始めて、基本的なモジュール化を実践する
- 再利用可能ワークフローで複雑な処理を標準化する
- 外部アクションで組織全体での共有を実現する
- 継続的な改善でモジュールの品質を向上させる
適切なモジュール化により、コードの品質向上、開発速度の向上、メンテナンスコストの削減を実現し、より効率的なCI/CDパイプラインを構築できるでしょう。
次回は、実際のプロジェクトでのモジュール化事例や、より高度なテクニックについて詳しく解説する予定です。