Dockerビルドを106秒→44秒に縮める — 受託で効くCIビルド高速化の実装 2026 | GH Media
URLがコピーされました

Dockerビルドを106秒→44秒に縮める — 受託で効くCIビルド高速化の実装 2026

URLがコピーされました
Dockerビルドを106秒→44秒に縮める — 受託で効くCIビルド高速化の実装 2026

git push してから本番に反映されるまでが長い」「CI の Docker ビルドだけで毎回何分も待たされる」「ビルド回数に比例して CI の従量課金が積み上がる」——受託でシステム開発・運用を担っていると、こうした相談が定期的に持ち込まれます。きっかけになった Docker Buildを106秒→44秒、32秒→3秒に高速化した3つの改善(Zenn)(2026-06-08)は、複数コンテナを抱えるプロジェクトで 命令の並び替え・キャッシュ活用・不要ファイルの除外といった地味な改善だけで、ビルド時間を半分以下、ものによっては 10 分の 1 にまで縮めた実例でした。特別なツールを足したわけではなく、Dockerfile と CI の書き方を直しただけで大きな差が出ています。

受託の現場では、これは「ビルドが速いか遅いか」という技術自慢の話ではありません。ビルド時間はそのままデプロイのリードタイムであり、CI の従量課金であり、開発者が待たされる時間です。1 回 100 秒のビルドが 1 日に何十回も走れば、それは積もって開発体験とコストを蝕みます。受託で引き渡す立場では、「Dockerfile を最適化し、CI のキャッシュ設定まで含めて、保守しやすい状態でビルドを速くして渡せるか」が問われます。これまで バックエンドのメモリ削減でクラウドコスト最適化(GH Media) で扱った 実行時コストの削り方と接続して、本記事では 「CIビルド高速化支援」受託パッケージとして整理します。

なぜビルドが遅くなるのか — レイヤーキャッシュの仕組み

Docker のイメージは 命令(FROM / COPY / RUN …)ごとのレイヤーの積み重ねでできています。ビルド時、Docker は各命令の結果をキャッシュし、入力が前回と同じなら再実行せずキャッシュを再利用します。逆に、ある命令でキャッシュが無効になると、それ以降の命令はすべて再実行されます。ここが遅さの正体です。

観点遅いビルド(よくある状態)速いビルド(最適化後)
命令の並び変わりやすいソースコピーが先変わりにくい依存インストールが先
キャッシュ範囲レイヤーキャッシュのみ+ cache mount でDLキャッシュ保持
ビルドコンテキスト不要ファイルも丸ごと送信.dockerignore で最小化
イメージ構成ビルドツールも本番に同梱マルチステージで成果物だけ
CIでの再利用毎回ゼロからregistry / GHA cache で共有

つまり 「依存インストールとソースコピーが同じ層に混ざっている」「不要ファイルまで送っている」「CI ではキャッシュが効いていない」といった構造があると、コードを一行直しただけで重い再ビルドが走ります。高速化とは、この再実行の連鎖を断ち切り、変わらない部分をキャッシュに固定する作業です。

高速化の具体手法

① 命令順序とキャッシュ層の分離

最も効くのは 「依存インストール」と「ソースコピー」を別の層に分け、変わりにくい依存を先に置くことです。package.json だけを先にコピーして依存をインストールし、その後にソース全体をコピーすれば、ソースを直しても依存のインストール層はキャッシュが効いたままになります。

# 改善前: ソースを全部コピーしてから install
# → ソースを1行直すたびに npm install が再実行される
COPY . .
RUN npm ci

# 改善後: 依存定義だけ先にコピーして install
# → ソース変更では install 層のキャッシュが効く
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

この並び替えだけで、日常的な「ソースを直して再ビルド」のほとんどが依存インストールをスキップできます。冒頭の Zenn 記事の改善も、本質はこの「キャッシュが効く層の設計」です。

② BuildKit の cache mount で依存ダウンロードを保持

レイヤーキャッシュが無効化されても、パッケージマネージャのダウンロードキャッシュ(npm / pip / apt / Go モジュール等)だけは保持したい——それを実現するのが BuildKit の cache mount(--mount=type=cache)です。ビルド中だけ存在する専用のキャッシュ領域で、イメージには含まれないが次回ビルドで再利用されるのが肝です。

# syntax=docker/dockerfile:1
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
# npm のキャッシュディレクトリを cache mount で保持
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build

レイヤーキャッシュ(命令結果の保存)と cache mount(ダウンロード領域の保持)は 別々の仕組みで、両方を併用すると効果が重なります。①でキャッシュが無効化された場合でも、cache mount があればダウンロードからやり直さずに済みます。

マルチステージビルドは 「ビルド用ステージ」と「実行用ステージ」を分け、最終イメージには成果物だけを持ち込む手法です。ビルドツールやソースを本番イメージから締め出せるので、イメージが小さくなり、転送・起動が速く、攻撃面も減ります。さらに COPY --link を使うと、コピー元のレイヤーが変わっても下流のキャッシュを壊しにくくなり、キャッシュヒット率が上がります。

# syntax=docker/dockerfile:1
# --- build stage ---
FROM node:22 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build

# --- runtime stage ---
FROM node:22-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
# 成果物だけを --link で持ち込む
COPY --link --from=build /app/dist ./dist
COPY --link --from=build /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

「ビルドに必要なもの」と「実行に必要なもの」を分けて考えるだけで、最終イメージのサイズとビルドの安定性が両立します。コンテナ運用そのものの効率化は Docker Gordon AIエージェントでコンテナ運用(GH Media) も併読してください。

④ .dockerignore の徹底

Docker はビルド開始時に ビルドコンテキスト(カレントディレクトリ一式)を丸ごとデーモンに送信します。.git / node_modules / ログ / ビルド生成物などを送っていると、送信だけで時間を浪費し、無関係なファイルの変更でキャッシュが無効化されます。.dockerignore で送る対象を絞るのは、効果の割に見落とされがちな一手です。

# .dockerignore の例
.git
node_modules
dist
*.log
.env
.env.*
Dockerfile
.dockerignore

特に .env 系を除外することは、後述の「秘密情報の混入」を防ぐ意味でも重要です。

⑤ CIでのキャッシュ共有

ローカルでは効いているキャッシュが、CI では毎回まっさらな環境のため効かない——これが「CI だけ遅い」典型です。BuildKit のキャッシュを registry にエクスポートする、あるいは **GitHub Actions のキャッシュバックエンド(type=gha)**を使うと、ジョブをまたいでビルドキャッシュを共有できます。

# GitHub Actions: BuildKit キャッシュを GHA に共有する例
- name: Set up Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v6
  with:
    context: .
    push: true
    tags: registry.example.com/app:latest
    cache-from: type=gha
    cache-to: type=gha,mode=max

mode=max にすると 中間ステージのキャッシュまで保存され、マルチステージ構成でもヒット率が上がります。なお、cache mount の中身は GHA キャッシュにそのままは載らない点に注意が必要で、必要なら専用の救済手段を併用します。インフラ選定の前提整理は CloudflareとAWSのインフラ選定(GH Media) を参照してください。

受託で提供する「CIビルド高速化支援」5フェーズ

フェーズ 1: 計測・診断(1 週間)

  • 現状の Dockerfile / CI 設定の棚卸し
  • ビルド時間・キャッシュヒット率・イメージサイズの計測
  • どの命令でキャッシュが壊れているかの特定
  • 成果物: ビルド遅延の原因レポート + 改善優先度表

フェーズ 2: 設計(1 週間)

  • レイヤー分離・cache mount・マルチステージの適用方針決定
  • CI のキャッシュ共有方式(registry / GHA)の選定
  • 改善後の目標ビルド時間・イメージサイズの設定
  • 成果物: 最適化設計書 + 改善前後の見積もり

フェーズ 3: 実装(1〜3 週間)

  • Dockerfile のリファクタリング(命令順序・cache mount・COPY --link
  • .dockerignore の整備とビルドコンテキストの最小化
  • CI ワークフローへのキャッシュ共有設定の組み込み
  • 成果物: 最適化済み Dockerfile / CI 設定 + 実装標準ドキュメント

フェーズ 4: 検証・引き渡し(1 週間)

  • 改善前後のビルド時間・課金・イメージサイズの比較計測
  • キャッシュ無効化シナリオでの再現性確認
  • 成果物: 効果測定レポート + 保守手順書

フェーズ 5: 継続保守(継続)

  • 依存追加・ベースイメージ更新時のキャッシュ劣化監視
  • CI キャッシュのヒット率の定点観測
  • 新規サービス追加時のビルド設計支援

受託向け実装標準セット

用途推奨避ける
依存とソース層を分け、依存を先にCOPY . . の後に install
DLキャッシュ--mount=type=cache毎回ダウンロードし直し
イメージ構成マルチステージ + slim/distrolessビルドツール同梱の肥大イメージ
コピーCOPY --link で安定化巨大ディレクトリの一括コピー
ビルドコンテキスト.dockerignore で最小化リポジトリ丸ごと送信
CIキャッシュregistry / type=gha,mode=maxキャッシュ未設定で毎回ゼロから

どの案件に必要か / 不要か

必要な案件優先度が低い案件
CI のビルドが数分かかりデプロイが詰まるビルドが数秒で完結する小規模
デプロイ頻度が高く待ち時間が積もるデプロイが月数回程度
CI の従量課金が膨らんでいる無料枠で十分収まる
イメージが巨大で転送・起動が遅いイメージが既に軽量
複数サービスを並行ビルドしている単一・単純な構成

受託契約に書く6つの条項

条項内容顧客が確認すべきこと
対象範囲最適化するサービス/Dockerfile対象の境界
目標値ビルド時間/イメージサイズの目標計測の定義
CI前提対象 CI と権限/キャッシュ環境反映先の整合
秘密情報ビルド時の秘密の扱い混入防止の基準
引き渡しDockerfile / CI 設定 / 手順書保守体制
継続保守キャッシュ劣化の監視運用費用

価格モデル — CIビルド高速化パッケージ

プラン金額対象内容
診断20 万円〜1 リポジトリ計測 + 原因レポート + 改善優先度
標準実装80 万円〜中規模Dockerfile 最適化 + CI キャッシュ設定
本格対応160 万円〜大規模+ 複数サービス + マルチステージ全面再設計
Lite 保守3 万円〜 / 月小規模ヒット率監視 + 軽微修正
Standard 保守10 万円〜 / 月中規模+ 新規サービスのビルド設計支援

顧客側 ROI 試算(CI ビルドを多用するチーム想定)

項目最適化前最適化後差分
ビルド時間100 秒前後数十秒〜数秒リードタイム短縮
CI 従量課金ビルド時間に比例大幅圧縮月額コストの低減
デプロイ回数待ち時間で抑制気軽に回せるリリース頻度の向上
開発者の待ち都度発生ほぼ解消開発体験の改善
年間効果課金削減 + 開発速度向上

診断(20 万円〜)だけでも、「自分たちのビルドの、どこでキャッシュが壊れ、何秒削れるのか」を数字で可視化できること自体に価値があります。ビルド時間は毎日積み上がるコストなので、一度の最適化が長く効きます。

ハマりやすい5つの落とし穴

落とし穴 1: 不用意な命令でキャッシュが無効化される

COPY . . を依存インストールの前に置くと、ソースを直すたびに全部再ビルドされます。変わりにくいものを先、変わりやすいものを後に並べます。

落とし穴 2: 秘密情報をビルド時に混入させる

ARGCOPY で API キーや .env をイメージに焼き込むと 履歴に残って漏れます.dockerignore で除外し、必要な秘密は --mount=type=secret で渡します。

落とし穴 3: CI とローカルでキャッシュ状態が違う

ローカルでは速いのに CI では毎回ゼロから——CI のキャッシュ共有を設定し、計測も CI 上で行って差を埋めます。

落とし穴 4: イメージを巨大なまま放置する

ビルドツールや不要パッケージを本番に同梱すると、転送・起動が遅く攻撃面も増えます。マルチステージで成果物だけに絞ります。

落とし穴 5: 過度な最適化で読めなくする

cache mount や条件分岐を詰め込みすぎると、誰も触れない Dockerfileになります。効果の大きい改善から入れ、保守できる範囲に留めます

90日アクションプラン

アクション
Week 1ビルド時間・キャッシュヒット率・イメージサイズの計測
Week 2原因特定 + 最適化方針と目標値の決定
Week 3〜5Dockerfile リファクタ + .dockerignore 整備 + CI キャッシュ設定
Week 6改善前後の比較計測 + 手順整備
Week 7〜13ヒット率の定点観測 + 新規サービスへの展開

まとめ — 「とりあえずビルドが通る」から「速くて保守できる状態で引き渡す」へ

Docker ビルドの高速化は、特別なツールではなく 命令順序・cache mount・マルチステージ・.dockerignore・CI キャッシュ共有という地味な積み上げで実現します。106 秒が 44 秒に、32 秒が 3 秒になるのは、魔法ではなく キャッシュが効く構造を設計し直した結果です。受託で引き渡す立場では、Dockerfile と CI を最適化し、効果を数字で示し、保守手順まで添えて渡す 「CIビルド高速化支援」が、デプロイのリードタイムと従量課金を同時に削る主力サービスです。本番の性能保証まで踏み込むなら k6 負荷テストで性能保証(GH Media) も併読してください。

弊社では診断 / 標準実装 / 本格対応 / Lite / Standard の各段階で本パッケージを提供しています。「CI のビルドが遅くてデプロイが詰まる」「ビルドの従量課金を減らしたい」「保守できる形で Dockerfile を直してほしい」というご相談は お問い合わせフォーム からお気軽にどうぞ。

Sources

URLがコピーされました

グリームハブ株式会社は、変化の激しい時代において、アイデアを形にし、人がもっと自由に、もっと創造的に生きられる世界を目指しています。

記事を書いた人

鈴木 翔

鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

関連記事