📚

CI/CDとは?【テスト・デプロイ】

に公開

0. はじめに

この記事は、駆け出しバックエンドエンジニアによる学習記録です。
初学で調べたことをまとめたものなので、多少間違った説明もあるかもしれません。ご了承くださいmm

1. CIとは?

CI(Continuous Integration、継続的インテグレーション)は、「ソフトウェア開発における自動化されたビルド・テスト・統合の仕組み」を指す。

概要

  • 目的:開発チームが頻繁にコードを統合し、早期にバグを発見するための仕組み
  • 基本の流れ:
    1. 開発者がコードをGitなどのリポジトリにプッシュ
    2. CIツール(例:GitHub Actions, Jenkins, GitLab CI)が自動でビルドを実行
    3. 単体テストや統合テストを自動実行
    4. 結果(成功/失敗)を開発者に通知

これにより、コードが常に動作する状態(“緑の状態”)に保たれる。

メリット

  • 早期バグ検出:小さい変更ごとにテストするので、不具合の原因が特定しやすい
  • 品質向上:テストが自動で走るため、人為的ミスを減らせる
  • 開発スピード向上:統合時のコンフリクトやビルド失敗を事前に防げる
  • リリースの安定:常に動く状態が維持されるため、本番リリースが安心

CIツール

  • GitHub Actions(GitHubリポジトリと連携しやすい)
  • Jenkins(自前サーバーで運用可能、柔軟性が高い)
  • GitLab CI/CD(GitLabと統合済み)

2. CDとは?

CI(Continuous Integration)とセットでよく出てくるCDは、文脈によって2通りの意味がある:

CDの2つの意味

  • Continuous Delivery(継続的デリバリー)
    • 本番リリース直前までを自動化(ビルド・テスト・ステージング環境へのデプロイ)
    • 使われ方: 「レビューOKならボタン1つで本番リリースできる状態」
  • Continuous Deployment(継続的デプロイ)
    • 本番リリースまで完全自動化
    • 使われ方: 「テストが通ったら自動で本番へリリース」

ポイント

  • まずは、CIを導入 → テストが常にグリーンになる環境を作る
  • その後、CDを導入 → デプロイも自動化するとチーム全体が早く動ける

3. CIの実践

0) 前提

  • リポジトリがGitHub上にある
  • gradlewgradle/wrapper/*がコミット済み(ローカルで./gradlew testが通っている)

1) ワークフローを作る

リポジトリ直下に以下のパスでファイルを新規作成:

.github/workflows/ci.yml

ci.ymlの中身(例)

name: CI

on:
  push:
    branches: [ "**" ]
  pull_request:

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    permissions:
      contents: read

    defaults:
      run:
        working-directory: backend  # gradlewがbackend/に配置されている

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Validate Gradle Wrapper
        uses: gradle/actions/wrapper-validation@v3

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "21"
          cache: gradle  # Gradle依存キャッシュ

      # (任意)環境変数をここで渡す。必要ならSecretsに入れて参照
      # - name: Set env
      #   run: echo "JWT_SECRET=local-test-secret" >> $GITHUB_ENV

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build & Test
        run: ./gradlew clean build test --no-daemon

      # 失敗時にテストレポートを見れるようアーティファクト収集
      - name: Upload test reports (always)
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-reports
          path: |
            **/build/reports/tests/test
            **/build/test-results/test
            **/build/reports/jacoco/**
          if-no-files-found: ignore

これでpush/prのたびに./gradlew clean build testが走る。
Testcontainersを使っていても追加設定は不要(Ubuntu runnerにDockerデーモンが入っているため)。

2) build.gradleに設定追加

build.gradle(Groovy)にJaCoCoを追加。まずは可視化→後で閾値を上げる方針が実務的。

plugins {
  id 'jacoco'
}

jacoco {
  toolVersion = "0.8.10"
}

test {
  useJUnitPlatform()
  finalizedBy jacocoTestReport
}

jacocoTestReport {
  dependsOn test
  reports {
    xml.required = true
    html.required = true
  }
}

// 閾値(最初は緩めでOK。CIで赤にしたければ有効化)
jacocoTestCoverageVerification {
  violationRules {
    rule {
      limit {
        counter = 'LINE'
        value = 'COVEREDRATIO'
        minimum = 0.80 // line coverage 80%
      }
    }
  }
}
// check.dependsOn jacocoTestCoverageVerification

CIのアーティファクトにHTMLレポートが入るので、失敗時でも詳細をDLして確認できる。

4. 感想

今回初めてCIを実装するにあたってCI/CDについて調べてまとめてみた。
実際に手を動かして実践したことで、ざっくり概要は掴めたと思う。
実務ではもっとやることがあると思うが、今回はとりあえずここまでやってみた感じ。
ここではGitHub Actionsを使ったが、新卒の会社ではJenkinsを使っていたことを思い出した。
個人開発ではCDまでは必要ないと思うけど、概要くらいは知っとくべきだと思った。よく頑張った。

Discussion