Skip to content

CICDの書き方

CI/CDの書き方は、どのCI/CDツールを使用するかによって大きく異なりますが、共通する基本的な考え方と構成要素があります。CI/CDパイプラインをコードとして定義する「Pipeline as Code」が主流であり、通常はYAML形式のファイルで記述されます。

📋 CI/CDパイプラインの基本構成

Section titled “📋 CI/CDパイプラインの基本構成”

CI/CDの書き方で最も重要なのは、パイプラインを定義することです。パイプラインは、ソースコードがコミットされてからデプロイされるまでのステップを順番に実行する自動化されたワークフローです。このワークフローは、通常、以下のステージ(段階)で構成されます。

  • トリガー (Trigger): パイプラインがいつ実行を開始するかを定義します。最も一般的なトリガーは、Gitリポジトリへのコードのプッシュやプルリクエストの作成です。

  • ステージ (Stages): パイプラインを構成する論理的なグループです。例えば、「ビルド」「テスト」「デプロイ」といったステージに分けられます。ステージは通常、順番に実行されます。

  • ジョブ (Jobs): 各ステージ内で実行される個別のタスクの集合です。例えば、「ビルドステージ」には「依存関係のインストール」や「コードのコンパイル」といったジョブが含まれます。

  • ステップ (Steps): ジョブを構成する最小単位のコマンドやアクションです。シェルコマンドを実行したり、特定のツールを呼び出したりします。

各ツールの設定ファイルは、上記の基本構成を反映していますが、その構文や用語には違いがあります。

GitHubリポジトリに統合されているため、設定が非常にシンプルです。.github/workflowsディレクトリにYAMLファイルを作成してパイプラインを定義します。

  • 用語と構文:
    • name: ワークフローの名前。
    • on: トリガー。例えば、pushpull_request
    • jobs: 実行するジョブの集合。
    • runs-on: ジョブを実行する環境(例: ubuntu-latest)。
    • steps: ジョブ内の各ステップ。usesで既存のアクションを利用したり、runでコマンドを実行したりします。
name: CI/CD Pipeline
on:
push:
branches:
- main
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test

GitLabに統合されており、プロジェクトのルートディレクトリに.gitlab-ci.ymlというYAMLファイルを配置します。

  • 用語と構文:
    • stages: パイプラインのステージを定義。
    • job_name: ジョブの名前。
    • script: 実行するコマンド。
    • only / except: どのブランチでジョブを実行するかを制御します。
    • image: ジョブを実行するDockerイメージを指定します。
stages:
- build
- test
build:
stage: build
script:
- echo "Building the application..."
- npm install
- npm run build
test:
stage: test
script:
- echo "Running tests..."
- npm test

CI/CDの書き方のベストプラクティス

Section titled “CI/CDの書き方のベストプラクティス”
  • Pipeline as Codeを徹底する: パイプラインの定義は、バージョン管理システム(Gitなど)で管理しましょう。これにより、変更履歴の追跡や共同作業が容易になります。

  • パイプラインの構造をシンプルに保つ: 複雑な処理は、シェルスクリプトや外部ツールに任せるなどして、パイプラインのYAMLファイル自体はシンプルで読みやすく保つことが重要です。

  • 環境変数を活用する: パスワードやAPIキーなどの機密情報は、ハードコーディング(直接コードに記述)せず、環境変数やシークレットとして管理しましょう。

  • ジョブの並列実行: 関連性のないジョブは並列で実行することで、パイプライン全体の実行時間を短縮できます。

  • キャッシュを有効活用する: 依存関係のインストールなど、時間がかかるステップの結果をキャッシュすることで、パイプラインの実行を高速化できます。

大規模開発では、1つの長いパイプラインではなく、複数のパイプラインを連携させることで、管理しやすさと柔軟性を高めます。

  1. パイプラインの多段階化 🪜

    • シンプルに「ビルド」と「テスト」をまとめるのではなく、より多くのステージに分割します。これにより、各ステージの役割が明確になり、問題の特定が容易になります。

    • ステージの例: lint (静的コード解析) → build (ビルド) → unit_test (単体テスト) → integration_test (結合テスト) → deploy_to_staging (ステージング環境へのデプロイ) → manual_approval (手動承認) → deploy_to_production (本番環境へのデプロイ)

    • この構成では、自動化できる部分は自動化しつつ、本番デプロイ前の承認プロセスなど、人による判断を組み込むことができます。

  2. パイプラインのモジュール化 🧩

    • パイプラインの定義ファイルが長大になるのを避けるため、共通の処理を再利用可能なコンポーネントとして分割します。これにより、コードの重複を防ぎ、メンテナンス性を向上させます。

    • 例: GitHub Actionsでの再利用可能なワークフロー

      • 共通のビルドやテストのジョブを、別のYAMLファイルとして定義し、メインのワークフローから呼び出します。
      reusable-build-workflow.yml (共通ビルド処理)
      name: Reusable Build
      on:
      workflow_call:
      inputs:
      node_version:
      required: true
      type: string
      jobs:
      build:
      runs-on: ubuntu-latest
      steps:
      - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
      node-version: ${{ inputs.node_version }}
      - name: Install dependencies
      run: npm install
      - name: Build application
      run: npm run build
      main-pipeline.yml (メインのパイプライン)
      name: Main CI/CD Pipeline
      on:
      push:
      branches:
      - main
      jobs:
      call-build:
      uses: ./reusable-build-workflow.yml
      with:
      node_version: '16'
  3. 動的な設定の活用 ⚙️

    • 複数の環境(開発、ステージング、本番)を同じパイプラインで管理するため、環境固有の設定を変数で制御します。

    • 例: GitLab CI/CDでの動的な設定

      • rulesを使って、ブランチ名に基づいてジョブの実行を制御します。
      deploy_to_staging:
      stage: deploy_staging
      script:
      - echo "Deploying to staging environment..."
      rules:
      - if: '$CI_COMMIT_BRANCH == "develop"'
      when: on_success
      deploy_to_production:
      stage: deploy_production
      script:
      - echo "Deploying to production environment..."
      rules:
      - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual # 手動での承認を必要とする
  4. パイプラインの分散とモノレポ戦略 🌳

    • モノレポ(単一リポジトリ)で複数のマイクロサービスを管理する場合、すべてのコード変更で全パイプラインを動かすのは非効率です。変更されたコードパスに基づいて、関連するパイプラインのみを実行するように設定します。

    • 例: GitHub Actionsでのパスフィルタリング

      on:
      push:
      paths:
      - 'services/auth-service/**'

      この設定により、services/auth-serviceディレクトリ内のファイルが変更された場合にのみ、パイプラインが起動します。

コンテナを利用したCI/CDの書き方 🐳

Section titled “コンテナを利用したCI/CDの書き方 🐳”

CI/CDパイプラインは、多くの場合、Dockerなどのコンテナ技術と組み合わせて使用されます。コンテナを使うことで、ビルド環境やテスト環境の再現性と分離性が格段に向上します。

  1. ジョブごとの環境定義

    • コンテナイメージをCI/CDジョブの実行環境として指定することで、ビルドやテストに必要なツール(特定の言語のバージョン、ライブラリ、データベースなど)をあらかじめ用意したクリーンな環境で実行できます。これにより、「開発者のPCでは動くのにCI/CD環境では動かない」といった問題を解消できます。

    • 例: GitLab CI/CDでのDockerイメージ指定

      stages:
      - build
      build_job:
      stage: build
      image: node:16-alpine # ジョブの実行にNode.js v16のコンテナを使用
      script:
      - npm install
      - npm run build
  2. ビルドの高速化

    • マルチステージビルドやレイヤーキャッシュなどのDockerの機能を活用することで、ビルド時間を短縮できます。CI/CDツールも、Dockerイメージのレイヤーをキャッシュする機能を持っていることが多いため、これを有効に利用することで、依存関係の再インストールなど、時間のかかるステップをスキップできます。

CI/CDパイプラインが複雑になると、その設定ファイル自体にバグが含まれることがあります。デプロイの失敗やセキュリティの脆弱性につながる可能性があるため、パイプラインの定義ファイルをテストすることが重要になります。

  • 静的解析:

    • 設定ファイルの構文エラーや、ベストプラクティスからの逸脱を検出するツールを使用します。
    • yamllint: YAMLファイルの構文チェック
    • actionlint: GitHub Actionsのワークフローの構文とベストプラクティスチェック
  • 動的な検証:

    • ローカル環境でパイプラインをシミュレーションし、本番環境で実行する前に動作を確認するツールもあります。
    • act: GitHub Actionsのワークフローをローカルで実行できるツール。

パイプラインのテストをCI/CDプロセス自体に組み込む(CI/CD for CI/CD)ことで、より信頼性の高い自動化プロセスを構築できます。これは、大規模な開発チームにとって、デプロイメントの安全性を確保するための重要なステップです。

CI/CDを組織に定着させるためのポイント

Section titled “CI/CDを組織に定着させるためのポイント”

技術的な側面だけでなく、開発チーム全体の文化やプロセスを変えていくことが、CI/CD導入の成功には不可欠です。

  1. スモールスタートで始める 🚀

    • いきなり複雑なパイプラインを構築しようとせず、まずは最もシンプルなプロセスから自動化してみましょう。例えば、コードをプッシュしたときに自動でビルドとテストが走るだけのCIパイプラインから始め、徐々にデプロイの自動化を追加していくのが効果的です。チームがCI/CDのメリットを実感することで、自然と次のステップへ進む意欲が生まれます。
  2. 責任を共有する 🤝

    • CI/CDは、開発チーム全体で責任を持って運用すべきものです。パイプラインの定義ファイルは、アプリケーションコードと同じように全員でレビューし、改善していく文化を育てましょう。開発者自身がパイプラインを修正できるようにすることで、DevOpsの考え方がチームに浸透します。
  3. 失敗から学ぶ文化を醸成する 🧠

    • CI/CDパイプラインは失敗することもあります。重要なのは、失敗をネガティブなものと捉えないことです。

      • なぜ失敗したのか?
      • どうすれば再発を防げるか?
      • パイプラインをどう改善できるか?
    • こういった議論を積極的に行うことで、プロセス全体が常に改善され、より堅牢なシステムが構築されていきます。失敗のログや通知をチーム全体に共有し、みんなで解決策を考えることが大切です。

  4. 継続的な改善を続ける 📈

    • CI/CDパイプラインは一度作って終わりではありません。

      • ビルド時間が遅くなったら、キャッシュ設定を見直す。
      • 新しいテストツールを導入したら、パイプラインに組み込む。
      • デプロイ戦略を変更したら、パイプラインの定義を更新する。
    • このように、パイプライン自体も継続的に改善していくことが、開発プロセスの進化を支えます。

これで、CI/CDの「書き方」から「文化」まで、包括的な内容が網羅されたと思います。CI/CDは単なるツールではなく、開発チームの働き方そのものを変える強力なアプローチです。