纯干货!Docker Dockerfile指令大全(上)

简介: 什么是 Dockerfile?Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令,用户可以创建基于基础镜像的自定义镜像。

什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。使用docker build命令,用户可以创建基于基础镜像的自定义镜像。


Dockerfile格式

# Comment 
INSTRUCTION arguments  # INSTRUCTION表示指令(不止一条)
复制代码


Dockerfile指令详解

FROM-指定基础镜像

指定基础镜像,并且Dockerfile中第一条指令必须是FROM指令,且在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。

语法格式如下:

FROM <image> 
FROM <image>:<tag> 
复制代码


其中<tag>是可选项,如果没有选择,那么默认值为latest

如果不以任何镜像为基础,那么写法为:FROM scratch


RUN-运行指定的命令

运行指定的命令。

包含两种语法格式,如下所示:

# shell格式:就像在命令行中输入的Shell脚本命令一样。
RUN <command> 
# exec格式:就像是函数调用的格式。
RUN ["executable", "param1", "param2"] 
复制代码


第一种后边直接跟shell命令。

  • 在linux操作系统上默认为/bin/sh -c
  • 在windows操作系统上默认为cmd /S /C

第二种是类似于函数调用。可将executable理解成为可执行文件,后面就是两个参数。

样例:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
RUN ["/bin/bash", "-c", "echo hello"] 
复制代码


注意:

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


CMD-容器启动时要运行的命令

容器启动时要运行的命令。

包含三种语法格式,如下所示:

# 第一种就是shell这种执行方式和写法
CMD command param1 param2
# 第二种是可执行文件加上参数的形式(推荐)
CMD ["executable","param1","param2"] 
# 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
CMD ["<param1>","<param2>",...]  
复制代码


推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是sh

样例:

CMD [ "sh", "-c", "echo $HOME" ]
CMD [ "echo", "$HOME" ] 
复制代码

注意:

这里边包括参数的一定要用双引号,不能是单引号。千万不能写成单引号。原因是参数传递后,docker解析的是一个JSON array.


ENTRYPOINT-为容器指定默认运行程序


类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。

在写Dockerfile时, ENTRYPOINT或者CMD指令会自动覆盖之前的ENTRYPOINT或者CMD指令。即ENTRYPOINT或者CMD指令只能写一条,如果写了多条,那么,ENTRYPOINT或者CMD都只有最后一条生效。

在Docker镜像运行时, 用户也可以在命令行指定具体命令, 覆盖在Dockerfile里的命令。

与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指令指定的程序,不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序。

其语法如下:

# exec格式(推荐)
ENTRYPOINT ["executable", "param1", "param2"] 
# shell格式
ENTRYPOINT command param1 param2
复制代码


第一种就是可执行文件加参数。与CMD指令一样,ENTRYPOINT也更加推荐使用exec格式。

第二种就是shell格式。

样例:

FROM ubuntu 
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* 
ENTRYPOINT ["curl", "-s", "http://ip.cn"]
复制代码


# 将其构建成镜像ubuntu:v1.2,下面我们创建并启动容器:
docker run -it ubuntu:v1.2
# 将会在控制台输出我们相应的公网IP信息!
# 此时,如果我们还需要获取HTTP头信息时,我们可以这样:
docker run -it ubuntu:v1.2 -i
复制代码


CMD与ENTRYPOINT的异同点

这俩命令非常像,而且还可以配合使用。

相同点:

  • 只能写一条,如果写了多条,那么只有最后一条生效。
  • 容器启动时才运行,运行时机相同。

不同点:

  • ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖。
  • 如果我们在Dockerfile中同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数。如下所示:
FROM ubuntu 
ENTRYPOINT ["rm", "docker2"] 
CMD ["-rf"]
复制代码


它真正执行的命令将会是:rm docker2 -rf

  • 如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效。如下所示:
FROM ubuntu
ENTRYPOINT ["top", "-b"]  
CMD ls -al
复制代码


那么将执行ls -al,top -b不会执行。

下表显示了针对不同的ENTRYPOINT/CMD进行组合后执行的命令:

  No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

虽然这2个指令功能类似,但是这两个指令不是互斥的. 在很多情况下, 你可以组合ENTRYPOINT和CMD指令, 提升最终用户的体验。同时我们从上表也发现在使用SHELL去执行ENTRYPOINT时,ENTRYPOINT会无视从CMD传来的任何参数,所以CMD只传参数是无效的。

组合ENTRYPOINT和CMD指令的最佳实践:

组合使用ENTRYPOINT和CMD命令式, 确保你一定用的是exec表示法. 如果有其中一个用的是shell表示法, 或者一个是shell表示法, 另一个是exec表示法, 你永远得不到你预期的效果。只有当ENTRYPOINT和CMD都用exec表示法, 才能得到预期的效果。


COPY-复制文件或者目录到容器里指定路径

从上下文目录中复制文件或者目录到容器里指定路径。

语法格式如下:

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
复制代码


参数说明:

  • [--chown=:] :可选参数,用户改变复制到容器内文件的拥有者和属组。
  • <源路径> :源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:COPY hom* /mydir/COPY hom?.txt /mydir/。源路径必须是build上下文中的路径,不能是其父目录中的文件。如果源路径是目录,则其内部文件或子目录会被递归复制,但源路径目录自身不会被复制。如果指定了多个源路径,或在源路径中使用了通配符,则目标路径必须是一个目录,且必须以/结尾。
  • <目标路径> :容器内的指定路径,建议为目标路径使用绝对路径,否则,COPY指令则以WORKDIR为其起始路径;如果目标路径事先不存在,它将会被自动创建,这包括其父目录路径。

样例:

# 复制宿主机文件index.html到容器/data/html/index.html
COPY index.html /data/html/index.html   
# 复制宿主机data目录下文件(包括子目录)到容器/data/目录下,并不会复制目录本身
COPY data  /data/    
复制代码


ADD-复制文件或者目录到容器里指定路径

ADD 指令和 COPY 的使用类似 (同样需求下,官方推荐使用 COPY) ,功能也类似。除此之外,ADD还支持使用TAR文件和URL路径,并且会将tar压缩文件(gzip, bzip2以及 xz格式)解压缩,如果指定的是url,会从指定的url下载文件放到目录中( 如果url下载的文件为tar文件,则不会展开)。

其语法格式如下:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
复制代码


样例:

ADD /data/src/nginx-1.14.0.tar.gz /data/src/
复制代码


# 构建镜像
docker build -t nginx:v1.1  .
# 创建容器
docker run --rm --name nginx -it  nginx:v1.1  ls /data/src
# 我们可以发现已经解压了nginx-1.14.0.tar.gz文件
复制代码


LABEL-为镜像指定标签

为镜像指定标签,其格式为:

LABEL <key1>=<value1> <key2>=<value2> ...
复制代码


LABEL后面是键值对,多个键值对以空格进行隔开,如果value中包含空格,请使用""将value进行圈起来。

# 如果太长需要换行的话,则使用\符号
LABEL name=test \
  description="a container is used to test"
复制代码


我们可以使用docker inspect命令,来查看镜像的标签:

docker inspect --format '{{json .Config.Labels}}' test | python3 -m json.tool
复制代码


其中,“test”为容器名称,”python3 -m json.tool“为将其格式化为JSON输出。


MAINTAINER-指定生成镜像的作者名称

用于指定生成镜像的作者名称,其格式为:

MAINTAINER <name>
复制代码


MAINTAINER指令已经被弃用,可以使用LABEL指令进行替代,样例如下:

LABEL maintainer='Stephen Chow'
复制代码


说明:

LABEL会继承基础镜像中的LABEL,如遇到key相同,则值覆盖。

EXPOSE-为容器打开指定要监听的端口以实现与外部通信

用于为容器打开指定要监听的端口以实现与外部通信,这个只是声明,真正要暴露这个端口需要再构建容器的时候使用"-P"选项。其格式为:

EXPOSE <port> [<port>/<protocol>...]
复制代码


示例:

EXPOSE 80/tcp
EXPOSE 80/udp
复制代码


如果想使得容器与主机的端口有映射关系,需要在启动容器时指定-P.

# 这里的“-P”选项是关键,在启动容器的使用使用-P,
# Docker会自动分配一个端口和转发指定的端口,
# 使用-p可以具体指定使用哪个本地的端口来映射对外开放的端口。
docker run --rm --name nginx -itd -P nginx:v1.4
复制代码


ENV-设置环境变量

设置环境变量,无论是接下来的指令(如ENVADDCOPY等,其调用格式为$variable_name${variable_name}),还是在容器中运行的程序,都可以使用这里定义的环境变量。

它有两种语法格式,如下所示:

ENV <key> <value> 
ENV <key1>=<value1> <key2>=<value2> ... 
复制代码


两者的区别就是第一种是一次设置一个,第二种是一次设置多个。

示例:

ENV word hello
ENV guodong xxxx    
ENV name1=ping name2=on_ip
RUN echo $word
复制代码


注意:

如果你想通过CMD或者ENTRYPOINT指令的exec格式来打印环境,就像下面这样:

CMD ["echo", $MODE]

CMD ["echo", "$MODE"]

这样都是不能正确输出环境变量的值的,你可以改成exec格式来执行shell命令,如下所示:

CMD ["sh", "-c", "echo $MODE"]

如此,就能正确输出环境变量的值了!


相关文章
|
3天前
|
NoSQL Java Linux
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
《docker高级篇(大厂进阶):2.DockerFile解析》包括:是什么、DockerFile构建过程解析、DockerFile常用保留字指令、案例、小总结
123 75
|
1月前
|
Java 应用服务中间件 Linux
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
本文主要讲解了Docker的安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库以及Docker容器虚拟化与传统虚拟机比较。
783 12
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
|
25天前
|
数据库 Docker 容器
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。Dockerfile定义了构建镜像所需的所有指令,包括基础镜像选择、软件安装、文件复制等,极大提高了开发和部署的灵活性与一致性。掌握Dockerfile的编写,对于提升软件开发效率和环境管理具有重要意义。
48 9
|
1月前
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
106 3
|
2月前
|
Docker 容器
docker中使用Dockerfile自动创建数据卷
【10月更文挑战第12天】
33 5
|
2月前
|
消息中间件 NoSQL Kafka
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
Flink-10 Flink Java 3分钟上手 Docker容器化部署 JobManager TaskManager Kafka Redis Dockerfile docker-compose
72 4
|
3月前
|
应用服务中间件 nginx Docker
Docker镜像-基于DockerFile制作编译版nginx镜像
这篇文章介绍了如何基于Dockerfile制作一个编译版的nginx镜像,并提供了详细的步骤和命令。
566 17
Docker镜像-基于DockerFile制作编译版nginx镜像
|
3月前
|
应用服务中间件 Linux nginx
Docker镜像-基于DockerFile制作yum版nginx镜像
本文介绍了如何使用Dockerfile制作一个基于CentOS 7.6.1810的yum版nginx镜像,并提供了详细的步骤和命令。
171 20
|
3月前
|
Docker 容器
7-13|docker build -t image-name:tag path/to/Dockerfile 这个命令具体什么意思
7-13|docker build -t image-name:tag path/to/Dockerfile 这个命令具体什么意思
|
4月前
|
Docker 容器
在Docker中,Dockerfile有哪些常见指令?
在Docker中,Dockerfile有哪些常见指令?

热门文章

最新文章