手臂, 码头工人

在2019年构建Docker容器

距集装箱爆炸已经过去了几年,生态系统开始稳定下来。在行业中的所有知名企业加入到容器化旅行车中之后,他们常常提出自己的解决方案,看来基于Docker的平台终于可以保留了。

Docker成为 实际上 标准方面,已经发生了许多事情,大多数情况是在幕后。这 开放式容器激励 (OCI)的创建旨在标准化运行时间和图像格式,而Docker更改了其内部管道以适应诸如实施 运行, 和 容器垫片.

现在,经过多年的Docker冻结其面向用户的API之后,我们开始再次看到这方面的动向,并且我们习惯于在构建和运行容器时看到的许多常见做法可能有更好的选择。其他事物刚刚被弃用或失宠。

构建套件在这里

现在,可以使用 构建套件 后端。该后端比经典后端更智能,并且能够通过实现更智能的缓存,并行化构建步骤并接受新的Dockerfile选项来加快构建过程。引用 官方文件

从版本18.09开始,Docker支持由moby / buildkit项目提供的用于执行构建的新后端。与旧的实现相比,BuildKit后端提供了许多好处。例如,BuildKit可以:检测并跳过执行未使用的构建阶段并行构建独立的构建阶段在两次构建之间逐步仅转移构建上下文中已更改的文件在构建上下文中检测并跳过未使用的文件使用具有许多新功能的外部Dockerfile实现避免使用-其余API的效果(中间图像和容器)对构建缓存进行优先级排序以进行自动修剪。

In order to select this backend, we export the environment variable DOCKER_BUILDKIT=1. If you miss the detailed output, just add --progress=plain.

使用多阶段构建

We are used to seeing a lot of trickery to try to keep each layer size to a minimum. Very often we use a RUN statement to download the source and build an artifact, for instance a .deb file or to compile a binary, and try to clean it up in the same statement to keep the layer tidy.

RUN \
    apt-get update ; \
    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y git make gcc libc-dev ; \
    git clone //github.com/some_repo ; \
    cd some_repo ; \
    ./configure ; \
    make ; \
    make install; \
    cd -; \
    rm -rf some_repo; \
    apt-get purge -y make gcc libc-dev git; \
    apt-get autoremove -y; \
    apt-get clean; \
    find /var/lib/apt/lists -type f | xargs rm; \
    find /var/log -type f -exec rm {} \;; \
    rm -rf /usr/share/man/*; \
    rm -rf /usr/share/doc/*; \
    rm -f /var/log/alternatives.log /var/log/apt/*; \
    rm /var/cache/debconf/*-old

这既浪费每个构建的时间,又很难做到。最好用 多阶段构建.

FROM debian:stretch-slim AS some_bin

RUN apt-get update; \
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-    recommends git make gcc libc-dev; \
    git clone //github.com/some_repo; \
    cd some_repo; \
    ./configure; \
    make

FROM debian:stretch-slim

COPY --from=some_bin /root/some_repo/some_bin /usr/local/bin/

在某些情况下,为了避免这种情况,我看到人们在git存储库中添加了一个二进制blob,以便可以对其进行复制。使用这种方法更好。

使用–squash

虽然没有’对于每个Dockerfile总是有意义的,我们经常可以压缩第一层并获得更可维护的Dockerfile。

--squash 是一个实验性参数,需要像我们解释的那样启用 这里。代替

RUN apt-get update; \
    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y mariadb; \
    apt-get autoremove -y; \
    apt-get clean; \
    find /var/lib/apt/lists -type f | xargs rm; \
    find /var/log -type f -exec rm {} \;; \
    rm -rf /usr/share/man/*; \
    rm -rf /usr/share/doc/*; \
    rm -f /var/log/alternatives.log /var/log/apt/*; \
    rm /var/cache/debconf/*-old

, 我们能做的

RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y mariadb
RUN apt-get autoremove -y
RUN apt-get clean
RUN find /var/lib/apt/lists -type f | xargs rm
RUN find /var/log -type f -exec rm {} \;
RUN rm -rf /usr/share/man/*
RUN rm -rf /usr/share/doc/*
RUN rm -f /var/log/alternatives.log /var/log/apt/*
RUN rm /var/cache/debconf/*-old

对所有架构使用一个Dockerfile

We talked about a technique to use e木-user-static for creating builds for different architectures in a 过去的文章. When building different versions of the same image for different architectures, it is very common to see three exact copies of the same Dockerfile where the only thing that changes is the FROM line.

FROM debian:stretch-slim
# the rest of the file is duplicated
FROM armhf/debian:stretch-slim
# the rest of the file is duplicated
FROM arm64v8/debian:stretch-slim
# the rest of the file is duplicated

像这样只有一个文件

ARG arch
FROM ${arch}/debian:stretch-slim

,并使用

码头工人 build . --build-arg arch=amd64
docker build . --build-arg arch=armhf
docker build . --build-arg arch=arm64v8

使用多架构清单

因此,我们现在使用一个Dockerfile进行了三个构建,并以此标记它们

码头工人 build . --build-arg arch=amd64   -t ownyourbits/example-x86
docker build . --build-arg arch=armhf   -t ownyourbits/example-armhf
docker build . --build-arg arch=arm64v8 -t ownyourbits/example-arm64

那’很好,但是我们现在可以通过创建一个 多拱清单.

This is still an experimental CLI feature, so we need to export DOCKER_CLI_EXPERIMENTAL=enabled to be able to access it.

export DOCKER_CLI_EXPERIMENTAL=enabled
docker manifest create --amend ownyourbits/example \
  ownyourbits/example-x86 \
  ownyourbits/example-armhf \
  ownyourbits/example-arm64

docker manifest annotate ownyourbits/example ownyourbits/example-x86   --os linux --arch amd64
docker manifest annotate ownyourbits/example ownyourbits/example-armhf --os linux --arch arm
docker manifest annotate ownyourbits/example ownyourbits/nextcloudpi-arm64 --os linux --arch arm64v8

docker manifest push -p ownyourbits/example

现在,任何架构的用户都只需要做

码头工人 pull ownyourbits/example

,他们将收到图像的正确版本。

添加健康检查

Even if we run with --restart=unless-stopped, the only clue Docker or Docker Swarm to know that things are OK is that the container has not crashed. If it is unresponsive or returning errors it won’不能正确重启。

It is more robust to add a HEALTHCHECK statement to the Dockerfile

HEALTHCHECK CMD curl --fail http://localhost:8080/status || exit 1

大学教师’t run as root

即使容器在理论上是隔离的,但以与root用户相同的方式在其内部以root身份运行进程也不是一个好的安全实践’t以根用户身份运行Web服务器。

在构建结束时,您应该添加以下内容

RUN \
    # other stuff
    useradd nonroot

USER nonroot

Also, if possible avoid relying on sudo and if you don’t control the Dockerfile at least run in a different user namespace with 码头工人 run -u nonroot:nonroot.

大学教师’别忘了用–pull

使用码头工人 build --pull in your scripts so you are always on the latest base image.

大学教师’t use MAINTAINER

MAINTAINER 不推荐使用。代替

MAINTAINER nachoparker (nacho@ownyourbits.com)

, use LABELs instead so they can be inspected just like any other metadata.

LABEL maintainer="纳乔帕克 (nacho@ownyourbits.com)"

尽可能避免使用ENV

ENV variables remain in the container at run time and pollute its own environment. Use ARGs instead.

使用缓存安装进行构建

通过为包管理器,ccache,git等提供缓存来加快构建速度。这需要启用 DOCKER_CLI_EXPERIMENTAL=enabled

# syntax=docker/dockerfile:experimental

# FROM and the rest

RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
    apt-get install -y --no-install-recommends mongodb-server

使用SSH代理

如果您需要SSH凭据进行构建,请不要’t copy ~/.ssh because it will stay in the layer even if you remove it later.
设置 SSH代理,并将实验功能用于 ssh挂载

RUN --mount=type=ssh git clone //github.com/private_repo/repo.git

使用构建机密

如果您需要不应该公开的敏感文件,请使用 机密. This way, those files will only be visible to that RUN command during its execution and its contents will disappear without a trace from all layers after that.

RUN --mount=type=secret,id=signing_key,dst=/tmp/sign.cert signing_command

再次阅读官方建议

虽然我指出对我来说最大的罪犯是什么,但回顾一下官方建议 最佳做法.

我们大多数人都熟悉:编写小型容器,重新排列图层以利用构建缓存,’添加不必要的软件包,但是’回到它并发现我们之前可能错过的东西并不少见。

作者: nachoparker

谦虚地分享我认为有用的东西 [ 的github 码头工人hub ]

2 Comments

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *