概要
Kaniko キャッシュは、Cloud Build の機能の 1 つであり、コンテナビルドのアーティファクトをキャッシュに保存します。キャッシュ保存の際は、コンテナ イメージ レジストリ(Google 独自の Container Registry など)内に中間レイヤが保存され、インデックス付けされます。レジストリ内のレイヤは、Kaniko に利用できます。
Kaniko キャッシュの仕組みは次のとおりです。
Cloud Build では、コンテナ イメージのレイヤがビルド時にレジストリに直接アップロードされるため、明示的な push ステップはありません。すべてのレイヤが正常にビルドされると、それらレイヤを含むイメージ マニフェストがレジストリに書き込まれます。
Kaniko では、各レイヤが、その作成元の Dockerfile ディレクティブと、先行するすべてのディレクティブ(
FROM
行のイメージのダイジェストに至るまでのもの)のコンテンツに従ってキャッシュに保存されます。
ビルドでの Kaniko キャッシュの有効化
Docker ビルドで Kaniko キャッシュを有効にするには、次に示すように、cloudbuild.yaml
ファイルで cloud-builders/docker
ワーカーを kaniko-project/executor
ワーカーに置き換えます。
Kaniko ビルド
steps:
- name: 'gcr.io/kaniko-project/executor:latest'
args:
- --destination=gcr.io/$PROJECT_ID/image
- --cache=true
- --cache-ttl=XXh
Docker ビルド
steps:
- name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/image', '.']
images:
- 'gcr.io/$PROJECT_ID/image'
ここで
--destination=gcr.io/$PROJECT_ID/image
は、ターゲットのコンテナ イメージです。Cloud Build によって、Dockerfile が含まれるプロジェクトからのプロジェクト ID が自動的に置き換えられます。--cache=true
は、Kaniko キャッシュを有効化します。--cache-ttl=XXh
でキャッシュの有効期限を設定します。ここで、XX
はキャッシュの有効期限までの時間です。キャッシュ保存の有効期限の構成をご覧ください。
Kaniko を使用すると、ビルドされたイメージはすぐに自動的に Container Registry に push されます。images
属性にイメージを指定する必要はありません(この属性を使用した場合、ビルドステップの完了後にイメージが push されます)。
gcloud builds submit --tag [IMAGE]
コマンドを使用してビルドを実行する場合、次に示すようにプロパティ builds/use_kaniko
を True
に設定することで Kaniko キャッシュを有効化できます。
gcloud config set builds/use_kaniko True
例: Node.js ビルドでの Kaniko キャッシュの使用
次の例では、Dockerfile に関して一般的に推奨されている方法を使用して Node.js アプリの差分ビルドを実行する方法を示しています。ここに示す方法は、サポートされている他のすべての言語のビルドにも適用されます。
ここでは、ビルド間で変更される可能性が低いディレクティブを Dockerfile の先頭に移動し、変更される可能性の高いディレクティブを末尾に移動します。これによってビルドプロセスでの差分処理が効率化され、ビルドを迅速化できます。
ここでは次の Dockerfile について考えてみます。
FROM node:8
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "npm", "start" ]
この Dockerfile では次の処理が行われます。
Node.js に関するおすすめの方法に基づいて Node.js アプリをインストールする。
イメージの実行時にそのアプリを実行する。
このビルドを実行する際には、Cloud Build に複数のビルドを対象とするイメージレイヤのキャッシュが存在しないため、ビルドの実行のたびに Cloud Build で各ステップを実行しなければなりません。しかし、Kaniko キャッシュを有効にしてこのビルドを実行した場合は、以下の処理が行われます。
初回の実行時に Cloud Build によってすべてのステップが実行され、各ディレクティブによってレイヤがコンテナ イメージ レジストリに書き込まれます。
Kaniko では、レイヤの作成元のディレクティブとそのすべての先行ディレクティブのコンテンツから導出されたキャッシュキーによるタグが、各レイヤに付けられます。
それ以降、Cloud Build で同じ Dockerfile からビルドを実行するときは、そのファイルが変更されたかどうかが確認されます。変更されていない場合、Cloud Build ではレジストリに保存されているキャッシュ内のレイヤを使用してビルドが実施されるため、ビルドの完了までの時間が短縮されます。以下をご覧ください。
FROM node:8 # no change -> cached!
COPY package*.json ./ # no change -> cached!
RUN npm install # no change -> cached!
COPY . . # no change -> cached!
CMD [ "npm", "start" ] # metadata, nothing to do
package.json
ファイルを変更した場合、内容が変更されていないため、COPY
ステップの前に Cloud Build でディレクティブを実行する必要はありません。ただし、package.json
ファイルの変更によって COPY
ステップは変更されるため、COPY
ステップの後のステップはすべて再実行する必要があります。以下をご覧ください。
FROM node:8 # no change -> cached!
COPY package*.json ./ # changed, must re-run
RUN npm install # preceding layer changed
COPY . . # preceding layer changed
CMD [ "npm", "start" ] # metadata, nothing to do
アプリの内容のみが変更され、依存関係が変更されない場合(よくあるシナリオ)には、package.json
ファイルを変更せず、Cloud Build は最終版の COPY . .
ステップのみを再実行する必要があります。この結果、このステップではソース コンテンツがコンテナ イメージ レジストリ内のレイヤにコピーされるだけなので、ビルドが迅速化されます。
FROM node:8 # no change -> cached!
COPY package*.json ./ # no change -> cached!
RUN npm install # no change -> cached!
COPY . . # changed, must re-run
CMD [ "npm", "start" ] # metadata, nothing to do
キャッシュ保存の有効期限の構成
--cache-ttl
フラグは、キャッシュ内のレイヤのうち特定の有効期限内に push されなかったものを無視するよう Kaniko に指示します。
構文は --cache-ttl=XXh
です。ここで、XX
は時間(hr)です。たとえば、--cache-ttl=6h
がキャッシュの有効期限を 6 時間に構成したとします。gcloud builds submit --tag [IMAGE]
コマンドを使用してビルドを実行する場合、--cache-ttl
フラグのデフォルト値は 6 時間です。Kaniko Executor イメージを直接使用する場合、デフォルト値は 2 週間です。
有効期限を長くすると、依存関係が頻繁に変更されない場合は、ビルドが迅速化されます。有効期限を短くすると、更新された依存関係(Maven パッケージや Node.js モジュール)がより迅速に取り込まれるものの、キャッシュ内のレイヤがあまり使用されなくなります。
キャッシュ保存の有効期限をコマンドラインから設定するには、次のコマンドを実行します。
gcloud config set builds/kaniko_cache_ttl XX
XX
は、キャッシュ保存の有効期限(hr)です。
Node.js の例では、RUN npm install
ディレクティブの出力は変わらないままであるため、キャッシュ保存されていても、このディレクティブを定期的に再実行する必要があります。--cache-ttl
パラメータの 6 時間という設定はバランスのとれた値です。このディレクティブのコンテンツが変更されたかどうかに関係なく、営業日ごとに少なくとも 1 回はディレクティブが実行されるからです。ただし、ビルドの実行時に毎回実行されるわけではないのでシステムの負荷が軽減されます。