変更要約: 初版
4.2CI/CDとコンテナ
コードを安全に届けるCI/CDパイプライン(build→test→deploy の自動化)、変更を守るユニットテスト(Python の unittest/pytest)、そしてアプリを可搬な形にするDockerfile(FROM/RUN/COPY/CMD/EXPOSE)とイメージ・コンテナの関係を、「このパイプライン/Dockerfile は何を保証し、どこが誤りか」という解釈・診断として学びます。
DevNet で問われるのは「CI/CD とは何か」という定義ではなく、目の前のパイプラインや Dockerfile が何を保証し、どこに欠陥があるかを読めることです。テストを通さずにデプロイするパイプラインは事故を量産し、キャッシュを無視した Dockerfile はビルドを無駄に遅くし、CMD を書き忘れたイメージは起動しません。この節では、CI/CD の各段階・Python のユニットテスト・Dockerfile の各命令を、提示された成果物を解釈・診断する視点で押さえます。
4.2.1CI/CDパイプライン
- CI(継続的インテグレーション)=開発者の変更をこまめに共有ブランチへ統合し、その都度自動でビルドとテストを回して壊れを早期検知する。CD(継続的デリバリ/デプロイ)は、テストを通った成果物を自動で配布/本番反映まで進める。要は
build -> test -> deployを人手を介さず反復可能にする仕組み。 - パイプラインの要はテストが失敗したら先へ進めない(ゲート)こと。
testステージが赤ならdeployは実行されないのが正しい設計で、テストを飛ばして本番反映するパイプラインは自動化された事故になる。失敗を早く・小さく検知するほど修正コストは小さい。
4.2.2Pythonユニットテスト
- ユニットテスト=関数やメソッドという最小単位の振る舞いを、入力に対する期待出力で自動検証する。Python では標準の
unittest(assertEqualなどのアサーション)やpytest(assert文と簡潔な記法)を使う。CI が回すのは主にこのユニットテストで、変更が既存の振る舞いを壊していないかを守る。 - 良いテストは1つの振る舞いを1つのケースで確かめ、失敗時にどこがなぜ壊れたかが分かる。例えば
assertEqual(add(2, 3), 5)が落ちればaddの回帰が一目で分かる。テストが通ることが CI の合格条件であり、テストが無いコードは CI の保護を受けられない点が実務上の要。
4.2.3Dockerfile・イメージ・コンテナ
- Dockerfile=イメージの作り方を記述したテキスト。主要命令は
FROM(ベースイメージ)/RUN(ビルド時にコマンド実行=依存導入等)/COPY(ファイルをイメージへ取り込む)/EXPOSE(待ち受けポートの宣言)/CMD(コンテナ起動時に実行する既定コマンド)。docker build -t myapp .で イメージ(不変のテンプレート)を作り、docker run myappでそのイメージからコンテナ(実行中の実体)を起動する。 - ビルドは命令ごとにレイヤをキャッシュする。頻繁に変わるアプリコードの
COPYは後ろに、めったに変わらない依存インストール(COPY requirements.txt→RUN pip install)は先に置くと、コード変更のたびに依存を入れ直さずビルドが速い。順序を逆にすると毎回キャッシュが無効化され、遅くなる。RUN(ビルド時)とCMD(起動時)の実行タイミングの違いも要注意。
「CI=統合ごとに自動build+test・CD=テスト通過後に自動配布/反映」「testが赤ならdeployしない(ゲート)」「Dockerfile: FROM/RUN/COPY/EXPOSE/CMD」「build→イメージ(不変テンプレ)→run→コンテナ(実行実体)」「RUN=ビルド時・CMD=起動時」「変わりにくい依存を先・変わりやすいコードのCOPYを後にしてキャッシュを効かせる」が頻出です。設問は提示されたパイプライン/Dockerfileの解釈・誤り診断として来ます。
次の Dockerfile をレビューしてください:FROM python:3.12-slim の後に COPY . /app(プロジェクト全体をコピー)、続けて RUN pip install -r /app/requirements.txt、最後に CMD ["python", "/app/main.py"] と書かれています。動作はしますが、ビルドが毎回遅いという相談が来ました。問題は COPY . /app を依存インストールより前に置いている点です。ソースを1行直すだけでも COPY . のレイヤが変化してキャッシュが無効化され、その後ろの pip install が毎回最初からやり直しになります。正しくは、まず COPY requirements.txt /app/ だけを行って RUN pip install -r /app/requirements.txt を済ませ、その後に COPY . /app でアプリ本体を入れる——こうすれば依存が変わらない限り pip install レイヤはキャッシュされ、コード修正時のビルドが劇的に速くなります。次に別のチームから「テストが落ちているのに本番へ出てしまった」と報告が来ました。パイプラインを見ると、deploy ジョブが test ジョブの成否に依存せず並行実行される設定になっていました。CI/CD の本質はテストがゲートであることなので、deploy は test 成功を前提条件にし、赤なら止める(人手で握り潰させない)よう直します。ここで学ぶべきは、CI/CD も Dockerfile も「動く/動かない」だけでなく「何を保証し、どこが速度・安全性を損なっているか」を提示物から読み解くことが問われる、という点です。単語(FROM や CI)の意味を答える問題ではなく、この成果物の欠陥を診断して直すのが本領です。
| Dockerfile命令 | 役割 | 実行タイミング | 例 |
|---|---|---|---|
| `FROM` | ベースイメージの指定 | ビルド時 | `FROM python:3.12-slim` |
| `COPY` | ファイルをイメージへ取り込む | ビルド時 | `COPY requirements.txt /app/` |
| `RUN` | ビルド中にコマンド実行(依存導入等) | ビルド時 | `RUN pip install -r requirements.txt` |
| `EXPOSE` | 待ち受けポートの宣言 | メタ情報 | `EXPOSE 8080` |
| `CMD` | コンテナ起動時の既定コマンド | 起動時 | `CMD ["python", "main.py"]` |
ひっかけ: 「Dockerfile では命令の順序は結果が同じなら自由で、COPY . /app を RUN pip install の前に置いても後に置いても違いはない」は誤りです——順序はレイヤキャッシュの効きを左右し、頻繁に変わるコードの COPY を依存インストールより前に置くと毎回キャッシュが無効化されビルドが遅くなります。また「CI が緑でなくてもデプロイは走ってよい」も誤り=テストがゲートであり、test が失敗したら deploy を止めるのが正しい設計です。
4.2.4この節のまとめ
- CI/CDは
build -> test -> deployを自動化し、テストをゲートにする(testが赤ならdeployしない) - Python のユニットテスト(
unittest/pytest)は最小単位の振る舞いを期待出力で守り、CI の合格条件になる - Dockerfile(
FROM/RUN/COPY/EXPOSE/CMD)→buildでイメージ→runでコンテナ。変わりにくい依存を先・コードのCOPYを後にしてキャッシュを効かせる
進捗の記録にはログインが必要です。
理解度チェック
(軽い確認用)Q1. ある Dockerfile は `FROM python:3.12-slim` の直後に `COPY . /app` でプロジェクト全体をコピーし、その後に `RUN pip install -r /app/requirements.txt` を実行している。ソースを1行変えるだけでもビルドが毎回遅い。改善策として最も適切なものはどれか。
Q2. CI/CD パイプラインで、ユニットテストが失敗しているコミットがそのまま本番へデプロイされてしまった。調べると deploy ジョブが test ジョブの成否に依存せず並行実行される設定だった。修正方針として最も適切なものはどれか。
Q3. 開発者が `docker build -t myapp .` を実行して成果物を作り、続けて `docker run myapp` を実行した。この一連の操作で「build で作られるもの」と「run で起きること」の説明として最も適切なものはどれか。

