纯干货!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月前
|
Cloud Native NoSQL Redis
云原生 Docker Dockerfile 构建应用
【1月更文挑战第9天】云原生 Docker Dockerfile 构建应用
|
3月前
|
Cloud Native Docker 容器
云原生 Docker Dockerfile 构建配置
【1月更文挑战第9天】云原生 Docker Dockerfile 构建配置
|
4月前
|
Linux 开发工具 Docker
Docker dockerfile 案例:centos 支持 vim
Docker dockerfile 案例:centos 支持 vim
52 0
|
3月前
|
分布式计算 Java Linux
【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)
Docker 是一套构建在 Linux 内核之上的高级工具,旨在帮助开发人员和运维人员更轻松地交付应用程序和依赖关系,实现跨系统和跨主机的部署。使用安全且轻量级的容器环境来实现这一目标。容器可以手动创建,也可以通过编写 Dockerfile 自动创建。开发人员和运维人员可以将应用程序及其依赖打包到容器中,实现应用程序的可移植性和环境一致性。
120 5
【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Dockerfile使用手册)
|
3月前
|
Java 持续交付 Docker
Docker 项目如何使用 Dockerfile 构建镜像?
Docker 简介:讲述 Docker 的起源、它是如何革新现代软件开发的,以及它为开发者和运维团队带来的好处。重点强调 Docker 的轻量级特性和它在提高应用部署、扩展和隔离方面的优势。
|
4月前
|
应用服务中间件 Linux nginx
Docker Compose 安装与使用(常用指令)
Docker Compose 安装与使用(常用指令)
233 0
|
1月前
|
Java 网络安全 开发者
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
【Docker】5、Dockerfile 自定义镜像(镜像结构、Dockerfile 语法、把 Java 项目弄成镜像)
44 0
|
3月前
|
运维 Ubuntu Docker
【Docker】Dockerfile 构建文件
【1月更文挑战第26天】【Docker】Dockerfile 构建文件
|
3月前
|
应用服务中间件 nginx Docker
docker系列:dockerfile及其用法解析
docker系列:dockerfile及其用法解析
83 0
|
3月前
|
缓存 Ubuntu JavaScript
Docker自定义镜像-构建镜像-Dockerfile语法
Docker自定义镜像-构建镜像-Dockerfile语法
45 0