前言:Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
在一个文件夹中,如果有一个名字为 Dockfile 的文件,其内容满足语法要求,在这个文件夹路径下执行命令:docker build --tag name:tag .
,就可以按照描述构建一个镜像了。name 是镜像的名称,tag 是镜像的版本或者是标签号,不写的话默认为 lastest。注意后面有一个空格和点。
本文目录
1. FROM 指定基础镜像
FROM
指令用于指定其后构建新镜像所使用的基础镜像。FROM
指令必是Dockerfile
文件中的首条命令,启动构建流程后,Docker
将会基于该镜像构建新镜像,FROM
后的命令也会基于这个基础镜像。- 语法格式如下:
FROM <image># 或
FROM <image>:<tag># 或
FROM <image>:<digest>
- 通过
FROM
指定的镜像,可以是任何有效的基础镜像。FROM
有以下限制: -FROM
必须 是Dockerfile
中第一条非注释命令。- 在一个Dockerfile
文件中创建多个镜像时,FROM
可以多次出现。只需在每个新命令FROM
之前,记录提交上次的镜像 ID。-tag
或digest
是可选的,如果不使用这两个值时,会使用latest
版本的基础镜像。
2. RUN 执行命令
RUN
指令在镜像的构建过程中执行特定的命令,并生成一个中间镜像。- 语法格式如下(有两种格式):
shell
格式:
RUN <命令行命令># <命令行命令> 等同于,在终端操作的 shell 命令。
exec
格式:
RUN ["可执行文件", "参数1", "参数2"]# 例如:# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
RUN
命令将在当前image
中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行Dockerfile
中的下一个指令。- 层级
RUN
指令和生成提交是符合Docker
核心理念的做法。它允许像版本控制那样,在任意一个点,对image
镜像进行定制化构建。 RUN
指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache
参数,如:docker build --no-cache
。
注意:
Dockerfile
的指令每执行一次都会在
docker
上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -yinstallwget
RUN wget-O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar-xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum -yinstallwget\&&wget-O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"\&&tar-xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
3. COPY 复制文件
- 复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
- 语法格式如下:
COPY [--chown=<user>:<group>]<源路径1>... <目标路径>
COPY [--chown=<user>:<group>]["<源路径1>",... "<目标路径>"]
参数说明:
[--chown=<user>:<group>]
:可选参数,用户改变复制到容器内文件的拥有者和属组。<源路径>
:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>
:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
补充说明:
COPY
和
RUN
指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。
COPY
指令将从构建上下文目录中
<源路径>
的文件/目录复制到新的一层的镜像内的
<目标路径>
位置。比如:
COPY package.json /usr/src/app/
<源路径>
可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>
可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
此外,还需要注意一点,使用
COPY
指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。
4. ADD 更高级的复制文件
ADD
指令和COPY
的格式和性质基本一致(同样需求下,官方推荐使用COPY
)。但是在COPY
基础上增加了一些功能。比如<源路径>
可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到<目标路径>
去。- 在构建镜像时,复制上下文中的文件到镜像内,语法格式如下:
ADD <源路径1>... <目标路径>
ADD ["<源路径1>",... "<目标路径>"]
ADD
的优点:在执行<源文件>
为tar
压缩文件的话,压缩格式为gzip, bzip2
以及xz
的情况下,会自动复制并解压到<目标路径>
。ADD
的缺点:在不解压的前提下,无法复制tar
压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。- 注意:如果
docker
发现文件内容被改变,则接下来的指令都不会再使用缓存。关于复制文件时需要处理的/,基本跟正常的 copy 一致。
5. CMD
- 类似于
RUN
指令,用于运行程序,但二者运行的时间点不同:-CMD
在docker run
时运行,在构建时不进行任何操作。-RUN
是在docker build
,并生成一个新的镜像。 - 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
CMD
指令指定的程序可被docker run
命令行参数中指定要运行的程序所覆盖。 - 注意:如果
Dockerfile
中如果存在多个CMD
指令,仅最后一个生效。 - 语法格式如下(有三种格式):
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...]# 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是
sh
。
6. ENTRYPOINT
ENTRYPOINT
用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过ENTRYPOINT
指定的程序都会被设置为默认程序。- 类似于
CMD
指令,但其不会被docker run
的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT
指令指定的程序。 - 但是,如果运行
docker run
时使用了--entrypoint
选项,将覆盖 ENTRYPOINT 指令指定的程序。 - 优点:在执行
docker run
的时候可以指定ENTRYPOINT
运行所需的参数。 - 注意:如果
Dockerfile
中如果存在多个ENTRYPOINT
指令,仅最后一个生效。 - 语法格式如下:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配
CMD
命令使用:一般是变参才会使用
CMD
,这里的
CMD
等于是在给
ENTRYPOINT
传参,下面的示例会提到。
- 示例:
假设已通过
Dockerfile
构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"]# 定参
CMD ["/etc/nginx/nginx.conf"]# 变参
1、不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
7. ENV 设置环境变量
- 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
- 语法格式如下(有两种格式):
ENV <key><value>
ENV <key1>=<value1><key2>=<value2>...
- 这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如
RUN
,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV VERSION=1.0DEBUG=on \NAME="Happy Feet"
这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。
8. ARG
- 构建参数,与
ENV
作用一致。不过作用域不一样。ARG
设置的环境变量仅对Dockerfile
内有效,也就是说只有docker build
的过程中有效,构建好的镜像内不存在此环境变量。 - 构建命令
docker build
中可以用--build-arg <参数名>=<值>
来覆盖。 - 语法格式如下:
ARG <参数名>[=<默认值>]
例如,通过
ARG
指定两个变量:
ARG site
ARG build_user=IT笔录
以上我们指定了
site
和
build_user
两个变量,其中
build_user
指定了默认值。在使用
docker build
构建镜像时,可以通过
--build-arg <varname>=<value>
参数来指定或重设置这些变量的值。
docker build --build-arg site=itiblu.com -t itbilu/test .
这样我们构建了
itbilu/test
镜像,其中
site
会被设置为
itbilu.com
,由于没有指定
build_user
,其值将是默认值 IT 笔录。
9. VOLUME 定义匿名卷
- 定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
- 作用:- 避免重要的数据,因容器重启而丢失,这是非常致命的。- 避免容器不断变大。
- 语法格式如下:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器
docker run
的时候,我们可以通过
-v
参数修改挂载点。
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
- 卷可以容器间共享和重用
- 容器并不一定要和其它容器共享卷
- 修改卷后会立即生效
- 对卷的修改不会对镜像产生影响
- 卷会一直存在,直到没有任何容器在使用它
VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。
10. EXPOSE
- 为构建的镜像设置监听端口,使容器在运行时监听(仅仅只是声明端口)。
- 作用: - 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。- 在运行时使用随机端口映射时,也就是
docker run -P
时,会自动随机映射EXPOSE
的端口。 - 语法格式如下:
EXPOSE <port>[<port>...]
EXPOSE
指令并不会让容器监听host
的端口,如果需要,需要在docker run
时使用-p
、-P
参数来发布容器端口到host
的某个端口上。
11. WORKDIR 指定工作目录
- 指定工作目录。用
WORKDIR
指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR
会帮你建立目录。 docker build
构建镜像过程中的,每一个RUN
命令都是新建的一层。只有通过WORKDIR
创建的目录才会一直存在。- 语法格式如下:
WORKDIR <工作目录路径>
- 通过
WORKDIR
设置工作目录后,Dockerfile
中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。
例如,使用
WORKDIR
设置工作目录:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
在以上示例中,pwd 最终将会在
/a/b/c
目录中执行。在使用
docker run
运行容器时,可以通过
-w
参数覆盖构建时所设置的工作目录。
12. USER 指定当前用户
- 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
- 语法格式如下:
USER<用户名>[:<用户组>]
- 使用
USER
指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。以下都是合法的指定:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
- 使用
USER
指定用户后,Dockerfile
中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过-u
参数来覆盖所指定的用户。
13. HEALTHCHECK
- 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
- 语法格式如下:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令>: 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
14. ONBUILD
ONBUILD
用于设置镜像触发器。- 语法格式如下:
ONBUILD <其它指令>
- 当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。
如,当镜像被使用时,可能需要做一些处理:
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
15. LABEL
LABEL
用于为镜像添加元数据(metadata),元数以键值对的形式指定。- 语法格式如下:
LABEL <key>=<value><key>=<value><key>=<value>...
使用
LABEL
指定元数据时,一条
LABEL
指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条
LABEL
指令指定,以免生成过多的中间镜像。
例如,通过
LABEL
指定一些元数据:
LABEL version="1.0"description="这是一个Web服务器"by="IT笔录"
指定后可以通过
docker inspect
查看:
docker inspect itbilu/test
"Labels":{"version":"1.0",
"description":"这是一个Web服务器",
"by":"IT笔录"},
16. STOPSIGNAL
STOPSIGNAL
用于设置停止容器所要发送的系统调用信号。- 语法格式如下:
STOPSIGNAL signal
所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。
17. SHELL
SHELL
用于设置执行命令(shell式)所使用的的默认shell
类型。- 语法格式如下:
SHELL["executable", "parameters"]
SHELL
在 Windows 环境下比较有用,Windows 下通常会有cmd
和powershell
两种shell
,可能还会有sh
。这时就可以通过SHELL
来指定所使用的shell
类型:
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host helloSHELL["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo helloSHELL["cmd", "/S"", "/C"]
RUN echo hello
18. 实践操作(Ubuntu)
1. 创建 DockerFile 文件
- 首先创建一个空文件夹单独存放
Dockerfile
文件,然后创建一个Dockerfile
文件。命令如下:
mkdir mydocker
cd mydocker
touch Dockerfile
2. 进入文件
命令如下:
sudovim Dockerfile
注意:
有的虚拟机可能没有安装
vim
,导致会出现下面这样的错误:
sudo: vim: command not found
此时,可以输入下面这条命令进行下载:
sudoapt-getinstall vim-gtk
进入文件后的界面如下:
补充:文件编辑好之后如何进行退出?
- 【要退出,但是不保存】:先按
Esc
,然后输入:q
,按回车键即可退出。无法退出,则在:q
加入一个叹号!
,再按回车键就行了,即!q!
。 - 【要退出,保存】:先按
Esc
,输入:wq
,按回车键即可退出。强制保存退出,则输入:wq!
。 - 【以
nano
开头编辑文件的要退出】:按Ctrl+x
,回车键。如要保存的,则先按Ctrl+o
,再按x
退出。
3. 输入文件内容
#基础镜像
FROM ubuntu
#维护者信息
MAINTAINER carson [email protected]
#镜像的操作指令
RUN apt-get update &&apt-getinstall-y inotify-tools nginx apache2 openssh-server
#容器启动时的执行命令
CMD /user/sbin/nginx
补充:在
Dockerfile
中添加维护者信息是可选的,它用于指定镜像的作者或维护人员。维护者信息可以帮助其他人了解镜像的来源和相关信息。以下是在
Dockerfile
中添加维护者信息的语法和示例:
- 语法:
MAINTAINER <作者或维护者的姓名和邮箱>
- 示例:
FROM ubuntu:latest
MAINTAINER John Doe <[email protected]># 添加其他指令...
在示例中,我们使用
FROM
指令指定基础镜像为最新版本的
Ubuntu
。然后,使用
MAINTAINER
指令指定了维护者的姓名和邮箱地址。
注意:从
Docker 1.13
版本开始,
MAINTAINER
指令已经被标记为过时(deprecated)。推荐使用
LABEL
指令来添加维护者信息和其他元数据。下面是使用
LABEL
指令的示例:
FROM ubuntu:latest
LABEL maintainer="John Doe <[email protected]>"
# 添加其他指令
...
使用
LABEL
指令的好处是可以添加多个标签,包括维护者信息和其他自定义元数据,使镜像更丰富和可理解。
总结起来,可以选择使用
MAINTAINER
或
LABEL
指令来添加维护者信息,具体选择取决于使用的
Docker
版本和个人偏好。
4. 生成镜像
- 编辑完
Dockerfile
后使用docker build
指令生成镜像。命令如下:
docker build -t myngix .
运行该命令后的截图:
5. 验证镜像是否生成成功
输入以下命令:
# 普通用户涉及权限问题,在该命令之前加上 sudo 即可docker images
由上面的截图可知,镜像生成成功!
版权归原作者 mortalོ 所有, 如有侵权,请联系我们删除。