zoukankan      html  css  js  c++  java
  • Dockerfile构建实践

    Dockerfile构建实践

    本文介绍了用于构建有效图像的推荐最佳实践和方法。

    Docker通过从一个Dockerfile文本文件中读取指令来自动构建映像,该文本文件按顺序包含构建给定映像所需的所有命令。ADockerfile遵循特定的格式和指令集,可以在Dockerfile参考中找到该指令。

    Docker映像由只读层组成,每个只读层代表一个Dockerfile指令。这些层是堆叠的,每个层都是与上一层相比变化的增量。考虑一下Dockerfile:

    FROM ubuntu:18.04

    COPY . /app

    RUN make /app

    CMD python /app/app.py

    每条指令创建一层:

    • FROM从ubuntu:18.04Docker映像创建一个图层。
    • COPY 从Docker客户端的当前目录添加文件。
    • RUN使用构建应用程序make。
    • CMD 指定在容器中运行什么命令。

    运行图像并生成容器时,可以在基础层之上添加一个新的可写层(“容器层”)。对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入可写容器层。

    一般准则和建议

    创建临时容器

    定义的图片Dockerfile应生成尽可能短暂的容器。“短暂”是指可以停止并销毁容器,然后对其进行重建和替换,并采用绝对的最低限度的设置和配置。

    构建环境

    启动docker build命令时,当前的工作目录称为构建上下文。默认情况下,假定Dockerfile位于此处,但是可以使用文件标志(-f)指定其它位置。无论Dockerfile实际位于何处,当前目录中文件和目录的所有递归内容,都将作为构建上下文发送到Docker守护程序。

    构建上下文示例

    为构建上下文创建一个目录并cd进入该目录。将“ hello”写入hello文本文件,然后创建一个cat在其上运行的Dockerfile。从构建上下文(.)中构建图像:

    mkdir myproject && cd myproject

    echo "hello" > hello

    echo -e "FROM busybox COPY /hello / RUN cat /hello" > Dockerfile

    docker build -t helloapp:v1 .

    移动Dockerfile并hello进入单独的目录并构建映像的第二个版本(不依赖于上次构建的缓存)。使用-f以指向Dockerfile并指定构建上下文的目录:

    mkdir -p dockerfiles context

    mv Dockerfile dockerfiles && mv hello context

    docker build --no-cache -t helloapp:v2 -f dockerfiles/Dockerfile context

    构建映像所不需要的文件,会导致较大的构建上下文和较大的映像大小。这会增加生成图像的时间,拉动和推动图像的时间以及容器运行时的大小。要查看构建上下文有多大,在构建时查找如下消息Dockerfile:

    Sending build context to Docker daemon  187.8MB

    通过stdin

    docker具有通过管道的能力来构建图像Dockerfile,通过stdin与本地或远程构建上下文。管道中的Dockerfile通过stdin 可以执行一次性构建,无需编写Dockerfile到磁盘上,或者有用Dockerfile的产生,并且不应该事后持续。

     本节中的示例使用此处的文档,但是可以使用提供Dockerfileon的任何方法stdin

    例如,以下命令是等效的:

    echo -e 'FROM busybox RUN echo "hello world"' | docker build -

    docker build -<<EOF

    FROM busybox

    RUN echo "hello world"

    EOF

    可以使用首选方法或最适合用例的方法替换示例。

    使用STDIN中的DOCKERFILE构建映像,而无需发送构建上下文

    使用此语法可使用Dockerfilefrom来构建映像stdin,而无需发送其它文件作为构建上下文。连字符(-)占据的位置PATH,并指示Docker从而不是目录中读取构建上下文(仅包含Dockerfile)stdin:

    docker build [OPTIONS] -

    以下示例使用Dockerfile传递构建图像stdin。没有文件作为构建上下文发送到守护程序。

    docker build -t myimage:latest -<<EOF

    FROM busybox

    RUN echo "hello world"

    EOF

    在Dockerfile 不需要将文件复制到映像中的情况下,省略构建上下文会很有用,并且由于没有文件发送到守护程序,因此可以提高构建速度。

    如果要通过从构建上下文中排除某些文件来提高构建速度, 使用.dockerignore进行排除

    如果使用此语法,尝试构建使用COPYADD,导致失败的Dockerfile。以下示例说明了这一点:

    # create a directory to work in

    mkdir example

    cd example

     

    # create an example file

    touch somefile.txt

     

    docker build -t myimage:latest -<<EOF

    FROM busybox

    COPY somefile.txt .

    RUN cat /somefile.txt

    EOF

     

    # observe that the build fails

    ...

    Step 2/3 : COPY somefile.txt .

    COPY failed: stat /var/lib/docker/tmp/docker-builder249218248/somefile.txt: no such file or directory

    使用STDIN中的DOCKERFILE从本地构建上下文进行构建

    使用此语法可使用本地文件系统上的文件,但使用Dockerfilefrom来构建映像stdin。该语法使用-f(或--file)选项来指定Dockerfile使用,使用连字符(-)作为文件名可指示docker读取Dockerfile从stdin:

    docker build [OPTIONS] -f- PATH

    下面的示例使用当前目录(.)作为构建上下文,并构建用的图像Dockerfile,其通过传递stdin使用这里文档

    # create a directory to work in

    mkdir example

    cd example

     

    # create an example file

    touch somefile.txt

     

    # build an image using the current directory as context, and a Dockerfile passed through stdin

    docker build -t myimage:latest -f- . <<EOF

    FROM busybox

    COPY somefile.txt .

    RUN cat /somefile.txt

    EOF

    使用STDIN中的DOCKERFILE从远程构建上下文进行构建

    使用此格式可以从远程文件来构建一个图像git库,使用Dockerfile从stdin。该语法使用-f(或--file)选项来指定Dockerfile使用,使用连字符(-)作为文件名可指示docker读取Dockerfile从stdin:

    docker build [OPTIONS] -f- PATH

    如果要从不包含的存储库中构建映像Dockerfile,或者想要使用custom来构建Dockerfile,而不维护自己的存储库派发,则此语法很有用。

    下面的示例使用Dockerfilefrom构建一个图像stdin,并添加GitHub上“ hello-world” Git存储库中的hello.c文件。

    docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF

    FROM busybox

    COPY hello.c .

    EOF

    引擎

    当使用远程Git存储库作为构建上下文构建映像时,Dockergit clone在本地计算机上执行一个存储库,并将这些文件作为构建上下文发送到守护程序。需要git在运行docker build命令的主机上安装此功能。

    排除

    要排除与构建无关的文件(无需重组源存储库),使用.dockerignore文件。该文件支持类似于.gitignore文件的排除模式。

    使用多阶段构建

    多阶段构建使可以大幅度减小最终图像的大小,而不必努力减少中间层和文件的数量。

    由于映像是在生成过程的最后阶段生成的,可以利用生成缓存来最小化映像层。

    例如,如果构建包含多个层,则可以将从更改频率较低(以确保生成缓存可重用)到更改频率较高的顺序排序:

    • 安装构建应用程序所需的工具
    • 安装或更新库依赖项
    • 生成

    Go应用程序的Dockerfile可能类似于:

    FROM golang:1.11-alpine AS build

     

    # Install tools required for project

    # Run `docker build --no-cache .` to update dependencies

    RUN apk add --no-cache git

    RUN go get github.com/golang/dep/cmd/dep

     

    # List project dependencies with Gopkg.toml and Gopkg.lock

    # These layers are only re-built when Gopkg files are updated

    COPY Gopkg.lock Gopkg.toml /go/src/project/

    WORKDIR /go/src/project/

    # Install library dependencies

    RUN dep ensure -vendor-only

     

    # Copy the entire project and build it

    # This layer is rebuilt when a file changes in the project directory

    COPY . /go/src/project/

    RUN go build -o /bin/project

     

    # This results in a single layer image

    FROM scratch

    COPY --from=build /bin/project /bin/project

    ENTRYPOINT ["/bin/project"]

    CMD ["--help"]

    不要安装不必要的软件包

    为了降低复杂性,依赖性,文件大小和构建时间,避免仅由于“很容易安装”而安装多余或不必要的软件包。例如,不需要在数据库映像中包括文本编辑器。

    解耦应用程序

    每个容器应该只有一个方面。将应用程序解耦到多个容器中,可以更轻松地水平缩放和重复使用容器。例如,一个Web应用程序堆栈可能由三个单独的容器组成,每个容器都有自己的唯一映像,以分离的方式管理Web应用程序,数据库和内存中缓存。

    将每个容器限制为一个进程是一个很好的经验法则,但这并不是一成不变的规则。例如,不仅可以使用初始化进程生成容器,而且某些程序还可以自行生成其它进程。例如,Celery可以产生多个工作进程,而Apache可以为每个求创建一个进程。

    根据最佳判断,使容器尽可能保持清洁和模块化。如果容器相互依赖,则可以使用Docker容器网络。确保这些容器可以通信。

    最小化层数

    在较旧的Docker版本中,重要的是最小化映像中的层数以确保其性能。添加了以下功能来减少此限制:

    • 只有说明RUN,COPY,ADD创建图层。其它说明创建临时的中间映像,并且不会增加构建的大小。
    • 尽可能使用多阶段构建,并且仅将所需的工件复制到最终映像中。这使可以在中间构建阶段中包含工具和调试信息,而无需增加最终映像的大小。

    排序多行参数

    只要有可能,就可以通过字母数字排序多行参数来简化以后的更改。这有助于避免软件包重复,并使列表更易于更新。这也使PR易于阅读和查看。在反斜杠()之前添加空格也有帮助。

    下面是来自一个示例buildpack-deps图像

    RUN apt-get update && apt-get install -y

      bzr

      cvs

      git

      mercurial

      subversion

      && rm -rf /var/lib/apt/lists/*

    构建缓存

    构建映像时,Docker将逐步Dockerfile执行指令,并按指定的顺序执行每个指令。检查每条指令时,Docker会在其缓存中寻找一个可以重用的现有映像,而不是创建一个新的(重复的)映像。

    如果根本不想使用缓存,则可以使用命令--no-cache=true 上的选项docker build。但是,如果确实允许Docker使用其缓存,那么了解何时可以找到匹配的映像非常重要。Docker遵循的基本规则概述如下:

    • 从已在缓存中的父映像开始,将下一条指令与从该基本映像派生的所有子映像进行比较,以查看是否其中一个是使用完全相同的指令构建的。如果不是,则高速缓存无效。
    • 在大多数情况下,只需将中的指令Dockerfile与子图像之一进行比较就足够了。但是,某些说明需要更多的检查和解释。
    • 对于ADD和COPY指令,将检查图像中文件的内容,并为每个文件计算一个校验和。在这些校验和中不考虑文件的最后修改时间和最后访问时间。在缓存查找期间,将校验和与现有映像中的校验和进行比较。如果文件中的任何内容(例如内容和元数据)已更改,则缓存将无效。
    • 除了ADD和COPY命令之外,缓存检查不会查看容器中的文件来确定缓存是否匹配。例如,在处理RUN apt-get -y update命令时,不检查容器中更新的文件以确定是否存在缓存命中。在这种情况下,仅使用命令字符串本身来查找匹配项。

    一旦缓存无效,所有后续Dockerfile命令都会生成新映像,并且不使用缓存。

    Dockerfile说明

    这些建议旨在帮助创建高效且可维护的工具Dockerfile。

    来源

    Dockerfile的FROM指令参考

    尽可能使用当前的官方图像作为图像的基础。建议使用Alpine映像,因为受到严格控制且尺寸较小(当前小于5 MB),同时仍是完整的Linux发行版。

    标签

    了解对象标签

    可以在图像上添加标签,以帮助按项目组织图像,记录许可信息,帮助自动化或其它原因。对于每个标签,添加一行LABEL并以一个或多个键值对开头。以下示例显示了不同的可接受格式。内嵌包含解释性注释。

    带有空格的字符串必须用引号引起来,否则必须转义空格。内引号(")也必须转义。

    # Set one or more individual labels

    LABEL com.example.version="0.0.1-beta"

    LABEL vendor1="ACME Incorporated"

    LABEL vendor2=ZENITH Incorporated

    LABEL com.example.release-date="2015-02-12"

    LABEL com.example.version.is-production=""

    一幅图像可以有多个标签。在Docker 1.10之前,建议将所有标签合并为一条LABEL指令,以防止创建额外的层。不再需要此操作,但仍支持组合标签。

    # Set multiple labels on one line

    LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"

    上面也可以写成:

    # Set multiple labels at once, using line-continuation characters to break long lines

    LABEL vendor=ACME Incorporated

          com.example.is-beta=

          com.example.is-production=""

          com.example.version="0.0.1-beta"

          com.example.release-date="2015-02-12"

    运行

    RUN指令的Dockerfile参考

    将多行长或复杂的RUN语句分割成多行,并用反斜杠分隔,以使Dockerfile更具可读性,可理解性和可维护性。

    适当的

    可能最常见的用例RUN是的应用apt-get。因为它安装了软件包,所以该RUN apt-get命令需要注意一些陷阱。

    避免RUN apt-get upgrade和dist-upgrade,因为许多从父图像的“基本”套餐的不能内部升级特权的容器。如果父映像中包含的软件包已过期,联系其维护者。如果知道foo需要更新的特定软件包,使用 apt-get install -y foo来自动更新。

    始终在同一条语句中结合RUN apt-get update使用。例如:apt-get installRUN

    RUN apt-get update && apt-get install -y

        package-bar

        package-baz

        package-foo 

        && rm -rf /var/lib/apt/lists/*

    apt-get update在RUN语句中单独使用会导致缓存问题,并且后续apt-get install指令会失败。例如,假设有一个Dockerfile:

    FROM ubuntu:18.04

    RUN apt-get update

    RUN apt-get install -y curl

    构建映像后,所有层都在Docker缓存中。假设以后apt-get install通过添加额外的程序包进行修改:

    FROM ubuntu:18.04

    RUN apt-get update

    RUN apt-get install -y curl nginx

    Docker将初始指令和修改后的指令视为相同,并重复使用先前步骤中的缓存。其结果是,apt-get update在执行,因为编译使用缓存的版本。由于apt-get update未运行,因此构建可能会获得curl和 nginx包的过时版本。

    使用RUN apt-get update && apt-get install -y确保Dockerfile安装了最新的软件包版本,而无需进一步的编码或手动干预。这种技术称为“缓存清除”。还可以通过指定软件包版本来实现缓存清除。这称为版本固定,例如:

    RUN apt-get update && apt-get install -y

        package-bar

        package-baz

        package-foo=1.3.*

    版本固定会强制构建检索特定版本,而不管缓存中的内容是什么。还可以减少由于所需包装中的意外更改而导致的故障。

    以下是格式正确的RUN说明,其中演示了所有apt-get 建议。

    RUN apt-get update && apt-get install -y

        aufs-tools

        automake

        build-essential

        curl

        dpkg-sig

        libcap-dev

        libsqlite3-dev

        mercurial

        reprepro

        ruby1.9.1

        ruby1.9.1-dev

        s3cmd=1.1.*

     && rm -rf /var/lib/apt/lists/*

    该s3cmd参数指定一个版本1.1.*。如果映像先前使用的是旧版本,则指定新版本会导致缓存崩溃,apt-get update并确保安装新版本。在每行上列出软件包还可以防止软件包重复中的错误。

    此外,/var/lib/apt/lists由于通过将apt缓存未存储在图层中来清理apt缓存时,它会减小图像大小。由于该 RUN语句开头为apt-get update,因此包缓存始终在之前刷新apt-get install。

    官方的Debian和Ubuntu映像会自动运行apt-get clean,因此不需要显式调用。

    使用管道

    某些RUN命令取决于使用管道字符(|)将一个命令的输出管道传输到另一个命令的能力,如以下示例所示:

    RUN wget -O - https://some.site | wc -l > /number

    Docker使用/bin/sh -c解释器执行这些命令,该解释器仅评估管道中最后一个操作的退出代码以确定成功。在上面的示例中,只要wc -l命令成功,即使wget命令失败,该构建步骤也会成功并生成一个新映像。

    如果希望由于管道中的任何阶段的错误而导致命令失败,添加前缀set -o pipefail &&以确保意外错误可以防止构建意外成功。例如:

    RUN set -o pipefail && wget -O - https://some.site | wc -l > /number

    并非所有的外壳程序都支持该-o pipefail选项。

    在诸如dash基于Debian的映像上的shell之类的情况下,考虑使用exec形式的RUN显式选择确实支持该pipefail选项的shell 。例如:

    RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]

    CMD 

    CMD指令的Dockerfile参考

    该CMD说明应与任何参数一起用于运行映像中包含的软件。CMD应该几乎总是以的形式使用CMD ["executable", "param1", "param2"…]。因此,如果映像用于服务(例如Apache和Rails),则应运行CMD ["apache2","-DFOREGROUND"]。实际上,建议将这种形式的指令用于任何基于服务的映像。

    在大多数其它情况下,CMD应使用交互式外壳程序,例如bash,python和perl。例如,CMD ["perl", "-de0"],CMD ["python"],或CMD ["php", "-a"]。使用这种形式意味着执行诸如之类的东西时 docker run -it python,将被放入一个可用的shell中,可以开始使用了。除非和预期用户已经非常熟悉其工作CMD方式,否则应该很少将其与CMD ["param", "param"]结合使用。ENTRYPOINTENTRYPOINT

    暴露

    Dockerfile的EXPOSE指令参考

    该EXPOSE指令指示容器在其上侦听连接的端口。因此,应该为应用程序使用通用的传统端口。例如,包含Apache Web服务器EXPOSE 80的图像将使用,而包含MongoDB的图像将使用EXPOSE 27017等等。

    对于外部访问,用户可以执行docker run带有标志的执行,该标志指示如何将指定端口映射到他们选择的端口。对于容器链接,Docker为从接收者容器到源容器(即MYSQL_PORT_3306_TCP)的路径提供了环境变量。

    ENV 

    ENV指令的Dockerfile参考

    为了使新软件更易于运行,可以使用ENV更新PATH容器所安装软件的 环境变量。例如,ENV PATH=/usr/local/nginx/bin:$PATH确保其CMD ["nginx"] 正常工作。

    该ENV指令对于提供特定于要容器化的服务的必需环境变量(例如Postgres的)也很有用 PGDATA。

    最后,ENV还可以用来设置常用的版本号,以便更容易维护版本凹凸,如以下示例所示:

    ENV PG_MAJOR=9.3

    ENV PG_VERSION=9.3.4

    RUN curl -SL https://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgres && …

    ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH

    与在程序中具有恒定变量(与硬编码值相反)类似,此方法使可以更改一条ENV指令以自动神奇地修改容器中软件的版本。

    每ENV行都创建一个新的中间层,就像RUN命令一样。这意味着即使在以后的层中取消设置环境变量,它也仍将保留在该层中,并且其值可以转储。可以通过创建如下所示的Dockerfile,然后对其进行构建来进行测试。

    FROM alpine

    ENV ADMIN_USER="mark"

    RUN echo $ADMIN_USER > ./mark

    RUN unset ADMIN_USER

    $ docker run --rm test sh -c 'echo $ADMIN_USER'

     

    mark

    为避免这种情况,并真正取消设置环境变量,使用RUN带有shell命令的命令来在单个层中全部设置,使用和取消设置该变量。可以使用;或分隔命令&&。如果使用第二种方法,并且其中一个命令失败,则命令docker build也将失败。这通常是个好主意。使用作为Linux的Dockerfiles续行符提高可读性。还可以将所有命令放入一个Shell脚本中,并让该RUN命令仅运行该Shell脚本。

    FROM alpine

    RUN export ADMIN_USER="mark"

        && echo $ADMIN_USER > ./mark

        && unset ADMIN_USER

    CMD sh

    $ docker run --rm test sh -c 'echo $ADMIN_USER'

    添加或复制

    尽管ADD和COPY在功能上相似,但是一般来说COPY 是优选的。那是因为它比透明ADD。COPY仅支持将本地文件基本复制到容器中,而ADD具有一些功能(例如,仅本地tar提取和远程URL支持)并不立即显而易见。因此,最好的用途ADD是将本地tar文件自动提取到映像中,如中所示ADD rootfs.tar.xz /。

    如果有多个Dockerfile步骤使用了上下文中的不同文件,COPY则应单独执行而不是一次执行。这样可以确保仅在特别需要的文件发生更改的情况下,才使每个步骤的构建缓存无效(强制重新运行该步骤)。

    例如:

    COPY requirements.txt /tmp/

    RUN pip install --requirement /tmp/requirements.txt

    COPY . /tmp/

    与在RUN步骤COPY . /tmp/之前放置缓存相比,该步骤 导致更少的缓存无效化。

    由于图像大小很重要,ADD因此强烈建议不要使用从远程URL获取软件包的方法。应该使用curl或wget代替。这样,可以在提取文件后删除不再需要的文件,而不必在图像中添加另一层。例如,应该避免做以下事情:

    ADD https://example.com/big.tar.xz /usr/src/things/

    RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

    RUN make -C /usr/src/things all

    相反,执行以下操作:

    RUN mkdir -p /usr/src/things

        && curl -SL https://example.com/big.tar.xz

        | tar -xJC /usr/src/things

        && make -C /usr/src/things all

    对于不需要ADDtar自动提取功能的其它项目(文件,目录),应始终使用COPY。

    入口点

    ENTRYPOINT指令的Dockerfile参考

    最好的用法ENTRYPOINT是设置映像的主命令,使该映像像该命令一样运行(然后CMD用作默认标志)。

    让从命令行工具的图像示例开始s3cmd:

    ENTRYPOINT ["s3cmd"]

    CMD ["--help"]

    现在可以像这样运行图像以显示命令的帮助:

    $ docker run s3cmd

    或使用正确的参数执行命令:

    $ docker run s3cmd ls s3://mybucket

    这很有用,因为映像名称可以用作对二进制文件的引用,如上面的命令所示。

    该ENTRYPOINT指令也可以与辅助脚本结合使用,即使启动该工具可能需要一个以上的步骤,也可以使其以与上述命令类似的方式起作用。

    例如,Postgres Official Image 使用以下脚本作为其脚本ENTRYPOINT:

    #!/bin/bash

    set -e

     

    if [ "$1" = 'postgres' ]; then

        chown -R postgres "$PGDATA"

     

        if [ -z "$(ls -A "$PGDATA")" ]; then

            gosu postgres initdb

        fi

     

        exec gosu postgres "$@"

    fi

     

    exec "$@"

    将应用程序配置为PID 1

    此脚本使用的execbash命令 ,以使最终运行的应用程序成为容器的PID 1.这允许应用程序接收发送到所述容器任何Unix信号。

    将帮助程序脚本复制到容器中,并通过ENTRYPOINT在容器启动时运行:

    COPY ./docker-entrypoint.sh /

    ENTRYPOINT ["/docker-entrypoint.sh"]

    CMD ["postgres"]

    该脚本允许用户以多种方式与Postgres进行交互。

    它可以简单地启动Postgres:

    $ docker run postgres

    或者,它可以用于运行Postgres并将参数传递给服务器:

    $ docker run postgres postgres --help

    最后,它也可以用于启动一个完全不同的工具,例如Bash:

    $ docker run --rm -it postgres bash

    Volume

    VOLUME指令的Dockerfile参考

    该VOLUME指令应用于公开由Docker容器创建的任何数据库存储区,配置存储或文件/文件夹。强烈建议VOLUME将图像用于任何可变和/或用户可维修的部分。

    用户

    USER指令的Dockerfile参考

    如果服务可以在没有特权的情况下运行,使用USER更改为非root用户。通过创建在用户和组开始Dockerfile喜欢的东西RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres。

    考虑一个明确的UID / GID

    为图像中的用户和组分配了不确定的UID / GID,因为无论图像重建如何,都将分配“下一个” UID / GID。因此,如果很关键,则应分配一个明确的UID / GID。

    由于Go存档/ tar软件包处理稀疏文件中的一个未解决的错误,尝试在Docker容器内创建具有非常大的UID的用户可能会导致磁盘耗尽,因为/var/log/faillog在容器层中填充了NULL( 0)字符。解决方法是将--no-log-init标志传递给useradd。Debian / Ubuntuadduser包装器不支持此标志。

    避免安装或使用sudo它具有不可预测的TTY和信号转发行为,这可能会引起问题。如果绝对需要类似的功能sudo,例如将守护程序初始化为,root但以非运行方式运行root,考虑使用“ gosu”

    最后,为减少层次和复杂性,避免USER频繁地来回切换。

    WORKDIR 

    适用于WORKDIR指令的Dockerfile参考

    为了清楚和可靠起见,应始终为使用绝对路径 WORKDIR。另外,应该使用WORKDIR而不是像那样RUN cd … && do-something繁琐的说明,这些说明难以阅读,排除故障和维护。

    Build

    适用于ONBUILD指令的Dockerfile参考

    一个ONBUILD命令将当前执行后Dockerfile构建完成。 ONBUILD在派生FROM当前图像的任何子图像中执行。将ONBUILD命令视为父母Dockerfile对孩子的指示Dockerfile。

    Docker构建ONBUILD在子级中的任何命令之前先执行命令 Dockerfile。

    ONBUILD对于将要构建FROM给定图像的图像很有用。例如,将使用ONBUILD一个语言堆栈映像,该映像构建Dockerfile在Ruby中ONBUILD以该语言编写的任意用户软件,正如在Ruby的变体中所看到的那样。

    使用生成的图像ONBUILD应获得一个单独的标签,例如: ruby:1.9-onbuild或ruby:2.0-onbuild。

    放入ADD或COPY放入时要小心ONBUILD。如果新构建的上下文缺少要添加的资源,则“ onbuild”映像将灾难性地失败。如上所述,添加一个单独的标签可以允许Dockerfile做出选择,从而有助于缓解这种情况。

    人工智能芯片与自动驾驶
  • 相关阅读:
    匿名函数
    Ajax
    Mysql 数据库操作
    Linux下查看apache连接数
    c++ 当输入的数据不符合数据类型时,清理输入流
    c++ 将输入存储到数组,然后反转数组,最后输出
    c++ 递归求一个数的阶乘
    c++ 计算彩票中奖概率
    c++ 结构体,设置物品体积并输出物品属性
    c++ 输入10个数,显示它的平均分
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/14553179.html
Copyright © 2011-2022 走看看