[docker] Dockerfile详解

0 序

1 Docerfile 概述与详解

1.1 什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

DockerFileDocker的一个配置文件,本质上来说它只是一个文本文件,它是用来构建【Docker镜像】的。
DockerFile配置文件中包含了一系列的指令配置信息,用于描述如何构建镜像以及如何运行容器。
通过编写 Dockerfile,我们可以将构建 Docker 镜像的【过程】自动化,实现应用程序的快速部署迭代

1.2 如何使用 Dockerfile 定制镜像?(简单样例)

这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解,将在下一节中介绍,这里你只要知道构建的流程即可。

  • 1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html

  • 2、FROM 和 RUN 指令的作用

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

  • shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
  • exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

以上执行会创建 3 层镜像。可简化为以下格式:

FROM centos
RUN yum -y install wget \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
    && tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

1.3 Dockerfile的基本结构

  • Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。一般而言,Dockerfile,分为四部分:
  • 基础镜像信息;
  • 维护者信息;
  • 镜像操作指令;
  • 和容器启动时执行指令

例如:

# This Dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
FROM ubuntu
# Maintainer: docker_user <docker_user at email.com> (@docker_user)
MAINTAINER docker_user docker_user@email.com
# Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/
sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Commands when creating a new container
CMD /usr/sbin/nginx

其中,一开始必须指明【所基于的镜像名称】,接下来一般是说明维护者信息,后面则是镜像操作指令,例如 RUN 指令,RUN 指令将对镜像执行跟随的命令。每运行一条 RUN 指令,镜像就添加新的一层,并提交。最后是 CMD 指令,用来指定运行容器时的操作命令。

1.4 Dockerfile 指令清单

指令 说明
FROM 指定所创建镜像的基础镜像
MAINTAINER 指定维护者信息
RUN 运行命令
CMD 指定容器启动时默认执行的命令
LABEL 指定生成镜像的元数据标签信息
EXPOSE 声明镜像内服务所监听的端口
ENV 指定环境变量
ADD 复制指定的 路径下的内容到容器中的 路径下, 可以为 URL;如果为 tar 文件,会自动解压到 路径下
COPY 复制本地主机的 路径下的内容到镜像中的 路径下;一般情况下推荐使用 COPY 而不是 ADD
ENTRYPOINT 指定镜像的默认入口
VOLUME 创建数据卷挂载点
WORKDIR 配置工作目录
ARG 指定镜像内使用的参数 (例如版本号信息等)
ONBUILD 配置当所创建的镜像作为其它镜像的基础镜像时,所执行的创建操作指令
STOPSIGNAL 容器退出的信号值
HEALTHCHECK 如何进行健康检查
SHELL 指定使用 shell 时的默认 shell 类型

1.4.1 FROM

指定所创建镜像的基础镜像,如果本地不存在,则默认会去 Docker Hub 下载指定镜像。格式为

FROM <image> 
FROM <image>:<tag>
FROM <image>@<digest>

FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]

任何 Dockerfile 中的第一条指令必须为 FROM 指令。并且,如果在同一个 Dockerfile 中创建多个镜像,可以使用多个 FROM 指令(每个镜像一次)。

Dockerfile 中可以多次出现 FROM 指令,当 FROM 第二次或者之后出现时,表示在此刻构建时,要将当前指出镜像的内容合并到此刻构建镜像的内容里。这对于我们直接合并两个镜像的功能很有帮助。

1.4.2 MAINTAINER

  • 指定维护者信息,格式为
MAINTAINER <name> <email>

例如:

MAINTAINER image_creator@docker.com

该信息会写入生成镜像的 Author 属性域中。

1.4.3 RUN

RUN 指令在新镜像内部执行的命令,如:执行某些动作、安装系统软件、配置系统信息之类。格式为

RUN <command> 
或 
RUN ["executable","param1","param2"]

注意,后一个指令会被解析为 Json 数组,因此必须用双引号。前者默认将在 shell 终端中运行命令,即 /bin/sh -c ;后者则使用 exec 执行,不会启动 shell 环境。
指定使用其他终端类型可以通过第二种方式实现,例如

RUN ["/bin/bash","-c","echo hello"]

每条 RUN 指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。例如:

RUN apt-get update \
 && apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \
 && rm -rf /var/cache/apt

注:多行命令不要写多个 RUN 。原因是: Dockerfile 中每一个指令都会建立一层,多少个 RUN 就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

1.4.4 CMD

  • CMD 指令用来指定启动容器默认执行的命令
  • 它支持三种格式:
  • CMD ["executable","param1","param2"]
    【exec形式】、这是首选形式;使用 exec 执行,是推荐使用的方式;
  • CMD command param1 param2
    【shell形式】、在 /bin/sh 中执行,提供给需要交互的应用;
  • CMD ["param1","param2"]
    提供给 ENTRYPOINT 的默认参数
  • 每个 Dockerfile 只能有一条 CMD 命令。

如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时手动指定了运行的命令(作为 run 的参数),则会覆盖掉 CMD 指定的命令。

  • 如容器启动时进入 bash:
CMD /bin/bash

或者可以用 exec 写法

CMD ["/bin/bash"]
  • ENTRYPOINTCMD 同时给出时,CMD 中的内容会作为 ENTRYPOINT 定义命令的参数,最终执行容器启动的还是 ENTRYPOINT 中给出的命令。

1.4.5 LABEL

  • LABEL 指令用来指定生成镜像的元数据标签信息。格式为:
LABEL <key>=<value><key>=<value><key>=<value>...

例如:

LABEL version="1.0"
LABEL description="This text illustrates \ that label-values can span multiple lines."

1.4.6 EXPOSE

  • 【声明】镜像内服务所监听的端口。EXPOSE 命名适用于设置【容器对外映射】的容器端口号,格式为
EXPOSE <port>[<port>...]

例如:

EXPOSE 22 80 8443

注意,该指令只是起到声明作用,并不会自动完成【端口映射】
准确来说————Dockerfile 中的 EXPOSE 用处不大!
原因:

  • 1、真正的暴露端口是在创建容器 run 的时候指定的 -p 或者 -P 参数,先来说说 -p 参数后面跟的是【主机端口:容器端口】,那么问题就来了既然在运行的时候还需要指定端口那么 EXPOSE还要什么用呢!
  • 2、当我们创建容器 run 的时候指定参数是 -P,那么在运行之后 会把 EXPOSE 的端口随机映射到主机的不同端口,这时问题又来了既然映射到不同的端口那么容器的端口就是是随机的不确定的,那就要在运行之后才能知道端口,这样使用起来是极其不便的。
  • EXPOSE的真正用途:

EXPOSE可以不用、但是不能没有,因为 Dockerfile 不一定是一个人维护的,或者说当下一个运维人员接手项目之后能够通过 Dockerfile 里面的参数掌握整体的逻辑,一切还是为了规范

  • 启动容器时需要使用 -PDocker 主机会自动分配一个宿主机的临时端口转发到指定的端口;使用 -p,则可以具体指定哪个宿主机的本地端口会映射过来。

如 Tomcat 容器内使用的端口 8081,则用 EXPOSE 命令可以告诉外界该容器的 8081 端口对外,在构建镜像时用 Docker run -p 可以设置暴露的端口对宿主机器端口的映射。

EXPOSE 8081
  • EXPOSE 8081 其实等价于 Docker run -p 8081 当需要把 8081 端口映射到宿主机中的某个端口(如8888)以便外界访问时,则可以用 : Docker run -p 8888:8081

1.4.7 ENV

  • 指定环境变量,在镜像生成过程中会被后续 RUN 指令使用,在镜像启动的容器中也会存在。
  • ENV 命名用于设置容器的环境变量,这些变量以 key=value 的形式存在,在容器内被脚本或者程序调用,容器运行的时候这个变量也会保留。
  • 格式为
ENV <key>  <value>

或
ENV <key>=<value>...
  • 例如:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/
postgress && ...
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
  • 指令指定的环境变量在运行时可以被覆盖掉,如
docker run --env <key>=<value> {built_image_name}
  • 在使用 ENV 设置环境变量时,有几点需要注意:
  • 具有传递性。也就是当前镜像被用作其它镜像的基础镜像时,新镜像会拥有当前这个基础镜像所有的环境变量;
  • 影响范围。ENV 定义的环境变量,可以在 Dockerfile 被后面的所有指令( CMD 除外)中使用,但不能被 Docker run 的命令参数引用 。 如:
ENV Tomcat_home_name Tomcat_7
RUN mkdir $Tomcat_home_name
  • 可覆盖性。由于环境变量在容器运行时依然有效,所以运行容器时我们还可以对其进行覆盖,在创建容器时使用 -e 或是 --env 选项,可以对环境变量的值进行修改或定义新的环境变量。除了 ENV 之外,docker run -e 也可以设置环境变量传入容器内。
docker run -d Tomcat -e "TOMCAT_HOME=Tomcat_7"

这样我们进入容器内部用 ENV 可以看到 TOMCAT_HOME 这个环境变量。

  • 通过 ENV 指令和 ARG 指令所定义的参数,在使用时都是采用 $ + NAME 这种形式来占位的。

所以它们之间的定义就存在冲突的【可能性】。对于这种场景,大家只需要记住,ENV 指令所定义的变量,永远会覆盖 ARG 所定义的变量,即使它们定时的顺序是相反的。

与参数变量 ARG 只能影响构建过程不同,环境变量不仅能够影响构建,还能够影响基于此镜像创建的容器。

  • 环境变量设置的实质,其实就是定义操作系统环境变量,所以在运行的容器里,一样拥有这些变量,而容器中运行的程序也能够得到这些变量的值。
  • 另一个不同点是,环境变量的值不是在构建指令中传入的,而是在 Dockerfile 中编写的,所以如果我们要修改环境变量的值,我们需要到 Dockerfile 修改。

不过即使这样,只要我们将 ENV 定义放在 Dockerfile 前部容易查找的地方,其依然可以很快的帮助我们切换镜像环境中的一些内容。

1.4.8 ADD

  • 作用和使用方法和 COPY 一样。该命令将复制指定的 src 路径下的内容到容器中的 dest 路径下。格式为
ADD <src> <dest>
  • src 可以是 【宿主机】的 Dockerfile 所在目录的一个相对路径(文件或目录),也可以是一个 URL ,还可以是一个 tar 文件(如果为 tar 文件,会自动解压到 dest 路径下)。
  • dest 可以是【镜像内】的绝对路径,或者相对于工作目录( WORKDIR )的相对路径。路径支持正则格式,例如:
ADD *.c /dirCode/

1.4.9 COPY

  • COPY 命令用于将宿主机器上的的文件复制到镜像内,如果目的位置不存在,Docker 会自动创建。但宿主机器用要复制的目录必须是和 Dockerfile 文件同级目录下。 格式为
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
  • 复制本地主机的 src (为 Dockerfile 所在目录的相对路径、文件或目录)下的内容到镜像中的 dest 下。目标路径不存在时,会自动创建。路径同样支持正则格式。当使用本地目录为源目录时,推荐使用COPY

COPY 命令和 ADD 类似,唯一的不同是 ADD 会【自动解压压缩包】,还可以直接下载 url 中的文件。但是官方建义使用 wget 或者 curl 代替 ADD

# 拷贝并解压
ADD nickdir.tar.gz .

# 仅拷贝
ADD https://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

应该改成这样子:

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

1.4.10 ENTRYPOINT 【待完善】

  • 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。支持两种格式:
ENTRYPOINT ["executable", "param1", "param2"]  (exec调用执行)
  例如:ENTRYPOINT ["/bin/echo","hello"]

ENTRYPOINT command param1 param2  (shell中执行)

此时,CMD 指令指定值将作为根命令的参数。每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个有效。在运行时,可以被 --entrypoint 参数覆盖掉,如 docker run--entrypoint

1.4.11 VOLUME

  • 创建一个数据卷挂载点。格式为
VOLUME ["/data"]
  • 可以从本地主机或其他容器挂载数据卷,一般用来存放数据库需要保存的数据等。VOLUME 用来创建一个可以从本地主机或其他容器挂载的挂载点。

  • 但使用数据卷需要我们在创建容器时通过 -v 选项来定义,而有时候由于镜像的使用者对镜像了解程度不高,会漏掉数据卷的创建,从而引起不必要的麻烦。

  • VOLUME 指令中定义的目录,在基于新镜像创建容器时,会自动建立为数据卷,不需要我们再单独使用 -v 选项来配置了。

例如,我们知道 TomcatWebapps 目录是放 Web 应用程序代码的地方,此时我们要把 Webapps 目录挂载为匿名卷,这样任何写入 Webapps 中的都不会被记录到容器的存储层,让容器存储层无状态化。
例如,创建 TomcatWebapps 目录的一个挂载点

VOLUME /usr/local/Tomcat/Webapps

这样,在运行容器时,也可以用过 Docker run -v 来把匿名挂载点挂载都宿主机器上的某个目录,如

docker run -d -v /home/Tomcat_Webapps:/usr/local/Tomcat/Webapps

前面的路径:宿主机的
后面的路径:镜像内的

1.4.12 USER

  • 指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份。需要注意的是这个用户必须是已经存在,否则无法指定。格式为
USER daemon
  • 当服务不需要管理员权限时,可以通过该命令指定运行用户,并且可以在之前创建所需要的用户。例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres

要临时获取管理员权限可以使用 gosu 或 sudo 。

  • USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。

WORKDIR 是改变工作目录, USER 则是改变之后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。
注意, USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]
  • 如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu
# 建立 redis 用户,并使用 gosu 换另一个用户执行命令
RUN groupadd -r redis && useradd -r -g redis redis

# 下载 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.12/gosu-amd64" \
 && chmod +x /usr/local/bin/gosu \
 && gosu nobody true

# 设置 CMD,并以另外的用户执行
CMD [ "exec", "gosu", "redis", "redis-server" ]

1.4.13 WORKDIR

  • 为后续的 RUNCMDENTRYPOINT 指令配置【工作目录】。

其效果类似于 Linux 命名中的 cd 命令,用于目录的切换,但是和 cd 不一样的是:如果切换到的目录不存在,WORKDIR 会为此自动创建目录。格式为

WORKDIR /path/to/workdir
  • 可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则: 会基于之前命令指定的路径

例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则:最终路径为 /a/b/c

1.4.14 ARG

  • 指定一些镜像内使用的参数(例如:版本号信息等),这些参数在执行 docker build 命令时才以 --build-arg <varname>=<value> 格式传入。格式为
ARG  <name> [=<default value>]

示例:

docker build --build-arg <name>=<value> . 

来指定参数值。

示例,Dockefile 文件内容

FROM debian:stretch-slim

## ......

ARG TOMCAT_MAJOR
ARG TOMCAT_VERSION

## ......

RUN wget -O tomcat.tar.gz "https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz"

## ......

其镜像的构建命令

$ sudo docker build --build-arg TOMCAT_MAJOR=8 --build-arg TOMCAT_VERSION=8.0.53 -t tomcat:8.0 ./tomcat

1.4.15 ONBUILD

  • 配置当所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令。

意思就是:这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的 ONBUILD 命令。格式为

ONBUILD [INSTRUCTION]

例如,Dockerfile 使用如下的内容创建了镜像 image-A:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像,会自动执行 ONBUILD 指令的内容,等价于在后面添加了两条指令:

FROM image-A
# Automatically run the following

ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的镜像,推荐在标签中注明,例如 ruby: 1.9-onbuild。

1.4.16 STOPSIGNAL

  • 指定所创建镜像启动的容器接收退出的信号值。例如:
STOPSIGNAL signal

1.4.17 HEALTHCHECK

  • 配置所启动容器如何进行健康检查(如何判断健康与否),自 Docker 1.12开始支持。格式有两种:
  • HEALTHCHECK[OPTIONS]CMD command:根据所执行命令返回值是否为 0 来判断。
  • HEALTHCHECK NONE:禁止基础镜像中的健康检查。
  • OPTION支持:
  • interval=DURATION(默认为:30s):过多久检查一次;
  • timeout=DURATION(默认为:30s):每次检查等待结果的超时;
  • retries=N(默认为:3):如果失败了,重试几次才最终确定失败。

1.4.18 SHELL

  • 指定其他命令使用 shell 时的默认 shell 类型。默认值为 ["/bin/sh","-c"] 。注意对于 Windows 系统,建议在 Dockerfile 开头添加 #escape= 来指定转义信息。

1.5 基于Dockerfile创建镜像

  • 编写完成 Dockerfile 之后,可以通过 docker build 命令来创建镜像。

基本的格式为

docker build [OPTIONS] PATH | URL | -
  • OPTIONS 有很多指令,下面列举几个常用的:
  • --build-arg=[] : 设置镜像创建时的变量;
  • -f : 指定要使用的 Dockerfile 路径;
  • --force-rm : 设置镜像过程中删除中间容器;
  • --rm : 设置镜像成功后删除中间容器;
  • --tag, -t : 镜像的名字及标签,通常 name:tag 或者 name 格式。
  • docker build 可以接收一个参数,需要特别注意的是,这个参数为一个目录路径 ( 本地路径或 URL 路径 ),而并非 Dockerfile 文件的路径。

docker build 里,这个我们给出的目录会作为构建的环境目录,我们很多的操作都是基于这个目录进行的。

例如,在我们使用 COPY 或是 ADD 拷贝文件到构建的新镜像时,会以这个目录作为基础目录。

  • 该命令将读取指定路径下(包括子目录)的 Dockerfile,并将该路径下的所有内容发送给 Docker 服务端,由服务端来创建镜像。因此除非生成镜像需要,否则一般建议放置 Dockerfile 的目录为空目录。
    有两点经验:
  • 如果使用非内容路径下的 Dockerfile,可以通过 -f 选项来指向文件系统中任何位置的 Dockerfile
docker build -f /path/to/a/Dockerfile .
  • 要指定生成镜像的标签信息,可以使用 -t 选项。例如,指定 Dockerfile 所在路径为 /tmp/docker_builder/,并且希望生成镜像标签为 build_repo:first_image,可以使用下面的命令:
$ docker build -t build_repo:first_image /tmp/docker_builder/
$ docker build -t webapp:latest ./webapp

执行命名之后,会看到控制台逐层输出构建内容,直到输出两个 Successfully 即为构建成功。

  • 基于git远程仓库及Dockerfile构建镜像
# $env:DOCKER_BUILDKIT=0
# export DOCKER_BUILDKIT=0
 
$ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
 
Step 1/3 : FROM scratch
 --->
Step 2/3 : COPY hello /
 ---> ac779757d46e
Step 3/3 : CMD ["/hello"]
 ---> Running in d2a513a760ed
Removing intermediate container d2a513a760ed
 ---> 038ad4142d2b
Successfully built 038ad4142d2b

1.6 使用.dockerignore文件

  • 可以通过 .dockerignore 文件(每一行添加一条匹配模式)来让 Docker 忽略匹配模式路径下的目录和文件。

例如:

# comment
*/temp*
*/*/temp*
tmp?

其中:

  • * 表示任意多个字符
  • ? 表示单个字符
  • ! 表示不匹配(即不忽略指定的路径或文件)

1.X 镜像最佳实践

  • 精简镜像用途:尽量让每个镜像的用途都比较集中单一,避免构造大而复杂,多功能的镜像;
  • 选用合适的基础镜像:容器的核心是应用,选择过大的父镜像(如 Ubuntu 系统镜像)会造成生成应用镜像臃肿,推荐选用较为小巧的系统镜像(如 alpine、busybox、debian);
  • 提供注释和维护者的信息;
  • 正确的使用版本号:可以避免环境不一致的问题;
  • 减少镜像层数:尽量合并 RUNADDCOPY 等指令;
  • 使用 .dockerignore 文件;
  • 及时删除临时文件和缓存文件:特别是在执行 apt-get 指令后,/var/cache/apt 下面会缓存了一些安装包;
  • 减少外部源的干扰:如果确实要从外部引入数据,则需要指定持久的地址,并带有版本信息等,让他人可以复用而不报错;

2 Dockerfile FAQ

Q1 CMD 与 ENTRYPOINT 的区别?

  • 在Docker容器中,CMDENTRYPOINT都是用于指定在容器启动时要执行的命令。然而,它们之间存在着一些关键的区别,需要深入了解这两者的用途和差异,以及何时应该选择使用哪一个。

  • 什么是 CMD ?

CMDDockerfile中的一个关键指令,用于指定默认的容器启动命令
它可以是一个命令字符串,也可以是一个命令数组
当在运行容器时没有指定要执行的命令时,Docker会使用CMD中的命令作为默认命令启动容器

  • 什么是ENTRYPOINT?
  • ENTRYPOINT也是Dockerfile中的一个指令,用于指定容器的入口点入口命令)。
  • CMD不同的是,ENTRYPOINT的命令不会被覆盖,而是始终会被执行,即使在运行容器时指定了要执行的命令
  • CMD和ENTRYPOINT的差异:
差异点 CMD ENTRYPOINT
命令执行时机 CMD指定的命令在容器启动时会被执行,但当docker run命令中有参数时,守护进程会忽略CMD指令(即:被覆盖 ENTRYPOINT指定的命令始终会被执行(不会被覆盖),即使在运行容器时指定了其他命令
(使用ENTRYPOINT指令不会忽略,并且会接收docker run参数附加到命令行中。)
命令覆盖 在docker run命令中指定的命令会覆盖CMD指令中的默认命令 在docker run命令中指定的命令会作为ENTRYPOINT命令的参数执行,而不会覆盖它。
命令格式 CMD可以是一个命令字符串,也可以是一个命令数组。如果是字符串,会被解释为Shell命令。如果是数组,不会被解释为Shell命令 ENTRYPOINT只能是一个命令数组,它不会被解释为Shell命令
使用场景小结 1、定义容器的默认行为,当用户未指定特定命令时。
2、在Dockerfile中设置默认参数,以适应多种使用情况。
1、定义容器的主要入口点,始终执行该命令。
2、创建可重用的Docker映像,以便用户可以在ENTRYPOINT命令上提供自定义参数。

X 参考文献

posted @ 2024-03-22 10:22  千千寰宇  阅读(33)  评论(0编辑  收藏  举报