惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

Docker 从入门到实践

修订记录 如何贡献 Docker — 从入门到实践 高级网络配置 容器访问控制 自定义网桥 编辑网络配置文件 配置 docker0 网桥 工具和示例 映射容器端口到宿主主机的实现 示例:创建一个点到点连接 快速配置指南 附录 Dockerfile 最佳实践 Docker 命令查询 客户端命令(docker) 服务端命令(dockerd) 如何调试 Docker 常见问题总结 热门镜像介绍 Node.js 资源链接 归档项目 基本概念 Docker 容器 Docker 镜像 Docker Buildx 使用 Buildx 构建镜像 使用 buildx 构建多种系统架构支持的 Docker 镜像 CI/CD GitHub Actions Drone Demo Drone 部署 Drone Alpine Busybox CentOS/Fedora Debian/Ubuntu 容器与云计算 亚马逊云 腾讯云 Docker Compose 项目 Compose 命令说明 Compose 模板文件 使用 Django 安装与卸载 Compose 简介 使用 compose 搭建 LNMP 环境 使用 Rails 使用 使用 WordPress 操作 Docker 容器 进入容器 后台运行 导出和导入容器 删除容器 启动容器 终止容器 Fedora CoreOS 安装 Fedora CoreOS Fedora CoreOS 介绍 Docker 数据管理 挂载主机目录 数据卷 etcd 集群 使用 etcdctl 使用 etcdctl v2 什么是 etcd 在 IDE 中使用 Docker VS Code 中使用 Docker 使用 Dockerfile 定制镜像 使用 Docker 镜像 利用 commit 理解镜像构成 Dockerfile 指令详解 ADD 更高级的复制文件 ARG 构建参数 CMD 容器启动命令 COPY 复制文件 ENTRYPOINT 入口点 EXPOSE 声明端口 CentOS minio MongoDB MySQL Nginx PHP Redis Ubuntu WordPress Docker Registry 操作系统 本章小结 阿里云 简介 本章小结 etcd 安装 Docker — 从入门到实践
使用 BuildKit 构建镜像
2022-05-13 · via Docker 从入门到实践

# 使用 BuildKit 构建镜像

BuildKit 是下一代的镜像构建组件,在 https://github.com/moby/buildkit 开源。

注意:如果您的镜像构建使用的是云服务商提供的镜像构建服务(腾讯云容器服务、阿里云容器服务等),由于上述服务提供商的 Docker 版本低于 18.09,BuildKit 无法使用,将造成镜像构建失败。建议使用 BuildKit 构建镜像时使用一个新的 Dockerfile 文件(例如 Dockerfile.buildkit)

目前,Docker Hub 自动构建已经支持 buildkit,具体请参考 https://github.com/docker-practice/docker-hub-buildx

# Dockerfile 新增指令详解

启用 BuildKit 之后,我们可以使用下面几个新的 Dockerfile 指令来加快镜像构建。

# RUN --mount=type=cache

目前,几乎所有的程序都会使用依赖管理工具,例如 Go 中的 go modNode.js 中的 npm 等等,当我们构建一个镜像时,往往会重复的从互联网中获取依赖包,难以缓存,大大降低了镜像的构建效率。

例如一个前端工程需要用到 npm

FROM node:alpine as builder

WORKDIR /app

COPY package.json /app/

RUN npm i --registry=https://registry.npm.taobao.org \
        && rm -rf ~/.npm

COPY src /app/src

RUN npm run build

FROM nginx:alpine

COPY --from=builder /app/dist /app/dist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

使用多阶段构建,构建的镜像中只包含了目标文件夹 dist,但仍然存在一些问题,当 package.json 文件变动时,RUN npm i && rm -rf ~/.npm 这一层会重新执行,变更多次后,生成了大量的中间层镜像。

为解决这个问题,进一步的我们可以设想一个类似 数据卷 的功能,在镜像构建时把 node_modules 文件夹挂载上去,在构建完成后,这个 node_modules 文件夹会自动卸载,实际的镜像中并不包含 node_modules 这个文件夹,这样我们就省去了每次获取依赖的时间,大大增加了镜像构建效率,同时也避免了生成了大量的中间层镜像。

BuildKit 提供了 RUN --mount=type=cache 指令,可以实现上边的设想。

# syntax = docker/dockerfile:experimental
FROM node:alpine as builder

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.npm.taobao.org

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

由于 BuildKit 为实验特性,每个 Dockerfile 文件开头都必须加上如下指令

# syntax = docker/dockerfile:experimental

1

第一个 RUN 指令执行后,idmy_app_npm_module 的缓存文件夹挂载到了 /app/node_modules 文件夹中。多次执行也不会产生多个中间层镜像。

第二个 RUN 指令执行时需要用到 node_modules 文件夹,node_modules 已经挂载,命令也可以正确执行。

第三个 RUN 指令将上一阶段产生的文件复制到指定位置,from 指明缓存的来源,这里 builder 表示缓存来源于构建的第一阶段,source 指明缓存来源的文件夹。

上面的 Dockerfile--mount=type=cache,... 中指令作用如下:

Option Description
id id 设置一个标志,以便区分缓存。
target (必填项) 缓存的挂载目标文件夹。
ro,readonly 只读,缓存文件夹不能被写入。
sharing shared private locked 值可供选择。sharing 设置当一个缓存被多次使用时的表现,由于 BuildKit 支持并行构建,当多个步骤使用同一缓存时(同一 id)会发生冲突。shared 表示多个步骤可以同时读写,private 表示当多个步骤使用同一缓存时,每个步骤使用不同的缓存,locked 表示当一个步骤完成释放缓存后,后一个步骤才能继续使用该缓存。
from 缓存来源(构建阶段),不填写时为空文件夹。
source 来源的文件夹路径。

# RUN --mount=type=bind

该指令可以将一个镜像(或上一构建阶段)的文件挂载到指定位置。

# syntax = docker/dockerfile:experimental
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
        cat /docker-php-entrypoint

1
2
3

# RUN --mount=type=tmpfs

该指令可以将一个 tmpfs 文件系统挂载到指定位置。

# syntax = docker/dockerfile:experimental
RUN --mount=type=tmpfs,target=/temp \
        mount | grep /temp

1
2
3

# RUN --mount=type=secret

该指令可以将一个文件(例如密钥)挂载到指定位置。

# syntax = docker/dockerfile:experimental
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
        cat /root/.aws/credentials

1
2
3

$ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .

1

# RUN --mount=type=ssh

该指令可以挂载 ssh 密钥。

# syntax = docker/dockerfile:experimental
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh ssh git@gitlab.com | tee /hello

1
2
3
4
5

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker build -t test --ssh default=$SSH_AUTH_SOCK .

1
2
3
4

# 官方文档

  • https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md