什么是Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了构建镜像所需的指令和说明。
Dockerfile 文件具有特定的语法规则。
Docker 按照顺序执行 Dockerfile 文件里的指令集合。
官方文档:https://docs.docker.com/engine/reference/builder/
Dockerfile常用指令
FROM
指定基于哪个基础镜像来构建新镜像,如果没有指定tag,则使用默认latest。
FROM <image>:<tag>
Docker 中存在一个特殊的镜像 scratch
。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果以 scratch
为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
FROM scratch
注:
-
FROM
必须是第一个非注释行指令 - 默认会从本地查找指定的基础镜像,如果本地不存在,则会从远程拉取所需镜像。
RUN
用于执行命令行命令,有两种格式:
RUN <command>
RUN ["executable", "param1", "param2"]
示例:
RUN tar -xvf redis.tar.gz
需要执行多个命令时,推荐使用 &&
符号连接多个命令,这样执行后,只会创建 1 层镜像:
RUN apt-get update && mkdir -p /usr/src/redis && tar -xvf redis.tar.gz
LABEL
以键值对的形式给镜像添加一些元数据(metadata)。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
LABEL version="1.0" org.opencontainers.image.authors="xxx"
MAINTAINER (deprecated)
指定镜像作者及联系方式,已经弃用,推荐使用 LABEL
。
EXPOSE
暴露端口,可以指定端口是监听TCP还是UDP,如果不指定协议,默认为TCP。
要将 EXPOSE
和在运行时使用 -p <宿主端口>:<容器端口>
区分开来。-p
是映射宿主机端口和容器端口,就是将容器的对应端口服务公开给外界访问,而 EXPOSE
仅仅是声明容器打算使用什么端口而已,并不会在宿主机和容器进行端口映射。
EXPOSE <port> [<port>/<protocol>...]
示例:
EXPOSE 80/udp
要同时在 TCP 和 UDP 上公开,请包含两行:
EXPOSE 80/tcp
EXPOSE 80/udp
ENV
设置环境变量。
两种方式:
ENV <key> <value>
# 此语法不允许在单个ENV指令中设置多个环境变量,推荐使用第一种
ENV <key1>=<value1> <key2>=<value2>...
COPY
从上下文目录中复制文件或者目录到镜像内指定路径。
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
<src>
:源文件或者源目录可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则
<dest>
:可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR
指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
示例:
# 复制所有以 "hom" 开头的文件
COPY hom* /mydir/
# ?被替换为任何单个字符,例如 "home.txt"。
COPY hom?.txt /mydir/
# 使用相对路径,将 "test.txt" 添加到 <WORKDIR>/relativeDir/
COPY test.txt relativeDir/
ADD
ADD
指令和 COPY
的使用基本一致。ADD
和COPY
的不同在于:
- 如果
<src>
为一个tar
压缩文件,压缩格式为gzip
,bzip2
以及xz
的情况下,ADD
指令将会自动解压缩这个文件到<dest>
中 。 -
<src>
可以是一个URL
,这种情况下,Docker 引擎会试图去下载这个链接的文件放到<dest>
中。
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
CMD
启动容器时需要执行的命令。如果存在多个 CMD
指令,则只会有最后一个生效。使用docker run
命令启动容器时指定要运行的程序可以覆盖 CMD
指令。
有以下三种格式:
CMD ["executable","param1","param2"]
CMD ["param1","param2"] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
CMD command param1 param2
和 RUN
指令的区别:CMD
是在 docker run
时运行,而 RUN
是在 docker build
是执行。
ENTRYPOINT
类似 CMD
指令,但是不会被 docker run
指定的指令所覆盖。如果 Dockerfile 中如果存在多个 ENTRYPOINT
指令,仅最后一个生效。
有以下二种格式:
# exec格式
ENTRYPOINT ["executable", "param1", "param2"]
# shell格式
ENTRYPOINT command param1 param2
注意:
-
运行
docker run
命令时如果使用了--entrypoint
选项,将覆盖CMD
指令指定的程序。 -
搭配
CMD
命令使用,CMD
相当于是在给ENTRYPOINT
传参。
VOLUME
定义匿名数据卷。
格式如下:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器执行 docker run
的时候,我们可以通过 -v 参数修改挂载的数据目录。
USER
指定执行指令的用户。
有两种格式:
USER <user>[:<group>]
USER <UID>[:<GID>]
WORKDIR
指定工作目录,用 WORKDIR
指定的工作目录,会在构建镜像的每一层中都存在。如该目录不存在,WORKDIR
会帮你建立目录。
WORKDIR /path/to/workdir
ARG
设置在构建过程中使用的环境变量,也就是说ARG
设置的环境变量只有 docker build
的过程中有效,构建好的镜像内不存在此环境变量。
ARG <name>[=<default value>]
一个 Dockerfile 文件可能包含一个或多个ARG
指令。用户在使用docker build
构建时,可以使用--build-arg <varname>=<value>
标志的命令将其传递给构建器。
FROM busybox
ARG user1
ARG buildno
SHELL
更改执行shell命令的程序。
SHELL ["executable", "parameters"]
Linux 上的默认 shell 是["/bin/sh", "-c"]
,Windows 上是["cmd", "/S", "/C"]
。该SHELL
指令在 Windows 上特别有用,因为 Windows 有两种常用且截然不同的本机 shell:cmd
和powershell
,以及可用的备用 shell,包括sh
。
ONBUILD
Dockerfile 里 ONBUILD
指定的命令,在本次构建镜像的过程中不会执行。当有新的 Dockerfile 在构建镜像时使用了之前构建的镜像,会执行之前 Dockerfile 里 ONBUILD
指定的命令。
ONBUILD <其他指令>
STOPSIGNAL
设置容器退出时发出的关闭信号。
STOPSIGNAL signal
HEALTHCHECK
指定某个程序或者指令来监控容器的运行状态。
# 设置检查容器健康状况的命令
HEALTHCHECK [OPTIONS] CMD command
# 如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK NONE
HEALTHCHECK
支持下列选项:
-
--interval=<间隔>
:两次健康检查的间隔,默认为 30 秒; -
--timeout=<时长>
:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒; -
--retries=<次数>
:当连续失败指定次数后,则将容器状态视为unhealthy
,默认 3 次。
和 CMD
, ENTRYPOINT
一样,HEALTHCHECK
只可以出现一次,如果写了多个,只有最后一个生效。
使用Dockerfile构建镜像
(1)编写Dockerfile文件
vi Dockerfile
- 文件名一般就叫 Dockerfile。
Dockerfile文件内容如下:
FROM centos:7
LABEL version="1.0" org.opencontainers.image.authors="charles"
WORKDIR /usr/local
RUN mkdir -p /usr/local/java && mkdir -p /usr/local/tomcat
ADD jdk-11.0.12_linux-x64_bin.tar.gz /usr/local/java
ADD apache-tomcat-10.0.10.tar.gz /usr/local/tomcat
EXPOSE 8081
ENV JAVA_HOME /usr/local/java/jdk-11.0.12
ENV PATH $PATH:$JAVA_HOME/bin
CMD ["/usr/local/tomcat/apache-tomcat-10.0.10/bin/catalina.sh", "run"]
(2)使用 docker build
命令从 Dockerfile 和“上下文”构建 Docker 镜像。构建的上下文可以是构建执行所在的本地路径,也可以是远程URL,如Git库、tarball或文本文件等。
docker build [OPTIONS] PATH | URL | -
Options:
-
--add-host
:添加自定义主机到 IP 映射(host:ip)。 -
--build-arg
:设置构建时的变量。 -
--compress
:默认false,使用 gzip 压缩构建上下文。 -
--file, -f
:Dockerfile的完整路径,默认值为("PATH/Dockerfile")。 -
--label
:设置镜像的元数据。 -
--no-cache
:构建镜像时不使用缓存。 -
--tag, -t
,镜像的名字及标签,通常name:tag或者name格式,可以在一次构建中为一个镜像设置多个tag。
构建镜像:
在Dockerfile同级目录执行如下命令。
docker build -f Dockerfile -t mycentos:7 .
注意:jdk、tomcat和Dockerfile目录相同。
(3)基于刚刚创建的镜像启动容器:
docker run -id --name mycentos7 -p 8080:8080 mycentos:7
访问:http://127.0.0.1:8080/ 可以看到 tomcat 成功启动页面。