メインコンテンツまでスキップ

パイプライン設計

このドキュメントの目的

CI/CDパイプラインの構造と設計パターンを理解し、効率的で保守しやすいパイプラインを設計できるようになることが目標です。

IDサービスを題材にした具体例を使用しますが、設計原則自体はあらゆるSaaSに共通して適用できます。


パイプラインの構造

ステージ・ジョブ・ステップの関係

パイプラインは3つの階層で構成されます。

パイプライン (Pipeline)
├── ステージ 1: Lint & Build
│ ├── ジョブ A: Lint
│ │ ├── ステップ 1: チェックアウト
│ │ ├── ステップ 2: 依存関係キャッシュ復元
│ │ └── ステップ 3: Lint実行
│ └── ジョブ B: Build
│ ├── ステップ 1: チェックアウト
│ ├── ステップ 2: Gradleビルド
│ └── ステップ 3: アーティファクト保存
├── ステージ 2: Test
│ ├── ジョブ C: Unit Test
│ └── ジョブ D: Integration Test
├── ステージ 3: Package
│ └── ジョブ E: Docker Image Build & Push
└── ステージ 4: Deploy
├── ジョブ F: Deploy to Staging
└── ジョブ G: Deploy to Production (手動承認)
階層定義特徴
ステージパイプラインの論理的な段階順序制御(前ステージの完了が次の条件)
ジョブステージ内の実行単位同一ステージ内で並列実行可能
ステップジョブ内の個々のコマンド順次実行

典型的なステージ設計

ステージの全体フロー

┌────────┐   ┌────────┐   ┌────────┐   ┌────────┐   ┌────────┐
│ Lint │──▶│ Build │──▶│ Test │──▶│Package │──▶│ Deploy │
│ │ │ │ │ │ │ │ │ │
│・静的 │ │・コンパイ│ │・ユニット│ │・Docker │ │・Staging│
│ 解析 │ │ ル │ │・統合 │ │ Image │ │・Prod │
│・フォーマ│ │・依存 │ │・E2E │ │・レジスト│ │ │
│ ット │ │ 解決 │ │ │ │ リ │ │ │
└────────┘ └────────┘ └────────┘ └────────┘ └────────┘
数秒 数分 数分〜 数分 数分
数十分 数十分

各ステージの詳細

ステージ1: Lint(静的解析)

コードの品質とスタイルを検証します。ビルドの前に実行することで、スタイル違反を早期に検出します。

チェック項目ツール例目的
コードフォーマットSpotless, Prettierコーディング規約の統一
静的解析SpotBugs, ESLint潜在的バグの検出
セキュリティスキャンTrivy, Dependabot脆弱性のある依存ライブラリの検出
型チェックTypeScript compiler型の整合性検証

ステージ2: Build(ビルド)

ソースコードをコンパイルし、依存関係を解決します。

IDサービスの場合:

ソースコード
↓ ./gradlew build -x test
JARファイル (idp-server.jar)
↓ アーティファクトとして保存
次のステージへ

ビルド時間短縮のポイント:

  • 依存関係のキャッシュ: ~/.gradle/caches をキャッシュして再利用
  • インクリメンタルビルド: 変更のあったモジュールのみ再ビルド
  • テストの分離: ビルドとテストを別ステージに分けている場合に限り、ビルドステージでは -x test でテストをスキップし、後続のテストステージで実行する(単一ステージの場合はテストをスキップしない)

ステージ3: Test(テスト)

自動テストを実行し、品質を検証します。テスト戦略の詳細はCI/CDにおけるテスト戦略を参照してください。

ステージ4: Package(パッケージング)

テストを通過したアーティファクトをデプロイ可能な形式にパッケージングします。

IDサービスの場合:

JARファイル (前ステージのアーティファクト)
↓ Docker build
Docker Image (idp-server:v1.2.3)
↓ Docker push
Container Registry (ECR / GCR / Docker Hub)

ステージ5: Deploy(デプロイ)

パッケージをターゲット環境にデプロイします。デプロイ戦略の詳細はデプロイ戦略を参照してください。


並列化と依存関係

ジョブの並列実行

同一ステージ内のジョブは並列実行できます。適切な並列化により、パイプライン全体の実行時間を短縮できます。

直列実行(遅い):
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ Lint │──▶│Build │──▶│ Unit │──▶│Integ │ 合計: 20分
│ 2分 │ │ 5分 │ │ 5分 │ │ 8分 │
└──────┘ └──────┘ └──────┘ └──────┘

並列実行(速い):
┌──────┐
│ Lint │──┐
│ 2分 │ │ ┌──────┐ ┌──────────────┐
└──────┘ ├──▶│Build │──▶│ Unit │ Integ │ 合計: 18分
┌──────┐ │ │ 5分 │ │ 5分 │ 8分 │
│SecScan│──┘ └──────┘ └──────┴───────┘
│ 3分 │ ↑ ↑
└──────┘ Lint/SecScan Unit/Integは
完了後に実行 並列実行

Fan-out / Fan-in パターン

複数のジョブに分岐(Fan-out)し、全ジョブ完了後に合流(Fan-in)するパターンです。

Fan-out / Fan-in:

┌──────────────┐
│ Build │
└──────┬───────┘

┌─────────────┼─────────────┐ Fan-out
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Unit Test │ │ Integ Test │ │ E2E Test │
│ (Java 21) │ │ (PostgreSQL)│ │ (Docker) │
└─────┬──────┘ └─────┬──────┘ └──────┬─────┘
│ │ │
└──────────────┼───────────────┘ Fan-in


┌──────────────┐
│ Package │
└──────────────┘

マトリクスビルド

複数の環境・バージョンの組み合わせでテストを実行します。

JavaDBOS
21PostgreSQL 15Ubuntu
21MySQL 8Ubuntu

IDサービスの場合: PostgreSQLとMySQL両方をサポートするため、マトリクスビルドで両DBに対してテストを実行します。


アーティファクト管理

ビルド成果物の種類

アーティファクト保存先用途
JARファイルCI一時ストレージステージ間の受け渡し
Docker ImageContainer Registryデプロイ対象
テストレポートCI一時ストレージテスト結果の確認
カバレッジレポートCI一時ストレージ / SaaS品質メトリクスの追跡
SBOMファイルアーティファクトリポジトリソフトウェア構成管理

バージョニング戦略

タグベース:
git tag v1.2.3 → Docker Image: idp-server:v1.2.3

コミットSHAベース:
git commit abc1234 → Docker Image: idp-server:abc1234

ブランチベース:
main branch → Docker Image: idp-server:latest
feature/xyz → Docker Image: idp-server:feature-xyz
方式用途利点
セマンティックバージョン (v1.2.3)本番リリース人間が理解しやすい、互換性が明確
コミットSHA (abc1234)開発・ステージング一意性が保証される、追跡が容易
ブランチ名開発環境最新の状態を常に反映

保持ポリシー

アーティファクトの保持期間を設計します。無制限に保持するとストレージコストが増大します。

対象保持期間理由
本番リリース永久ロールバック・監査対応
ステージング30日検証期間
開発ブランチ7日短期間の検証用
テストレポート90日品質トレンド分析

パイプラインのアンチパターン

アンチパターン1: モノリシックパイプライン

NG: 1つの巨大ジョブにすべてを詰め込む

┌─────────────────────────────────────────────────────┐
│ Lint → Build → Unit Test → Integ Test → E2E Test │
│ → Docker Build → Deploy Staging → Deploy Prod │
│ │
│ 実行時間: 60分(途中で失敗すると全部やり直し) │
└─────────────────────────────────────────────────────┘

問題点:

  • 途中で失敗すると最初からやり直し
  • 並列化できない
  • どこで失敗したか分かりにくい

解決策: ステージ・ジョブに分割し、失敗箇所を特定しやすくする。

アンチパターン2: 環境依存のパイプライン

NG: 特定の環境に依存する設定

steps:
- run: /usr/local/special-tool --config /etc/myapp/config.yaml
# ↑ CIランナーに特定ツールがインストールされていることを前提

問題点:

  • CIランナーの環境変更で壊れる
  • 別のCIサービスに移行できない
  • 再現性がない

解決策: コンテナベースのジョブ実行で環境を固定する。

アンチパターン3: 秘密情報のハードコード

NG: パイプライン定義にシークレットを直接記述

steps:
- run: docker login -u admin -p MyS3cretP@ss
# ↑ 認証情報がソースコードに含まれる

問題点:

  • ソースコードに認証情報が漏洩
  • Git履歴に残り続ける
  • 権限管理ができない

解決策: CIサービスのシークレット管理機能を使用する。

アンチパターン4: テストの省略

NG: ビルド時間短縮のためにテストをスキップ

steps:
- run: ./gradlew build -x test
- run: docker build . && docker push
# ↑ テストなしで本番イメージを作成

問題点:

  • バグがそのまま本番に到達する
  • 品質の担保がない

解決策: テストは必ず実行する。時間短縮は並列化・キャッシュで対応する。

アンチパターン5: 肥大化したパイプライン定義

NG: 1000行を超えるパイプライン定義ファイル

# ci.yml - 1200行
# すべてのワークフローが1ファイルに...

問題点:

  • メンテナンスが困難
  • 変更影響の把握が難しい
  • レビューが大変

解決策: 再利用可能なワークフロー・テンプレートに分割する。


ブランチ戦略との連携

ブランチ戦略の比較

戦略ブランチ数リリース頻度複雑さ
Trunk-Based少ない(main + 短命feature)高い(日次)低い
GitHub Flow中程度(main + feature)中程度(週次)中程度
Git Flow多い(main + develop + feature + release + hotfix)低い(月次)高い

ブランチとパイプラインの対応

Trunk-Based Development:

feature ──PR──▶ main ──tag──▶ release
│ │ │
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│Lint │ │Lint │ │全テスト│
│Build │ │Build │ │Package│
│Unit │ │全テスト│ │Deploy │
└──────┘ │Package│ └──────┘
│Deploy │
│(Staging)│
└──────┘
ブランチ実行するパイプライン目的
feature/*Lint + Build + Unit Test早期フィードバック
mainFull Test + Package + Staging Deploy統合検証
tag/v*Full Test + Package + Production Deploy本番リリース

Pull Requestとの連携

Pull Requestに対してパイプラインを実行し、マージ前に品質を検証します。

Pull Request ワークフロー:

┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ PR作成 │───▶│ CI実行 │───▶│ レビュー │
│ │ │ │ │ │
│ │ │ ・Lint │ │ ・コードレビュー│
│ │ │ ・Build │ │ ・CI結果確認 │
│ │ │ ・Unit Test │ │ │
└──────────┘ └──────────────┘ └──────┬───────┘

┌────────────────────┘

┌──────────────┐
│ マージ │
│ │
│ mainブランチへ│
└──────────────┘

パイプライン設計のベストプラクティス

原則説明
高速フィードバック軽量チェック(Lint)を先に実行し、問題を早期検出
失敗の早期検出コストの低いテストから順に実行(Unit → Integ → E2E)
冪等性同じ入力で何度実行しても同じ結果になること
再現性環境に依存しない、コンテナベースの実行
最小権限各ステージに必要最小限の権限のみ付与
可観測性実行時間・成功率・失敗理由を計測・可視化

次のステップ

パイプラインの構造と設計パターンを理解しました。

次に読むべきドキュメント

  1. CI/CDにおけるテスト戦略 - テストの自動化と品質ゲート
  2. デプロイ戦略 - 安全なリリース手法

最終更新: 2026-03-04 対象: SaaS開発者・DevOpsエンジニア