[docker] Dockerfile详解
0 序
-
Dockerfile在现工作的Devops流程中时常使用,但一直未能对其进行系统性的学习一下。
所以就有了这篇。 -
关于 Docker 容器的基础知识,参见: [Docker] Docker 基础教程(概念/原理/基础操作) - 博客园/千千寰宇
1 Docerfile 概述与详解
1.1 什么是 Dockerfile?
Dockerfile
是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
DockerFile
是Docker
的一个配置文件,本质上来说它只是一个文本文件,它是用来构建【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"]
- 当
ENTRYPOINT
与CMD
同时给出时,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 里面的参数掌握整体的逻辑,一切还是为了规范。
- 在启动容器时需要使用
-P
,Docker
主机会自动分配一个宿主机的临时端口
转发到指定的端口;使用-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 选项来配置了。
例如,我们知道
Tomcat
的Webapps
目录是放Web
应用程序代码的地方,此时我们要把Webapps
目录挂载为匿名卷,这样任何写入Webapps
中的都不会被记录到容器的存储层,让容器存储层无状态化。
例如,创建Tomcat
的Webapps
目录的一个挂载点
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
- 为后续的
RUN
、CMD
和ENTRYPOINT
指令配置【工作目录】。
其效果类似于
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); - 提供注释和维护者的信息;
- 正确的使用版本号:可以避免环境不一致的问题;
- 减少镜像层数:尽量合并
RUN
、ADD
、COPY
等指令; - 使用
.dockerignore
文件; - 及时删除临时文件和缓存文件:特别是在执行
apt-get
指令后,/var/cache/apt
下面会缓存了一些安装包; - 减少外部源的干扰:如果确实要从外部引入数据,则需要指定持久的地址,并带有版本信息等,让他人可以复用而不报错;
2 Dockerfile FAQ
Q1 CMD 与 ENTRYPOINT 的区别?
-
在Docker容器中,
CMD
和ENTRYPOINT
都是用于指定在容器启动时要执行的命令。然而,它们之间存在着一些关键的区别,需要深入了解这两者的用途和差异,以及何时应该选择使用哪一个。 -
什么是
CMD
?
CMD
是Dockerfile
中的一个关键指令,用于指定默认的容器启动命令。
它可以是一个命令字符串,也可以是一个命令数组。
当在运行容器时没有指定要执行的命令时,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 参考文献
- [Docker] Docker 基础教程(概念/原理/基础操作) - 博客园/千千寰宇 【推荐】
- Docker - Official
- Docker Dockerfile 编排 - smoothies.com.cn
- Docker 入门系列(7)- Dockerfile 使用(FROM、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、WORKDIR) - CSDN
- Dockerfile EXPOSE有什么用? - 博客园
- 【docker】深入解析Docker中CMD和ENTRYPOINT的差异与用途 - CSDN
- dockerfile中ENTRYPOINT与CMD的结合 - 博客园 【推荐】
- 【docker】Dockerfile文件、run命令中的cmd、ENTRYPOINT命令(两种不同的进程执行方式 shell 和 exec) - CSDN 【推荐】
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!