使用 Kaniko 缓存

概览

Kaniko 通过在容器映像注册表(例如 Google 自己的 Artifact Registry)中存储中间层并将其编入索引来缓存容器构建工件。如需了解其他用例,请参阅 GitHub 上的 Kaniko 代码库

Kaniko 缓存的工作原理如下:

  • 构建容器映像层时,Cloud Build 会将容器映像层直接上传到注册表,因此没有明确的推送步骤。如果所有层均成功构建,则将包含这些层的映像清单文件写入注册表中。

  • Kaniko 根据创建层的 Dockerfile 指令及其前面的所有指令(直到 FROM 行中的映像摘要)的内容来缓存每一层。

在构建中启用 Kaniko 缓存

通过在 cloudbuild.yaml 文件中将 cloud-builders/docker 工作器替换为 kaniko-project/executor 工作器,您可以在 Docker 构建中启用 Kaniko 缓存,如下所示:

Kaniko 构建

steps:
- name: 'gcr.io/kaniko-project/executor:latest'
  args:
  - --destination=${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}
  - --cache=true
  - --cache-ttl=XXh

Docker 构建

steps:
- name: gcr.io/cloud-builders/docker
  args: ['build', '-t', '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}', '.']
images:
- '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}'

其中:

  • --destination=${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE} 是目标容器映像。Cloud Build 会自动替换包含 Dockerfile 的项目中的 PROJECT_IDLOCATIONREPOSITORYIMAGE用户定义的替代变量
  • LOCATION 是存储映像的代码库的单区域或多区域位置,例如 us-east1
  • REPOSITORY 是存储映像的代码库的名称。
  • IMAGE 是映像的名称。
  • --cache=true 启用 Kaniko 缓存。
  • --cache-ttl=XXh 设置缓存到期时间,其中 XX 是缓存到期前的小时数。请参阅配置缓存到期时间

如果您使用 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 文件执行以下操作:

每次运行此构建时,Cloud Build 必须运行每个步骤,因为 Cloud Build 中没有交叉构建映像层缓存。 但是,当您在 Kaniko 缓存已启用的情况下运行此构建时,会发生以下情况:

  1. 第一次运行期间,Cloud Build 会运行每个步骤,每个指令会向容器映像注册表写入一个层。

  2. Kaniko 使用其根据生成该层的指令及前面所有指令的内容派生的缓存键来标记每个层。

  3. 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 文件,则 Cloud Build 不需要在 COPY 步骤之前运行指令,因为其内容未更改。但是,由于修改 package.json 文件会修改 COPY 步骤,因此 Cloud Build 必须在 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 标志指示 Kaniko 忽略缓存中在特定到期时间内未被推送的层。

语法为 --cache-ttl=XXh,其中 XX 表示以小时为单位的时间。例如,--cache-ttl=6h 将缓存到期时间设置为 6 小时。如果您使用 gcloud builds submit --tag [IMAGE] 命令运行构建,则 --cache-ttl 标志的默认值为 6 小时。如果您直接使用 Kaniko 执行程序映像,则默认值为 2 周。

如果您不希望依赖项经常更改,则可以延长到期时间,从而确保加快构建速度,而缩短到期时间可确保您的构建以更快速度获取更新的依赖项(如 Maven 包或 Node.js 模块),但缓存层的使用将减少。

如需从命令行设置缓存到期时间,请运行以下命令:

gcloud config set builds/kaniko_cache_ttl XX

其中 XX 是以小时为单位的缓存到期时间。

在我们的 Node.js 示例中,由于 RUN npm install 指令的输出保持不变,因此即使该指令已缓存,我们也需要定期重新运行该指令。将 --cache-ttl 参数设置为 6 小时是一个不错的折衷办法,这样可确保无论该指令的内容是否发生更改,Cloud Build 每个工作日至少运行一次该指令,而不是在每次构建运行时运行该指令。