Skip to content
On this page

docker008 Dockerfile详解

https://docs.docker.com/engine/reference/builder

https://k8s.coding3min.com/docker-jing-xiang/best-dockerfilehttps://k8s.coding3min.com/docker-jing-xiang/best-dockerfile-other

1. FROM 基础镜像信息

FROM命令可能是最重要的Dockerfile命令。改命令定义了使用哪个基础镜像启动构建流程。基础镜像可以为任意镜 像。如果基础镜像没有被发现,Docker将试图从Docker image index来查找该镜像。FROM命令必须是Dockerfile的首个命令。

bash
# 第一行必须指定基于的基础镜像
# Usage: FROM [image name]
FROM <image>:<tag> 
FROM <image>@digest校验码

2. MAINTAINER 维护者信息

这个命令用于声明作者,一般应该放在FROM的后面。

bash
# Usage: MAINTAINER [name]
MAINTAINER authors_name email@emial.com
逐渐废弃, 
LABLE 替代 MAINTAINER

2. LABEL 生成镜像的元数据标签

LABEL指定生成镜像的元数据标签信息

bash
LABEL <key>=<value> <key>=<value> <key>=<value> ...
 一个Dockerfile种可以有多个LABEL
LABLE maintainer="1@1.com"

LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"

3 RUN 镜像操作指令

(运行指定命令用,即/bin/sh -c,安装软件用) 两种形式:

  • run command shell格式
  • run [ "executable","param1","param2" ]后一种形式必须用双引号,因为会被解析成Json字符串. exec格式

RUN命令是Dockerfile执行命令的核心部分。它接受命令作为参数并用于创建镜像。不像CMD命令,RUN命令用于创建镜像(在之前commit的层之上形成新的层)。

bash
# Usage: RUN [command]
RUN aptitude install -y riak
RUN [ "/bin/bash","-c","echo hello" ]

5 WORKDIR

https://docs.docker.com/engine/reference/builder/#workdir

Docker默认工作目录是/。只有RUN能执行cd切换目录,而且还只作用当下的RUN。

也就是每一个RUN都是独进行的。

想让其他指令也在指定目录下运行,就需要WORKDIR

WORKDIR命令用于设置CMD指明的命令的运行目录。 设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。 格式:

bash
WORKDIR /path/to/workdir
bash
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

pwd执行的结果是/a/b/c

WORKDIR也可以解析环境变量 如:

shell
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

pwd的执行结果是/path/$DIRNAME

bash
WORKDIR /usr/local/tomcat

4. CMD 容器启动时执行命令

(设置container启动时执行的操作) 三种格式:

  • CMD ["executable","param1","param2"]使用exec执行,是推荐使用方式
  • CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用
  • CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数

指定容器启动时候执行的命令,每个Dockerfile只能有一个CMD命令。如果有多条,只有最后一条被执行。 如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD指定的命令。

5. ENTRYPOINT 默认入口

指定镜像的默认入口命令.启动容器时作为跟命令执行.

格式1(exec调用执行):

bash
ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)

格式2(shell中执行.CMD指令指定值作为参数):

bash
ENTRYPOINT command param1 param2 (as a shell)  [CMD Args]

当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。

ENTRYPOINT 帮助你配置一个容器使之可执行化,如果你结合CMD命令和ENTRYPOINT命令,你可以从CMD命令中移除“application”而仅仅保留参数,参数将传递给ENTRYPOINT命令。

bash
# Usage: ENTRYPOINT application "argument", "argument", ..
# Remember: arguments are optional. They can be provided by CMD
# or during the creation of a container.
ENTRYPOINT echo
# Usage example with CMD:
# Arguments set with CMD can be overridden during *run*
CMD "Hello docker!"
ENTRYPOINT echo

# CMD指令将不会被执行,只有ENTRYPOINT指令被执行  
CMD echo “Hello, World!”  
ENTRYPOINT ls -l  
另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。
FROM ubuntu  
CMD ["-l"]  
ENTRYPOINT ["/usr/bin/ls"]

6. EXPOSE 指定端口

注意: 只声明,并不会自动完成端口映射 EXPOSE用来指定端口,使容器内的应用可以通过端口和外界交互。与启动容器的-P -p配合使用。

设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。

要完成整个操作需要两个步骤:

  • 首先在Dockerfile使用EXPOSE设置需要映射的容器端口
  • 然后在运行容器的时候指定-p选项加上EXPOSE设置的端口

这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。 EXPOSE指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用-p选项。

bash
# Usage: EXPOSE [port/tcp port/udp] 默认为tcp
# 映射一个端口  
EXPOSE port1  
# 相应的运行容器使用的命令  
docker run -p port1 image  

# 映射多个端口  
EXPOSE port1 port2 port3  
# 相应的运行容器使用的命令  
docker run -p port1 -p port2 -p port3 image  
# 还可以指定需要映射到宿主机器上的某个端口号  
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image

7. ENV 设置环境变量

ENV命令用于设置环境变量。这些变量以key=value的形式存在,并可以在容器内被脚本或者程序调用。这个机制给在容器中运行应用带来了极大的便利。

bash
# Usage: ENV key value
# Usage: ENV key=value
ENV SERVER_WORKS 4
ENV JAVA_HOME /usr/local/jdk
ENV XX_ver 1.1
RUN curl -SL http://xxxxx.xxx/xxx-$XX_ver.tar.gz | tar -xJC /user/src/xxx && ...
ENV PATH /user/local/xxx_$XX_ver/bin:$PATH

# 可以用docker inspect命令查看

注意: dokcer run --env k=v时候会覆盖掉

8. ADD 从src复制文件到container的dest路径

ADD命令有两个参数,源和目标。它的基本作用是从源系统的文件系统上复制文件到目标容器的文件系统。

  • 如果是文件或文件夹,复制
  • 如果源是一个URL,那该URL的内容将被下载并复制到容器中。
  • 如果是tar文件,自动解压到dest路径下

dest可以是镜像内的绝对路径,或者相对于工作目录(WORKDIR)的相对路径

bash
# Usage: ADD <src> <dest>
# Usage: ADD [source directory or URL] [destination directory]

ADD /my_app_folder /my_app_folder CMD

和RUN命令相似,CMD可以用于执行特定的命令。和RUN不同的是,这些命令不是在镜像构建的过程中执行的,而是在用镜像构建容器后被调用。 当目标路径不存在时,会自动创建;当使用本地目录为源目录时,推荐使用COPY。

9. COPY 拷贝文件或目录

bash
COPY <src> <dest>

命令有两个参数,源和目标。它的基本作用是从源系统的文件系统上复制文件到目标容器的文件系统。 src为绝对路径或者Dockerfile所在目录的相对路径,文件或目录。 路径支持正则格式. 当使用本地目录为源目录时,推荐使用COPY。

11. VOLUME 数据卷挂载点

VOLUME命令用于让你的容器访问宿主机上的目录。

shell
# Usage: VOLUME ["/dir_1", "/dir_2" ..]
VOLUME ["/my_files"]
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db

12. USER 设置运行容器时的用户名或UID

USER命令用于设置运行容器时的用户名或UID。

bash
# Usage: USER [UID]
USER 751
设置指令,设置启动容器的用户,默认是root用户。
# 指定memcached的运行用户  
ENTRYPOINT ["memcached"]  
USER daemon  
  
ENTRYPOINT ["memcached", "-u", "daemon"]

14. ARG 定义变量

shell
ARG <name>[=<default value>]

设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg=来指定参数 如果用户在build镜像时指定了一个参数没有定义在Dockerfile中,那么将有一个Warning [Warning] One or more build-args [foo] were not consumed. 如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值

bash
我们可以定义一个或多个参数,如下:
FROM busybox
ARG user1
ARG buildno

也可以给参数一个默认值:

FROM busybox
ARG user1=someuser
ARG buildno=1

docker build --build-arg name=value来传入

15. ONBUILD

当前镜像作为其他镜像的基础镜像时,锁执行的创建操作指令.

shell
ONBUILD [INSTRUCTION]

这个命令只对当前镜像的子镜像生效。 比如当前镜像为A,在Dockerfile种添加:

shell
ONBUILD RUN ls -al

这个 ls -al 命令不会在A镜像构建或启动的时候执行 此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。

shell
# image-A
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

如果B中

shell
FROM image-A
# 会自动执行如下
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src

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

16. STOPSIGNAL

STOPSIGNAL命令是的作用是当容器停止时给系统发送什么样的指令,默认是15

shell
STOPSIGNAL signal

17. HEALTHCHECK

容器健康状况检查命令 语法有两种:

  • HEALTHCHECK [OPTIONS] CMD command 容器内运行一个命令,根据返回值是否为0来判断
  • HEALTHCHECK NONE 禁止基础镜像中的健康检查
  • [OPTIONS]的选项支持以下三中选项:
shell
–interval=DURATION 两次检查默认的时间间隔为30秒
–timeout=DURATION 健康检查命令运行超时时长,默认30秒
–retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3

HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。 CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下: 0: success - 表示容器是健康的 1: unhealthy - 表示容器已经不能工作了 2: reserved - 保留值

例子:

shell
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
健康检查命令是:curl -f http://localhost/ || exit 1
两次检查的间隔时间是5秒
命令超时时间为3秒

18. SHELL

指定其他命令使用shell时的默认shell类型

shell
SHELL ["executable", "parameters"] 
默认值为
SHELL ["/bin/sh", "-c"]

windows中添加(建议)

shell
# escape=` 来指定转义信息

ubuntu中添加(建议)

shell
ENV DEBIAN_FRONTEND noninteractive
#设置环境变量,所有操作都是非交互式的
RUN echo "Asia/Shanghai" > /etc/timezone && \
dpkg-reconfigure -f noninteractive tzdata
#注意这里要更改系统的时区设置,因为在Web应用中经常会用到时区这个系统变量,默认的ubuntu会让应用发生不可思议的效果。

使用Dockerfiles创建镜像

  • 注意一个镜像不能超过 127 层 使用Dockerfiles和手工使用Docker Daemon运行命令一样简单。脚本运行后输出为新的镜像ID。 另外,可以通过 .dockerignore文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。
bash
# Build an image using the Dockerfile at current location
# Example: sudo docker build -t [name] .
sudo docker build -t my_mongodb . 
$ sudo docker build -t="ouruser/sinatra:v2" .
  • t 标记来添加 tag,指定新的镜像的用户信息。 "." 是 Dockerfile 所在的路径(当前目录),build时候的上下文目录
  • f 指定具体的 Dockerfile 的路径。 可以看到 build 进程在执行操作。它要做的第一件事情就是上传这个 Dockerfile 内容,因为所有的操作都要依据 Dockerfile 来进行。 然后,Dockfile 中的指令被一条一条的执行。每一步都创建了一个新的容器,在容器中执行指令并提交修改(就跟之前介绍过的 docker commit 一样)。当所有的指令都执行完毕之后,返回了最终的镜像 id。所有的中间步骤所产生的容器都被删除和清理了。

使用.dockerignore文件

.dockerignore 文件中指定在传递给 docker引擎 时需要忽略掉的文件或文件夹。

shell
#comment

#代表根目录(上下文环境目录中)中以abc开头的任意直接子目录或者直接子文件将被忽略
#如/abc  abc.txt
/abc*

#代表根目录(上下文环境目录中)中任意直接子目录中以abc开头的任意直接子目录或者直接子文件将被忽略
#如 /file/abc  /file/abc.txt
*/abc*

#代表根目录(上下文环境目录中)中任意两级目录下以abc开头的任意直接子目录或者直接子文件将被忽略
#如 /file1/file2/abc  /file1/file2/abc.txt
*/*/abc*

#排除根目录中的文件和目录,其名称是单字符扩展名temp。例如,/tempa与/tempb被排除在外。
temp?    

#Docker还支持一个**匹配任意数量目录(包括零)的特殊通配符字符串
**/abc*

#以!(感叹号)开头的行可用于对排除项进行例外处理,比如原本包含了README.md这个文件的过滤,但是加了如下一行后
#就不会再过滤README.md,依然会将其提交到守护进程。
!README.md

#异常规则的放置位置会影响行为
*.md
!README*.md
README-secret.md
#README-secret.md 仍然会被忽略

*.md
README-secret.md
!README*.md
#README-secret.md 不会被忽略

您甚至可以使用该.dockerignore文件来排除Dockerfile和.dockerignore文件。这些文件仍然发送到守护程序,因为它需要它们来完成它的工作。但是ADD和COPY命令不会将它们复制到图像中。

待整理

shell
# put my local web site in myApp folder to /var/www
ADD myApp /var/www
# expose httpd port
EXPOSE 80
# the command to run
CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]
bash
#让Nginx运行在非Daemon模式
RUN echo "ndaemon off;" >> /etc/nginx/nginx.conf


dpkg-reconfigure(选项)(参数) -a:重新配置所有的软件包;
-u或--unseen-only:仅显示未提过的问题;
--default-priority:使用默认优先级,而非“低”级;
--force:强制执行操作,需谨慎使用此选项;
--no-reload:不要轻易的重装模板(使用时请慎重考虑);
-f或--frontend:指定 debconf 前端界面;
-p或--priority:指定要显示的问题的最优先级;
--terse:开启简要模式。

Last updated:

Released under the MIT License.