レイヤ

Dockerfile 命令の順番は重要です。Docker は構築命令の順番に従い、構築を構成します。Dockerfile 内の各命令は、 イメージ レイヤ(image layer) に大ざっぱに相当します。以下の図が示すのは、Dockerfile がどのようにしてコンテナ内のレイヤ層の積み重なりに変換されるかです。

Dockerfile からレイヤへ

キャッシュされたレイヤ

構築を実行するとき、 ビルダ(builder) は以前に構築したレイヤを再利用しようとします。イメージのレイヤが変更されていない場合は、ビルダは 構築キャッシュ(build cache) からキャッシュを取り出します。最後の構築からレイヤに変更がある場合は、対象レイヤと以降のレイヤをすべて再構築されます。

前のセクションにある Dockerfile は、全てのプロジェクトファイルをコンテナにコピーします( COPY . . )。それから、続くステップでアプリケーションの依存関係をダウンロードします( RUN go mod download )。プロジェクトのファイルに変更があれば、 COPY レイヤのキャッシュが無効になります。また、以降に続く、全てのレイヤに対するキャッシュも無効になります。

レイヤキャッシュのバースト

現在の Dockerfile にある命令の順番では、ビルダは Go モジュールをダウンロードする必要があります。前回の構築時からパッケージは何も変わっていないのにもかかわらずです。

命令の順番を変える

Dockerfile 内の命令の順番を変えれば、この余計な冗長性を避けられます。ソースコードをコンテナへと渡す前に、ダウンロードと依存関係のインストールをするように命令の順番を変えます。この方法により、ソースコードに変更があったとしても、ビルダがキャッシュから「依存関係」のレイヤを再利用できるようになります。

Go は go.modgo.sum と呼ばれる2つのファイルを使い、プロジェクトの依存関係を追跡します。これらのファイルは Go にとって、JavaScript における package.jsonpackage-lock.json にあたります。Go がダウンロードすべき依存関係を分かるようにするには、 go.modgo.sum ファイルをコンテナ内にコピーする必要があります。 RUN go mod download の前に、今回は go.modgo.sum ファイルのみコピーする別の COPY 命令を追加します。

  # syntax=docker/dockerfile:1
  FROM golang:{{site.example_go_version}}-alpine
  WORKDIR /src
- COPY . .
+ COPY go.mod go.sum .
  RUN go mod download
+ COPY . .
  RUN go build -o /bin/client ./cmd/client
  RUN go build -o /bin/server ./cmd/server
  ENTRYPOINT [ "/bin/server" ]

これでアプリケーションのコードを変更したとしても、イメージの構築時に毎回ビルダが依存関係をダウンロードしなくなります。 COPY . . 命令はパッケージ管理命令の後にあるため、ビルダは RUN go mod download レイヤを再利用できます。

並び替え

まとめ

Dockerfile に書く命令の順番を適切にしておけば、構築時に不要な処理を防ぐのに役立ちます。

関連情報:

次のステップ

次のセクションでは、構築を速くし、最終出力を小さくするため、マルチステージビルドを使う方法を見ていきます。