Dockerfile 目前可扩展的语法
最近在调整公司项目的 CI,目前主要使用 GitLab CI,在尝试多阶段构建中踩了点坑,然后发现了一些有意思的玩意
本文参考:
一、起因
公司目前主要使用 GitLab CI 作为主力 CI 构建工具,而且由于机器有限,我们对一些包管理器的本地 cache 直接持久化到了本机;比如 maven 的 .m2 目录,nodejs 的 .npm 目录等;虽然我们创建了对应的私服,但是在 build 时毕竟会下载,所以当时索性调整 GitLab Runner 在每个由 GitLab Runner 启动的容器中挂载这些缓存目录(GitLab CI 在 build 时会新启动容器运行 build 任务);今天调整 nodejs 项目浪了一下,直接采用 Dockerfile 的 multi-stage build 功能进行 “Build => Package(docker image)” 的实现,基本 Dockerfile 如下
1 | |
本来这个 cnpm 命令是带有 cache 的(见这里),不过运行完 build 以后发现很慢,检查宿主机 cache 目录发现根本没有 cache…然后突然感觉

仔细想想,情况应该是这样事儿的…
1 | |

后来经过查阅文档,发现 Dockerfile 是有扩展语法的(当然最终我还是没用),具体请见下篇文章(我怕被打死)下面,先说好,下面的内容无法完美的解决上面的问题,目前只是支持了一部分功能,当然未来很可能支持类似 IF ELSE 语法、直接挂载宿主机目录等功能
二、开启 Dockerfile 扩展语法
2.1、开启实验性功能
目前这个扩展语法还处于实验性功能,所以需要配置 dockerd 守护进程,修改如下
1 | |
主要是 --experimental 参数,参考官方文档;同时在 build 前声明 export DOCKER_BUILDKIT=1 变量
2.2、修改 Dockerfile
开启实验性功能后,只需要在 Dockerfile 头部增加 # syntax=docker/dockerfile:experimental 既可;为了保证稳定性,你也可以指定具体的版本号,类似这样
1 | |
2.3、可用的扩展语法
RUN --mount=type=bind
这个是默认的挂载模式,这个允许将上下文或者镜像以可都可写/只读模式挂载到 build 容器中,可选参数如下(不翻译了)
| Option | Description |
|---|---|
target (required) | Mount path. |
source | Source path in the from. Defaults to the root of the from. |
from | Build stage or image name for the root of the source. Defaults to the build context. |
rw,readwrite | Allow writes on the mount. Written data will be discarded. |
RUN --mount=type=cache
专用于作为 cache 的挂载位置,一般用于 cache 包管理器的下载等
| Option | Description |
|---|---|
id | Optional ID to identify separate/different caches |
target (required) | Mount path. |
ro,readonly | Read-only if set. |
sharing | One of shared, private, or locked. Defaults to shared. A shared cache mount can be used concurrently by multiple writers. private creates a new mount if there are multiple writers. locked pauses the second writer until the first one releases the mount. |
from | Build stage to use as a base of the cache mount. Defaults to empty directory. |
source | Subpath in the from to mount. Defaults to the root of the from. |
Example: cache Go packages
1 | |
Example: cache apt packages
1 | |
RUN --mount=type=tmpfs
专用于挂载 tmpfs 的选项
| Option | Description |
|---|---|
target (required) | Mount path. |
RUN --mount=type=secret
这个类似 k8s 的 secret,用来挂载一些不想打入镜像,但是构建时想使用的密钥等,例如 docker 的 config.json,S3 的 credentials
| Option | Description |
|---|---|
id | ID of the secret. Defaults to basename of the target path. |
target | Mount path. Defaults to /run/secrets/ + id. |
required | If set to true, the instruction errors out when the secret is unavailable. Defaults to false. |
mode | File mode for secret file in octal. Default 0400. |
uid | User ID for secret file. Default 0. |
gid | Group ID for secret file. Default 0. |
Example: access to S3
1 | |
注意: buildctl 是 BuildKit 的命令,你要测试的话自己换成 docker build 相关参数
1 | |
RUN --mount=type=ssh
允许 build 容器通过 SSH agent 访问 SSH key,并且支持 passphrases
| Option | Description |
|---|---|
id | ID of SSH agent socket or key. Defaults to “default”. |
target | SSH agent socket path. Defaults to /run/buildkit/ssh_agent.${N}. |
required | If set to true, the instruction errors out when the key is unavailable. Defaults to false. |
mode | File mode for socket in octal. Default 0600. |
uid | User ID for socket. Default 0. |
gid | Group ID for socket. Default 0. |
Example: access to Gitlab
1 | |
1 | |
你也可以直接使用宿主机目录的 pem 文件,但是带有密码的 pem 目前不支持
目前根据文档测试,当前的挂载类型比如 cache 类型,仅用于 multi-stage 内的挂载,比如你有 2+ 个构建步骤,cache 挂载类型能帮你在各个阶段内共享文件;但是它目前无法解决直接将宿主机目录挂载到 multi-stage 的问题(可以采取些曲线救国方案,但是很不优雅);但是未来还是很有展望的,可以关注一下