CI/CD
CI/CDとは
- CI(継続的インテグレーション) = コードを push するたびに、ビルドと [[自動テスト]] を自動実行して問題を早期発見する
- CD(継続的デリバリー/デプロイ) = 検証を通ったコードを、自動で本番環境まで届ける
GitHub Actions、GitLab CI、CircleCI などのサービスで実現します。パイプラインの定義は [[YAML]] のファイルとしてリポジトリに置き、アプリのコードと同じようにレビューを通してから反映します。
# GitHub Actions の例
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:run
- run: npm run build
パイプラインの流れ
設定ファイルが表すのは、何をきっかけに、どの順で、何を実行するかという一本の流れ — パイプラインです。
| 段階 | やること | 失敗時 |
|---|---|---|
| トリガー | push・プルリクエスト・定時実行で起動 | — |
| 準備 | ソースと依存パッケージの取得 | 以降は走らない |
| 検証 | [[静的解析とリンター]]・[[自動テスト]] | マージさせない |
| ビルド | 配布できる成果物([[Docker]] イメージなど)を作る | マージさせない |
| デプロイ | 成果物を環境へ配る | 切り戻す |
押さえたいのは、ビルドは1回だけ行い、同じ成果物を各環境へ配るという原則です。環境ごとにビルドし直すと、検証したものと本番で動くものが別物になり得ます。環境で変えるのは接続先やキーなどの設定だけにします([[クラウドコンピューティング]])。
ローカルでは通るのにCIで落ちる
初学者が最初にぶつかる壁です。原因はほぼ手元とCIの環境が違うことに集約されます。
- 依存パッケージのバージョン差 — 手元には古い
node_modulesが残っている。CIではロックファイルどおりに入れ直すnpm ciを使う([[npmとパッケージ管理]]) - コミットし忘れたファイル — 手元にしか無い設定を参照している。CIはリポジトリの中身しか持たない
- OSの差 — macOSやWindowsはファイル名の大文字小文字を区別しないが、CIのLinuxは区別する。
import './Button'を./buttonと書いても手元だけは通る - 時刻と言語設定 — CIはUTCで動くことが多く、日付をまたぐ処理のテストが手元と違う結果になる
遅いパイプライン・信用されないテスト
導入して終わりではありません。放置すると効果が静かに失われる症状が2つあります。
1つ目は遅さです。実行が30分になると開発者は結果を待たず次へ移り、失敗に気づくのが翌日になります。遅れた分だけ「早期発見」の価値が削られる — キャッシュや並列実行で数分台に保つのが目安です。
2つ目はたまに落ちるテスト(flaky test)です。同じコードなのに10回に1回落ちると、赤信号を見ても「また例のやつだろう」と再実行するのが習慣になり、本物の不具合まで見逃されます。原因を直すか、いったん対象から外して別に管理します。
初学者向けポイント
- 「動くか不安だから金曜の夜にまとめてリリース」の逆。小さく頻繁に出すほうが安全という思想
- [[Git]] の push やプルリクエストが自動処理の起点(トリガー)になる
- パイプラインの中身は [[シェルとコマンドライン]] のコマンド列。ローカルで動くことが先決
効果
| Before | After |
|---|---|
| 手作業のデプロイでミスが起きる | 手順がコード化され再現可能 |
| バグの発見がリリース後 | pushの数分後にテストが検知 |
| リリースが怖い・稀 | 小さな変更を日常的に出せる |
ここから先を選ぶ地図
CI/CDは自動化の入口で、その先は多くの分野につながっています。一度に全部は要りません。いま近い群から選んでください。
なぜ自動化するのかを知る
考え方を先に押さえると設定ファイルの意味が変わって見えます。[[DevOps]] は開発と運用の壁をなくす文化そのもので、CI/CDはその中核の実践。[[アジャイル開発]] は「短く回して確かめる」という上位の考え方、[[ブランチ戦略]] は自動処理を起動するブランチとマージの取り決めです。
パイプラインの中身を組み立てる
CIが実行するのは、突き詰めれば検証とビルドです。何をどう検証するかは [[自動テスト]] が土台、書く順序を変えて設計にも効かせるのが [[テスト駆動開発]]、外部APIやDBへの依存を切り離してCIで安定に回すのが [[テストダブル(モック・スタブ)]]。成果物は [[Docker]] のイメージが定番で、その置き場と受け渡しは [[コンテナレジストリとイメージ管理]] が扱います。
本番へ安全に届ける
「テストが通った」の次は「どう切り替えるか」です。無停止と切り戻しの方式は [[デプロイ戦略]]、デプロイと公開を切り離してスイッチで止められるようにするのが [[フィーチャーフラグ]]。コードより戻しにくいDBの変更は [[スキーママイグレーション]] が扱い、届け先が [[Kubernetes]] か [[サーバーレス・Lambda]] かで手順も変わります。
パイプラインを危険物にしない
デプロイできるとは、本番の権限を持つことです。認証情報をコードから追い出す [[シークレット管理]]、その情報を有効期限つきにして漏えい被害を打ち切る [[短期クレデンシャル]]、依存ライブラリの弱点を自動検知する [[脆弱性管理とCVE]] — この3つは避けて通れません。
インフラと運用も同じ流れに乗せる
アプリだけ自動化しても、サーバー側が手作業では再現性が途切れます。構成をコードで書く [[IaC]] や設定作業を自動化する [[Ansibleと構成管理]] を同じパイプラインに乗せれば、インフラの変更もレビューを経て適用されます。さらに [[オブザーバビリティ]] まで揃うと「速く出して、早く気づく」が一周します。
複雑になってきたら
ジョブが増え、複数のプルリクエストが同時にマージされるようになると、パイプライン自体の制御が課題になります。並行実行のキャンセルや必須チェックの設計は [[CI/CDパイプラインのゲートと並行制御]] へ。
関連技術とのつながり
- [[Git]] — CI/CDのトリガーとなるバージョン管理
- [[自動テスト]] — CIで実行する検証の中身
- [[LLMアプリの評価とテスト]] — 出力が毎回変わる機能は合否判定の作り方が変わる
- [[Docker]] — ビルド成果物をイメージとして本番へ運ぶ
- [[コンテナレジストリとイメージ管理]] — ビルドしたイメージの置き場。本番はここから取り出す
- [[クラウドコンピューティング]] — 自動デプロイの届け先。開発・ステージング・本番の違いは設定で吸収し、同じ成果物を配る
Q: 本文が挙げるパイプラインの原則として正しいのはどれ?
- [x] ビルドは1回だけ行い、同じ成果物を各環境へ配る
- [ ] 開発・ステージング・本番でそれぞれビルドし直す
- [ ] 本番だけは手作業でビルドして確実性を高める
解説: 環境ごとにビルドし直すと、検証したものと本番で動くものが別物になり得ます。環境ごとに変えるのは接続先やキーなどの設定だけにします。
Q: 「ローカルでは通るのにCIで落ちる」原因として本文が挙げているのはどれ?
- [ ] CIのマシンが手元より遅いから
- [x] ファイル名の大文字小文字の扱いがOSによって違うから
- [ ] CIではテストが2回実行されるから
解説: macOSやWindowsは大文字小文字を区別せず、CIのLinuxは区別します。ほかに依存パッケージのバージョン差、コミットし忘れ、時刻や言語設定の違いも原因になります。
Q: たまに落ちるテスト(flaky test)を再実行で済ませ続けると起きることはどれ?
- [ ] テストの実行時間が自動的に短くなる
- [ ] 該当のテストがCIから自動で除外される
- [x] 赤信号が信用されなくなり、本物の不具合まで見逃される
解説: 「また例のやつだろう」と再実行する習慣がつくと、パイプラインは通過儀礼になります。原因を直すか、いったん対象から外して別に管理します。