跳转至

常见 Dockerfile 指令

dockerfile 指令

  • 熟悉 Dockerfile 的指令是编写 Dockerfile 的前提
  • 这里是最常见的 Dockerfile 指令,它们基本上囊括了所有 Dockerfile 中90%以上的工作
指令 解释 通俗解释
FROM 基础镜像,一切从这里开始构建 这个镜像的爸爸是谁?
MAINTAINER 镜像的作者,姓名+邮箱 告诉别人,谁在维护他
RUN 镜像构建的时候需要运行的命令 想让他干啥
ADD COPY 文件,会自动解压 直接给点创业资金
COPY 类似 ADD,将文件宝贝到镜像中 给你个主意,需要你自己挣钱
WORKDIR 镜像的工作目录 给指定一个工作的地点,某个大厦
VOLUME 挂载的目录(设置卷,挂在主机目录) 给一个手机,有办法把赚到的钱从大厦给到老家
EXPOSE 指定对外的端口 给一个营业执照,让别人能看到
CMD 指定容器启动的时候运行的命令,可以被替换 指定工作内容、上班时该干什么
ENTRYPOINT 指定容器启动的时候运行的命令,只能追加
ONBUILD 当构建一个被继承DockerFile
ENV 构建的时候设置环境变量

FROM

  • 选择一个已经存在的镜像作为我们新镜像的基础,这种方式能够大幅减少我们的时间。
  • 可通过 FROM 指令指定一个基础镜像,接下来所有的指令都是基于这个镜像所展开的。在镜像构建的过程中,Docker 也会先获取到这个给出的基础镜像,再从这个镜像上进行构建操作。
  • FROM 指令支持三种形式,不管是哪种形式,其核心逻辑就是指出能够被 Docker 识别的那个镜像,好让 Docker 从那个镜像之上开始构建工作。
  • 可多次出现 FROM 指令,当 FROM 第二次或者之后出现时,表示在此刻构建时,要将当前指出镜像的内容合并到此刻构建镜像的内容里。这对于我们直接合并两个镜像的功能很有帮助。
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]

RUN

  • 镜像的构建虽然是按照指令执行的,但指令只是引导,最终大部分内容还是控制台中对程序发出的命令,而 RUN 指令就是用于向控制台发送命令的指令。
  • 在 RUN 指令之后,我们直接拼接上需要执行的命令,在构建时,Docker 就会执行这些命令,并将它们对文件系统的修改记录下来,形成镜像的变化。
RUN <command>
RUN ["executable", "param1", "param2"]

换行

RUN 指令是支持 换行的,如果单行的长度过长,建议对内容进行切割,方便阅读。

CMD 和 ENTRYPOINT

  • 基于镜像启动的容器,在容器启动时会根据镜像所定义的一条命令来启动容器中进程号为 1 的进程。
  • 而这个命令的定义,就是通过 Dockerfile 中的 NTRYPOINT 和 CMD 实现的。
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

Cmd

指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代

Entrypoint

指定这个容器启动的时候要运行的命令,可以追加命令

同时存在

当 ENTRYPOINT 与 CMD 同时给出时,CMD 中的内容会作为 ENTRYPOINT 定义命令的参数,最终执行容器启动的还是 ENTRYPOINT 中给出的命令

案例实践点击展开

CMD

1. 编写 Dockerfile

FROM centos
CMD ["ls","-a"]

2. 构建测试镜像

docker build -f Dockerfile -t test-cmd:v2.0 .

3. 运行

docker run  test-cmd:v2.0

4. 结果对比

运行镜像成功,CMD ["ls","-a"] 生效 image-20230504114743831

想追加一个 -l 相当于 ls -la,失败报错 image-20230504114806640

CMD 的镜像中 -l 替换了 `CMD ["ls","-a"]` 命令,-l 不是命令所以报错。

ENTRYPOINT

1. 编写 Dockerfile

FROM centos
ENTRYPOINT ["ls","-a"]

2. 构建测试镜像

docker build -f Dockerfile -t test-ENTRYPOINT:v2.0 .

3. 运行

docker run test-cmd:v2.0

4. 结果对比

运行镜像成功,ENTRYPOINT ["ls","-a"] 生效 image-20230504115530705

想追加一个 -l 相当于 ls -la 生效 image-20230504115633671

ENTRYPOINT 的镜像中 -l 拼接到了 `ENTRYPOINT ["ls","-a"]` 后面 ,ls -a -l 。 

EXPOSE

构建镜像时更了解镜像中应用程序的逻辑,也更加清楚它需要接收和处理来自哪些端口的请求,所以在镜像中定义端口暴露显然是更合理的做法。

  • 通过 EXPOSE 指令就可以为镜像指定要暴露的端口
EXPOSE <port> [<port>/<protocol>...]

结论

当我们通过 EXPOSE 指令配置了镜像的端口暴露定义,那么基于这个镜像所创建的容器,在被其他容器通过 --link 选项连接时,就能够直接允许来自其他容器对这些端口的访问了

VOLUME

  • 在一些程序里,我们需要持久化一些数据,比如数据库中存储数据的文件夹就需要单独处理。
  • 但使用数据卷需要我们在创建容器时通过 -v 选项来定义,而有时候由于镜像的使用者对镜像了解程度不高,会漏掉数据卷的创建,从而引起不必要的麻烦。
  • 制作镜像的人是最清楚镜像中程序工作的各项流程的,所以它来定义数据卷也是最合适的。提供了 VOLUME 指令来定义基于此镜像的容器所自动建立的数据卷。
VOLUME ["/data"]

结论

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

COPY 和 ADD

  • 在制作新的镜像的时候,我们可能需要将一些软件配置、程序代码、执行脚本等直接导入到镜像内的文件系统里,使用 COPY 或ADD 指令能够帮助我们直接从宿主机的文件系统里拷贝内容到镜像里的文件系统中。

  • COPY 与 ADD 指令的定义方式完全一样,需要注意的仅是当我们的目录中存在空格时,可以使用后两种格式避免空格产生歧义。

  • 对比 COPY 与 ADD,两者的区别主要在于 ADD 能够支持使用网络端的 URL 地址作为 SRC 源,并且在源文件被识别为压缩包时,自动进行解压,而 COPY 没有这两个能力。
  • 虽然看上去 COPY 能力稍弱,但对于那些不希望源文件被解压或没有网络请求的场景,COPY 指令是个不错的选择。
COPY [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

构建镜像

  • 在编写好 Dockerfile 之后,我们就可以构建我们所定义的镜像了,构建镜像的命令为 docker build

编写 dockerfile 构建 centos

Docker Hub 中 99% 镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行的构建

# 创建第一个 Dockerfile 文件

FROM centos

MAINTAINER linuxnbg.com

ENV MYPATH /usr/local

WORKDIR ${MYPATH}

RUN yum -y install vim net-tools

EXPOSE 80

CMD /bin/bash

使用如下命令构建脚本

docker build -t test-v1.0 .