指令
一、FROM
FROM
指定基础镜像,用于后续的指令构建。
语法
FROM [--platform=<platform>] <image> [AS <name>]
// 或者
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
1.1 FROM php
1.2 FROM node
1.3 from mysql
1.4 FROM mongo
1.5 FROM nginx
1.6 FROM redis
1.7 FROM httpd
1.8 FROM centos
FROM centos
以 centos
镜像为基础, 定制镜像。
FROM centos
FROM centos as centos1 // 将 centos 命名为 centos1
1.9 FROM ubuntu
FROM ubuntu
以 ubuntu
镜像为基础, 定制镜像
FROM ubuntu
FROM ubuntu as ubuntu1 // 将 ubuntu 命名为 ubuntu1
1.10 FROM scratch
FROM scratch
基于 scratch
镜像来构建镜像。scratch
是一个空的镜像,里面什么都没有。
二、MAINTAINER
MAINTAINER
指定Dockerfile
的作者/维护者。(已弃用,推荐使用LABEL
指令)
三、LABEL
LABEL
添加镜像的元数据,使用键值对的形式。LABEL
指令用来给镜像添加一些元数据(metadata
)
2.1 语法
LABEL <key>=<value> <key>=<value> <key>=<value> ...
2.2 用法
我们可以添加镜像的作者
LABEL org.opencontainers.image.authors="runoob"
四、RUN
RUN
主要用于在镜像中执行命令。RUN
是执行命令并创建新的 Image Layer
。 每一个 RUN
命令都会创建一个新的镜像层,导致镜像的臃肿。为了减少镜像层数,可以将多个命令合并到一个 RUN
命令中,并使用 Shell
运算符 &&
链接。备注: 可以通过 docker history [镜像名称]:[镜像Tab]
查看镜像分层。
4.1 语法
shell
格式
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec
格式
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
ADD shell
格式: 命令被作为一个字符串传递给 /bin/sh -c
。
ADD exec
格式: 正确的 exec
形式 ADD
需要使用双引号 "
来包围整个数组及每个数组元素。这是因为 JSON
语法规定了数组和字符串必须用双引号来表示。不可以是 单引号, 否则这会导致 Docker
解析时将其视为 shell
形式。正确的 exec
格式命令被作为一个 JSON
数组传递,不会经过 /bin/sh
。
4.2 用法
一、在镜像中,通过 NPM
安装依赖, 并且启动服务: 因为每一个 RUN
命令都会创建一个新的镜像层。为了减少镜像层数,可以将多个命令合并到一个 RUN
命令中。Shell
格式中使用 &&
链接
FROM node:latest
RUN npm install && npm run start
五、CMD
CMD
设置容器启动后默认执行的命令和参数(可覆盖),同时 CMD
可以为 ENTRYPOINT
提供默认参数。CMD
指令指定的程序可被 docker run
命令行参数中指定要运行的程序所覆盖。类似于 RUN
指令,用于运行程序,但二者运行的时间点不同:
-
CMD
在docker run
时运行。 -
RUN
是在docker build
。
注意:如果 Dockerfile
中如果存在多个 CMD
指令,仅最后一个生效。
5.1 语法
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh
。
CMD shell
格式: 命令被作为一个字符串传递给 /bin/sh -c
。
CMD exec
格式: 正确的 exec
形式 CMD
需要使用双引号 "
来包围整个数组及每个数组元素。这是因为 JSON
语法规定了数组和字符串必须用双引号来表示。不可以是 单引号, 否则这会导致 Docker
解析时将其视为 shell
形式。正确的 exec
格式命令被作为一个 JSON
数组传递,不会经过 /bin/sh
。
5.2 用法
一、通过 CMD
打印日志
FROM ubuntu
CMD ["echo", "Hello, World!"]
// 1. 构建镜像
docker build -t cmd .
// 2. 运行镜像
docker run cmd
// 3. 输出 Hello, World!
二、通过 CMD []
来覆盖之前的 CMD
命令
FROM ubuntu:21.04
CMD []
三、docker run -it [镜像]:[镜像Tag] 命令
覆盖 CMD
命令
FROM ubuntu
CMD ["echo", "Hello, World!"]
// 1. 构建镜像
docker build -t cmd .
// 2. 运行镜像
docker run -it cmd echo "Hello World! 覆盖"
// 3. 输出 ello World! 覆盖, 覆盖了 CMD ["echo", "Hello, World!"] 命令
六、ENTRYPOINT
ENTRYPOINT
设置容器启动时运行的命令(不可被覆盖)。类似于 CMD
指令,但其不会被 docker run
的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT
指令指定的程序。但是, 如果运行 docker run
时使用了 --entrypoint
选项,将覆盖 ENTRYPOINT
指令指定的程序。
-
优点: 在执行
docker run
的时候可以指定ENTRYPOINT
运行所需的参数。 -
缺点: 如果
Dockerfile
中如果存在多个ENTRYPOINT
指令,仅最后一个生效。
6.1 语法
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
6.2 用法
一、通过 ENTRYPOINT
打印日志, 省略参数
FROM ubuntu
ENTRYPOINT ["echo"]
// 1. 构建镜像
docker build -t entrypoint .
// 2. 直接运行镜像
docker run entrypoint
// 3. 输出为空
// 4. 通过 -it 运行镜像
docker run -it entrypoint Hello World
// 5. 输出为 Hello World
二、通过 ENTRYPOINT
打印日志, 通过 CMD
设置 ENTRYPOINT
默认参数: 如果 docker run
中提供了额外参数, 那么会覆盖 CMD
提供的默认参数。
FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["Hello, World!"]
// 1. 构建镜像
docker build -t entrypoint .
// 2. 运行镜像
docker run entrypoint
// 3. 输出为 Hello, World!
// 4. 运行镜像
docker run -it entrypoint Hello World 覆盖
// 5. 输出为 Hello World 覆盖
三、通过 ENTRYPOINT
打印日志, 通过 ENTRYPOINT
设置参数: 如果在 docker run
中额外提供而来参数,那么会往后新增参数。
FROM ubuntu
ENTRYPOINT ["echo", "Hello World!"]
// 1. 构建镜像
docker build -t entrypoint1 .
// 2. 直接运行镜像
docker run entrypoint1
// 3. 输出为 Hello World!
// 4. 通过 -it 运行镜像
docker run -it entrypoint1 Hello World 覆盖
// 5. 输出为 Hello World! Hello World 覆盖
七、EXPOSE
EXPOSE
是 Dockerfile
中的一个指令,用于声明容器在运行时会监听的端口。可以用来记录容器应用程序所需的端口。它提供了一种规范化的方式来告诉其他开发者或运维人员该容器需要哪些端口。EXPOSE
并不是强制性的,你可以不在 Dockerfile
中指定它。即使没有 EXPOSE
,你仍然可以通过 -p
或 --publish
选项将容器端口映射到主机端口。
7.1 语法
EXPOSE <端口1> [<端口2>...]
八、ENV
ENV
在容器内部设置环境变量。定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。ENV
变量可以在构建过程中使用, 也可以在镜像中使用。
8.1 语法
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
8.2 用法
一、打印变量日志
FROM node
ENV a=1 b=2
CMD echo ${a} ${b}
九、ADD
ADD
将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的目标目录。如果目标目录不存在则会自动创建。ADD
指令和 COPY
的使用格类似(同样需求下,官方推荐使用 COPY
)。功能也类似,不同之处如下:
-
ADD
的优点:在执行<源文件>
为tar
压缩文件的话,压缩格式为gzip
,bzip2
以及xz
的情况下,会自动复制并解压到<目标路径>
。 -
ADD
的缺点:在不解压的前提下,无法复制tar
压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
因此,ADD
和 COPY
最佳实践为: 所有的文件复制均使用 COPY
指令, 仅在需要自动解压缩的场合使用 ADD
9.1 语法
ADD [本地文件] [镜像文件]
9.2 用法
一、将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的当前工作目录: 注意: 这里的目标目录是相对路径,因此它依赖于之前设置的工作目录。如果之前没有设置 WORKDIR
,它会复制到容器的根目录(/
)
ADD . .
二、将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的 /dist
目录: 这里的目标目录是绝对路径,因此它不依赖于工作目录,始终会将文件复制到容器的 /dist
目录。
ADD . /dist
三、指定镜像工作目录为 /dist
, 将本地当前目录下所有文件复制到镜像工作目录 /dist
, 之后的所有指令都会在这个目录下执行。
WORKDIR /dist
ADD . /dist // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的 /dist 目录。这里的目标目录是绝对路径,因此它不依赖于工作目录,始终会将文件复制到容器的 /dist 目录。
ADD . . // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的当前工作目录,在这里,由于 WORKDIR 设置为 /dist,因此它会将所有文件复制到 /dist 目录下。注意: 这里的目标目录是相对路径,因此它依赖于之前设置的工作目录。如果之前没有设置 WORKDIR,它会复制到容器的根目录(/)。、
// 总结: 在大多数情况下,效果是一样的,因为 WORKDIR 已经设置为了 /dist。但为了代码的清晰度和避免潜在的错误,通常建议使 用绝对路径,尤其是在复杂的 Dockerfile 中,使用绝对路径更容易理解和维护。
十、COPY
COPY
将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的目标目录。如果目标目录不存在则会自动创建。因此,ADD
和 COPY
最佳实践为: 所有的文件复制均使用 COPY
指令, 仅在需要自动解压缩的场合使用 ADD
10.1 语法
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
-
[--chown=<user>:<group>]
: 可选参数,用户改变复制到容器内文件的拥有者和属组。 -
<源路径>
: 源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足Go
的filepath.Match
规则 -
<目标路径>
: 容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
10.2 用法
一、将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的当前工作目录: 注意: 这里的目标目录是相对路径,因此它依赖于之前设置的工作目录。如果之前没有设置 WORKDIR
,它会复制到容器的根目录(/
)
COPY . .
二、将当前构建上下文(通常是 Dockerfile
所在的目录)中的所有文件和目录复制到容器的 /dist
目录: 这里的目标目录是绝对路径,因此它不依赖于工作目录,始终会将文件复制到容器的 /dist
目录。
COPY . /dist
三、指定镜像工作目录为 /dist
, 将本地当前目录下所有文件复制到镜像工作目录 /dist
, 之后的所有指令都会在这个目录下执行。
WORKDIR /dist
COPY . /dist // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的 /dist 目录。这里的目标目录是绝对路径,因此它不依赖于工作目录,始终会将文件复制到容器的 /dist 目录。
COPY . . // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的当前工作目录,在这里,由于 WORKDIR 设置为 /dist,因此它会将所有文件复制到 /dist 目录下。注意: 这里的目标目录是相对路径,因此它依赖于之前设置的工作目录。如果之前没有设置 WORKDIR,它会复制到容器的根目录(/)。、
// 总结: 在大多数情况下,效果是一样的,因为 WORKDIR 已经设置为了 /dist。但为了代码的清晰度和避免潜在的错误,通常建议使用绝对路径,尤其是在复杂的 Dockerfile 中,使用绝对路径更容易理解和维护。
十一、VOLUME
VOLUME
为容器创建挂载点或声明卷。定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷,名字是随机的 Hash
值。
-
避免重要的数据,因容器重启而丢失,这是非常致命的。
-
避免容器不断变大。
在启动容器 docker run
的时候,我们可以通过 -v
参数修改挂载点。如果我们没有通过 -v
指定挂载点, Docker
会默认生成一个 Hash
目录, 每次启动时值都不一样。
11.1 语法
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
11.2 用法
一、将Docker
工作目录 WORKDIR
持久化存储
// 1. 编辑 Dockerfile
WORKDIR /app
VOLUME ["/app"]
// 2. 运行 Docker 镜像, 需要通过 -v 来指定本地持久化存储数据的位置
docker run -t --name xx -v 本地指定位置:/app [镜像ID:Tag]
十二、WORKDIR
WORKDIR
设置后续指令的工作目录。指定工作目录。用 WORKDIR
指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR
会帮你建立目录。docker build
构建镜像过程中的,每一个 RUN
命令都是新建的一层。只有通过 WORKDIR
创建的目录才会一直存在。
理解: WORKDIR
的功能类似于 CD
, 用于进入到某个目录, 但是比 CD
好的一点是, 如果目录不存在会自动创建。
12.1 语法
WORKDIR <工作目录路径>
12.2 用法
一、指定镜像工作目录为 /dist
, 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的当前工作目录 dist
, 之后的所有指令都会在这个目录下执行。
WORKDIR /dist
COPY . /dist // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的 /dist 目录。这里的目标目录是绝对路径,因此它不依赖于工作目录,始终会将文件复制到容器的 /dist 目录。
COPY . . // 将当前构建上下文(通常是 Dockerfile 所在的目录)中的所有文件和目录复制到容器的当前工作目录,在这里,由于 WORKDIR 设置为 /dist,因此它会将所有文件复制到 /dist 目录下。注意: 这里的目标目录是相对路径,因此它依赖于之前设置的工作目录。如果之前没有设置 WORKDIR,它会复制到容器的根目录(/)。
十三、USER
USER
指定后续指令的用户上下文。用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
13.1 语法
USER <用户名>[:<用户组>]