Dockerfile
什么是Dockerfile
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本
Dockerfile官网地址:docs.docker.com/reference/d…
Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -y install wget
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 -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 &&
符号连接命令,这样执行后,只会创建 1 层镜像
Dockerfile构建过程
Dockerfile关键词详解
关键词 | 说明 |
---|---|
FROM | 指定基础镜像,用于后续的指令构建。必须是第一条指令 |
MAINTAINER | 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令) |
LABEL | 添加镜像的元数据,使用键值对的形式。 |
RUN | 在 构建镜像(docker build) 时运行 |
CMD | 指定容器启动(docker run)后的要干的事情。(如果有多个CMD,只有最后一个会被执行。可以被docker run后跟的执行程序覆盖) |
ENTRYPOINT | 也是用来指定一个容器启动时要运行的命令,它类似CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINIT指令指定的程序。设置容器创建时的主要命令。(不可被覆盖) |
EXPOSE | 声明容器运行时监听的特定网络端口。 |
ENV | 用来在构建镜像过程中设置环境变量,后续可以通过$引用 |
ADD | 将文件、目录或远程URL复制到镜像中,且自动解压 |
COPY | 将文件或目录复制到镜像中。 |
VOLUME | 为容器创建挂载点或声明卷。 |
WORKDIR | 指定在创建容器后,终端默认登录进来后的工作目录;设置后续指令的工作目录。 |
USER | 指定后续指令的用户上下文。 |
ARG | 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。 |
ONBUILD | 当该镜像被用作另一个构建过程的基础时,添加触发器。 |
STOPSIGNAL | 设置发送给容器以退出的系统调用信号。 |
HEALTHCHECK | 定义周期性检查容器健康状态的命令。 |
SHELL | 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。 |
FROM
FROM 为这次构建流程指定基础镜像,必须是第一条指令
示例:
- FROM redis 默认使用 latest 版本作为基础镜像
- FROM redis:7.0.5
- FROM redis@7614ae9453d1
- FROM scratch 即代表不以任何镜像为基础
scratch 是一个空镜像,可用于构建 debian, busybox 等超小镜像,真正地从零开始构建镜像
WORKDIR
WORKDIR 指定后续指令的工作目录,类似于 Linux 中的 cd 命令。如果目录不存在,则会直接创建
LABEL
为镜像添加元数据
LABEL author="matio" version="1.0.0" \
desc = "Dockerfile案例"
LABEL maintainer="matio"
可以使用如下命令查看某镜像的元数据:
docker image inspect -f='{{json .ContainerConfig.Labels}}' 镜像ID
ENV
设置环境变量
ENV k1=v1 k2=v2
ENV k1 v1
查看最终镜像中的环境变量
docker image inspect -f='{{json .ContainerConfig.Env}}' 镜像ID
COPY
从上下文目录中复制文件或者目录到容器里指定路径。只能复制宿主机本地的文件。格式:
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=:] :可选参数,用户改变复制到容器内文件的拥有者和属组。
<源路径> :源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径> :容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
ADD
功能类似linux系统中的scp
命令,支持自动解压
ADD 指令和 COPY 的使用格式和功能类似(同样需求下,官方推荐使用 COPY),不同之处如下:
-
ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
-
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
RUN
在 构建镜像(docker build) 时运行,有2种格式:
shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
# 例如:
# RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
# RUN echo "Asia/Shanghai" > /etc/timezone
# RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# RUN mkdir -p /user/test
# RUN echo "Asia/Shanghai" > /etc/timezone && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在 docker run 时运行
- RUN 在 docker build 时运行
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖(可以参考下面的CMD覆盖案例)。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
CMD覆盖案例
# 在启动tomcat容器的时候会去执行Dockerfile中的最后一个CMD ["catalina.sh","run"],这个CMD就是用来启动tomcat容器重点tomcat服务的
docker run -it -p 8080:8080 tomcat
# CMD ["/bin/bash"] 会覆盖Dockerfile的CMD,所以这里执行完成后其实只是启动了tomcat容器,但是tomcat容器重点tomcat服务没有启动
docker run -it -p 8080:8080 tomcat /bin/bash
ENTRYPOINT
也是用来指定一个容器启动时要运行的命令,它类似CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINIT指令指定的程序。设置容器创建时的主要命令。(不可被覆盖)
EXPOSE
声明当前容器要访问的网络端口,但是仅仅是声明要暴露的端口,启动的时候并不会直接能访问到,需要在启动容器的时候添加 -p
参数来挂载宿主端口
EXPOSE 80
EXPOSE 8080/tcp 9090/udp
-
EXPOSE 约定容器运行时监听的端口,通常用于容器与外界之间的通信
-
EXPOSE并不会真正将端口发布到宿主机,而是作为一种约定,让镜像使用者在运行容器时,用 -p 分别发布约定端口,或者 -P 发布所有约定端口
-
如果没有暴露端口,运行容器是也可以通过 -p 的方式映射端口
使用Dockerfile构建一个容器
现在我们进入到test目录下新建一个Dockerfile文件并添加以下内容:
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
在test目录下执行以下命令,基于该Dockerfile文件构建一个docker容器:
docker build -t nginx:test .
-t nginx:test
指定镜像的名称和tag.
上下文路径是当前目录
查看建好的容器如下:
root@iZuf63y0r6z2tc37u0q5l8Z:~/test# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx test 94461960a4e7 2 minutes ago 188MB
docker build -f ./Dockerfile -t app .
参数说明:
- -t :新的镜像名(app:latest)
- . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径