導入: なぜ今、ビルドの高速化が重要なのか
現代のDevOpsにおいて、CI/CDパイプラインの実行速度は開発者の生産性に直結します。特にNode.jsなどのエコシステムでは、`npm install` にかかる時間がビルド全体の数分を占めることも珍しくありません。変更頻度の低いライブラリを毎回インストールするのは、時間とリソースの無駄です。「Pre-installed Dependencies」の手法を取り入れることで、この無駄を省き、フィードバックループを劇的に高速化できます。
基礎知識: コンテナレイヤーの仕組み
Dockerイメージは複数の「レイヤー」で構成されています。Dockerfileの各命令(RUNなど)が新しいレイヤーを作成し、それがキャッシュされます。通常、`package.json`をコピーして`npm install`を実行すると、ソースコードが1行でも変更されるたびにキャッシュが破棄され、全ライブラリの再インストールが発生します。この仕組みを理解し、変更頻度の高いコードと、低いライブラリを分離して配置することが、高速化の鍵となります。
実装/解決策: 依存関係の先行インストール
最も効果的なのは、`package.json`と`package-lock.json`だけを先にコンテナへコピーし、ライブラリのインストールを済ませてから、残りのソースコードをコピーする手法です。これにより、ソースコードを変更しても、`package.json`に変更がない限り、ライブラリインストール層はキャッシュから再利用されます。
サンプルプログラム: 最適化されたDockerfile例
以下は、Node.jsアプリケーションを想定した、キャッシュ効率を最大化するDockerfileの構成です。
ベースイメージの指定 FROM node:18-alpine 作業ディレクトリの設定 WORKDIR /app 1. まずパッケージ定義ファイルのみをコピー これにより、ソースコードを変更してもnpm installはキャッシュされる COPY package.json ./ 2. 依存関係のインストール(ここでプリインストールを行う) プロダクション環境用のライブラリのみをインストールしてレイヤーを確定 RUN npm ci --only=production 3. その後、ソースコードをコピー ソースコードの変更は、このレイヤー以降にのみ影響する COPY . . アプリケーションの起動 CMD ["node", "index.js"]
応用・注意点: 現場で役立つTIPS
1. npm ci の活用:
開発環境の `npm install` ではなく、CI環境では `npm ci` を必ず使用してください。`package-lock.json` に厳密に従うため、インストール時間が短縮されるだけでなく、環境間の依存関係の不一致(再現性の欠如)を防ぐことができます。
2. マルチステージビルドの併用:
もしビルド時に `devDependencies`(TypeScriptのコンパイルなど)が必要な場合は、マルチステージビルドを使いましょう。「ビルド用イメージ」で全パッケージをインストールしてビルドし、「実行用イメージ」に生成物だけをコピーすることで、実行イメージのサイズを最小化できます。
3. キャッシュの無効化に注意:
`package.json` を変更した際は、必ず `package-lock.json` もコミットするようにしてください。そうしないと、予期せずライブラリのバージョンが再計算され、キャッシュが期待通りに機能しなくなります。
この構成を導入するだけで、CI環境のビルド時間を大幅に削減できるはずです。まずは現在のDockerfileを見直し、`COPY . .` の位置を確認することから始めてみてください。

コメント