mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 08:27:25 +00:00
fix(content): harden Docker practice guide
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
**BuildKit** 是下一代的镜像构建组件,在 [moby/buildkit](https://github.com/moby/buildkit) 开源。
|
||||
|
||||
> **重要**:自 Docker 23 起,BuildKit 已成为 **默认稳定构建器**,无需手动启用。Docker Engine 29 进一步将 Containerd 镜像存储设为默认,提升与 Kubernetes 的互操作性。
|
||||
> **重要**:自 Docker 23 起,BuildKit 已成为 **默认稳定构建器**,无需手动启用。Docker Engine 29 在新安装场景中进一步将 containerd image store 设为默认,提升多平台镜像、SBOM/Provenance 等 OCI 元数据能力。
|
||||
|
||||
目前,Docker Hub 自动构建已经支持 BuildKit,具体请参考 [docker-practice/docker-hub-buildx](https://github.com/docker-practice/docker-hub-buildx)。
|
||||
|
||||
@@ -46,7 +46,7 @@ COPY --from=builder /app/dist /app/dist
|
||||
```
|
||||
使用多阶段构建,构建的镜像中只包含了目标文件夹 `dist`,但仍然存在一些问题,当 `package.json` 文件变动时,`RUN npm i && rm -rf ~/.npm` 这一层会重新执行,变更多次后,生成了大量的中间层镜像。
|
||||
|
||||
为解决这个问题,进一步的我们可以设想一个类似 **数据卷** 的功能,在镜像构建时把 `node_modules` 文件夹挂载上去,在构建完成后,这个 `node_modules` 文件夹会自动卸载,实际的镜像中并不包含 `node_modules` 这个文件夹,这样我们就省去了每次获取依赖的时间,大大增加了镜像构建效率,同时也避免了生成了大量的中间层镜像。
|
||||
为解决这个问题,可以把包管理器的下载缓存挂载到构建步骤中,例如 npm 的 `/root/.npm`。注意:`type=cache` 只能作为性能优化,不能成为构建正确性的前提。缓存目录可能被并发构建改写,也可能被 GC 清理,所以不要把 `node_modules`、编译产物等必须存在的内容只放在 cache mount 里。
|
||||
|
||||
`BuildKit` 提供了 `RUN --mount=type=cache` 指令,可以实现上边的设想。
|
||||
|
||||
@@ -59,35 +59,23 @@ WORKDIR /app
|
||||
|
||||
COPY package.json /app/
|
||||
|
||||
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
|
||||
--mount=type=cache,target=/root/.npm,id=npm_cache \
|
||||
npm i --registry=https://registry.npmmirror.com
|
||||
RUN --mount=type=cache,target=/root/.npm,id=npm_cache \
|
||||
npm install --registry=https://registry.npmmirror.com
|
||||
|
||||
COPY src /app/src
|
||||
|
||||
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
|
||||
|
||||
## --mount=type=cache,target=/app/dist,id=my_app_dist,sharing=locked \
|
||||
|
||||
npm run build
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
## COPY --from=builder /app/dist /app/dist
|
||||
|
||||
## 为了更直观的说明 from 和 source 指令,这里使用 RUN 指令
|
||||
|
||||
RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
|
||||
# --mount=type=cache,target=/tmp/dist,from=my_app_dist,sharing=locked \
|
||||
|
||||
mkdir -p /app/dist && cp -r /tmp/dist/* /app/dist
|
||||
COPY --from=builder /app/dist /app/dist
|
||||
```
|
||||
|
||||
第一个 `RUN` 指令执行后,`id` 为 `my_app_npm_module` 的缓存文件夹挂载到了 `/app/node_modules` 文件夹中。多次执行也不会产生多个中间层镜像。
|
||||
第一个 `RUN` 指令执行后,`id` 为 `npm_cache` 的缓存文件夹挂载到了 `/root/.npm`,后续构建可复用下载缓存。
|
||||
|
||||
第二个 `RUN` 指令执行时需要用到 `node_modules` 文件夹,`node_modules` 已经挂载,命令也可以正确执行。
|
||||
第二个 `RUN` 指令执行时,`node_modules` 已经作为上一层真实写入到 builder 阶段的文件系统中,构建不依赖缓存目录内容。
|
||||
|
||||
第三个 `RUN` 指令将上一阶段产生的文件复制到指定位置,`from` 指明缓存的来源,这里 `builder` 表示缓存来源于构建的第一阶段,`source` 指明缓存来源的文件夹。
|
||||
最后使用 `COPY --from=builder` 将上一阶段产生的文件复制到最终镜像。跨阶段复制构建产物应使用 `COPY --from`;如果只是临时读取上一阶段文件,可使用 `RUN --mount=type=bind,from=builder,source=/app/dist,target=/tmp/dist,ro`。
|
||||
|
||||
上面的 `Dockerfile` 中 `--mount=type=cache,...` 中指令作用如下:
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对
|
||||
```bash
|
||||
$ docker buildx build --sbom=true -t myimage .
|
||||
```
|
||||
该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。
|
||||
该命令会把 SBOM 作为构建 attestation 附加到构建结果中;BuildKit 默认使用 SPDX SBOM attestation。需要 CycloneDX 文件时,可使用 Syft、Docker Scout 等工具另行生成或转换。
|
||||
|
||||
> **⚠️ 注意与失败模式**:
|
||||
> 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。
|
||||
|
||||
Reference in New Issue
Block a user