Py学习  »  docker

Dockerfile 目前可扩展的语法

K8S中文社区 • 4 年前 • 373 次点击  

作者:漠然,原文:

https://mritd.me/2019/05/13/dockerfile-extended-syntax/

最近在调整公司项目的 CI,目前主要使用 GitLab CI,在尝试多阶段构建中踩了点坑,然后发现了一些有意思的玩意

本文参考:

  • Dockerfile frontend experimental syntaxes

  • Advanced multi-stage build patterns

  • docker build Document

一、起因

公司目前主要使用 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 如下

FROM gozap/build as builder
COPY . /xxxx
WORKDIR /xxxx
RUN source ~/.bashrc \ && cnpm install \ && cnpm run build
FROM gozap/nginx-react:v1.0.0
LABEL maintainer="mritd "
COPY --from=builder /xxxx/public /usr/share/nginx/html
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]

本来这个 cnpm 命令是带有 cache 的(见这里),不过运行完 build 以后发现很慢,检查宿主机 cache 目录发现根本没有 cache…然后突然感觉

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

+------------+                +-------------+            +----------------+|            |                |             |            |                ||            |                |    build    |            |   Multi-stage  ||   Runner   +--------------->+  conatiner  +----------->+     Build      ||            |                |             |            |                ||            |                |             |            |                |+------------+                +------+------+            +----------------+                                     ^                                     |                                     |                                     |                                     |                              +------+------+                              |             |                              |    Cache    |                              |             |                              +-------------+

后来经过查阅文档,发现 Dockerfile 是有扩展语法的(当然最终我还是没用),具体请见下篇文章(我怕被打死)下面,先说好,下面的内容无法完美的解决上面的问题,目前只是支持了一部分功能,当然未来很可能支持类似 IF ELSE 语法、直接挂载宿主机目录等功能

二、开启 Dockerfile 扩展语法

2.1、开启实验性功能

目前这个扩展语法还处于实验性功能,所以需要配置 dockerd 守护进程,修改如下

ExecStart=/usr/bin/dockerd  -H unix:// \                            --init \                            --live-restore \                            --data-root=/data/docker \                            --experimental \                            --log-driver json-file \                            --log-opt max-size=30m \                            --log-opt max-file=3

主要是 --experimental 参数,参考官方文档;同时在 build 前声明 export DOCKER_BUILDKIT=1 变量

2.2、修改 Dockerfile

开启实验性功能后,只需要在 Dockerfile 头部增加 # syntax=docker/dockerfile:experimental既可;为了保证稳定性,你也可以指定具体的版本号,类似这样

# syntax=docker/dockerfile:1.1.1-experimentalFROM tomcat

2.3、可用的扩展语法

  • RUN --mount=type=bind

这个是默认的挂载模式,这个允许将上下文或者镜像以可都可写/只读模式挂载到 build 容器中,可选参数如下(不翻译了)

OptionDescription
target(required)Mount path.
sourceSource path in the from. Defaults to the root of the from.
fromBuild stage or image name for the root of the source. Defaults to the build context.
rw,readwriteAllow writes on the mount. Written data will be discarded.
  • RUN --mount=type=cache

专用于作为 cache 的挂载位置,一般用于 cache 包管理器的下载等

OptionDescription
idOptional ID to identify separate/different caches
target(required)Mount path.
ro,readonlyRead-only if set.
sharingOne of sharedprivate, 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.
fromBuild stage to use as a base of the cache mount. Defaults to empty directory.
sourceSubpath in the from to mount. Defaults to the root of the from.

Example: cache Go packages

# syntax = docker/dockerfile:experimentalFROM golang...RUN --mount=type=cache,target=/root/.cache/go-build go build ...

Example: cache apt packages

# syntax = docker/dockerfile:experimentalFROM ubuntuRUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cacheRUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \  apt update && apt install -y gcc
  • RUN --mount=type=tmpfs

专用于挂载 tmpfs 的选项

OptionDescription
target (required)Mount path.
  • RUN --mount=type=secret

这个类似 k8s 的 secret,用来挂载一些不想打入镜像,但是构建时想使用的密钥等,例如 docker 的 config.json,S3 的 credentials

OptionDescription
idID of the secret. Defaults to basename of the target path.
targetMount path. Defaults to /run/secrets/ + id.
requiredIf set to true, the instruction errors out when the secret is unavailable. Defaults to false.
modeFile mode for secret file in octal. Default 0400.
uidUser ID for secret file. Default 0.
gidGroup ID for secret file. Default 0.

Example: access to S3

# syntax = docker/dockerfile:experimentalFROM python:3RUN pip install awscliRUN --mount=type=secret,id=aws,target=/root/.aws/credentials aws s3 cp s3://... ...

注意: buildctl 是 BuildKit 的命令,你要测试的话自己换成 docker build 相关参数

$ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. \  --secret id=aws,src=$HOME/.aws/credentials
  • RUN --mount=type=ssh

允许 build 容器通过 SSH agent 访问 SSH key,并且支持 passphrases

OptionDescription
idID of SSH agent socket or key. Defaults to “default”.
targetSSH agent socket path. Defaults to /run/buildkit/ssh_agent.${N}.
requiredIf set to true, the instruction errors out when the key is unavailable. Defaults to false.
mode File mode for socket in octal. Default 0600.
uidUser ID for socket. Default 0.
gidGroup ID for socket. Default 0.

Example: access to Gitlab

# syntax = docker/dockerfile:experimentalFROM alpineRUN apk add --no-cache openssh-clientRUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hostsRUN --mount=type=ssh ssh -q -T git@gitlab.com 2>&1 | tee /hello# "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here# with the type of build progress is defined as `plain`.
$ eval $(ssh-agent)$ ssh-add ~/.ssh/id_rsa(Input your passphrase here)$ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. \  --ssh default=$SSH_AUTH_SOCK

你也可以直接使用宿主机目录的 pem 文件,但是带有密码的 pem 目前不支持

目前根据文档测试,当前的挂载类型比如 cache 类型,仅用于 multi-stage 内的挂载,比如你有 2+ 个构建步骤,cache 挂载类型能帮你在各个阶段内共享文件;但是它目前无法解决直接将宿主机目录挂载到 multi-stage 的问题(可以采取些曲线救国方案,但是很不优雅);但是未来还是很有展望的,可以关注一下

推荐阅读

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/38275
 
373 次点击