前言
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
FROM
指定基础镜像,必须为第一个命令。格式如下:
格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
示例:
FROM mysql:5.6
注:
tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER
维护者信息,格式如下:
格式:
MAINTAINER <name>
示例:
MAINTAINER bertwu
MAINTAINER xxx@163.com
MAINTAINER bertwu <xxx@163.com>
RUN
构建镜像时执行的命令,RUN用于在构建镜像时执行命令,其有以下两种命令执行方式:
1. shell执行
格式:
RUN <command>
2. exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
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 层镜像。
CMD
构建镜像后调用,也就是在容器启动时才进行调用。类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在 docker run 时运行。
- RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
CMD java -jar ${JAVA_NAME}
ADD
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget。
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行源文件为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到目标路径。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
COPY
复制指令,功能类似ADD,但是是不会自动解压文件,也不能访问网络资源从上下文目录中复制文件或者目录到容器里指定路径。容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。格式:
COPY ./${JAVA_NAME} /opt
ENTRYPOINT
略
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,格式如下:
LABEL version="1.0" \
description="This text illustrate"
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。格式:
ENV JAVA_NAME="appinfo-2.0.0.jar" \
EXPOSE_PORT=38080
以下示例设置 JAVA_NAME, 在后续的指令中可以通过 $JAVA_NAME引用:
COPY ./${JAVA_NAME} /opt
EXPOSE
指定于外界交互的端口,格式如下:
格式:
EXPOSE 端口号(默认协议是 TCP)
EXPOSE 端口号/协议
示例:
EXPOSE 8080
EXPOSE 80/tcp
EXPOSE 80/udp
EXPOSE 原理
- EXPOSE 并不会直接将端口自动和宿主机某个端口建立映射关系。
- 如果 docker run,指定了自动映射 -P,那么会将所有暴露的端口随机映射到宿主机的高阶端口(如果EXPOSE没有指定端口,那么使用 -P 参数无效)。
- 如果 docker run,指定了 --net=host 宿主机网络模式,容器中 EXPOSE 指令暴露的端口会直接使用宿主机对应的端口,不存在映射关系。
- 如果 EXPOSE 暴露的端口确定要和某个宿主机端口建立映射关系,还是要用到 docker run -p 参数【主机端口:容器端口】。
- EXPOSE 显式地标明镜像开放端口,一定程度上提供了操作的便利,也提高了 Dockerfile 的可读性和可维护性。
VOLUME
用于指定持久化目录(指定此目录可以被挂载出去),格式如下:
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
volume指令只是起到了声明了容器中的目录作为匿名卷,但是并没有将匿名卷绑定到宿主机指定目录的功能。当我们生成镜像的Dockerfile中以volume声明了匿名卷,并且我们以这个镜像run了一个容器的时候,docker会在安装目录下的指定目录下面生成一个目录来绑定容器的匿名卷(这个指定目录不同版本的docker会有所不同),我当前的目录为:/var/lib/docker/volumes/{容器ID}
。
指定volume只是为了避免用户忘记指定-v时导致的数据全部在容器中,这样的话容器一旦被删除所有的数据都丢失了。比如mysql,你不能说用户启动时没有指定-v,然后删了容器,就把mysql的数据文件都删了,那样生产上是会出大事故的,所以mysql的dockerfile里面就需要配置volume,这样即使用户没有指定-v,容器被删后也不会导致数据文件都不在了还是可以恢复的。volume与-v指令一样,容器被删除以后映射在主机上的文件不会被删除。
WORKDIR
指定工作目录。工作目录,类似于cd命令,用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。格式:
格式:
WORKDIR /path/to/workdir
示例:
WORKDIR /a (这时工作目录为/a)
WORKDIR b (这时工作目录为/a/b)
WORKDIR c (这时工作目录为/a/b/c)
注:
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY
等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
指定在创建容器后,终端默认登录后进来的工作目录,一个落脚点,默认根目录,通常绝对路径,CMD ENTRYPOINT 都会在这个目录下执行。
USER
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
示例:
USER www
注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。
镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
ARG
用于指定传递给构建运行时的变量(给dockerfile传参),相当于构建镜像时可以在外部为里面传参
格式:
ARG <name>[=<default value>]
示例:
ARG B=11
可以在build的时候指定值,build -t test --build-arg B=12,外面给他重新赋值
ONBUILD
用于设置镜像触发器
格式:
ONBUILD 后面可以接Dockerfile任何参数
示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
ONBUILD 后面跟指令,当前的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被触发
制作镜像
- 如果有多个RUN,自上而下依次运行,每次运行都会形成新的层,建议&& 放入一行运行。
- 如果有多个CMD,只有最后一个运行。
- 如果有多个Entrypoint,只有最后一个运行。
- 如果CMD和entrypoint共存,只有entrypoint运行,且最后的CMD会当做entrypoint的参数。
构建springboot应用
#基础镜像
FROM boatswain.registry.com.cn:30100/si-tech/os-jdk:v0.9.0
#镜像制作者信息
LABEL MAINTAINER="yangjj_tc@si-tech.com.cn" \
PRODUCT="EP产品"
#环境变量
ENV COMPANY="si-tech" \
DEPARTMENT="tc" \
PRODUCT="ep" \
JAVA_NAME="eplogin-2.5.0.jar" \
EXPOSE_PORT=38080
#指定工作空间
WORKDIR /${PRODUCT}
#拷贝文件到工作空间
COPY ./target/${JAVA_NAME} .
#指定与外部交换端口
EXPOSE ${EXPOSE_PORT}
#启动进程
CMD java -XX:+UseContainerSupport -XX:InitialRAMPercentage=75.0 -XX:MinRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0 -XX:-UseAdaptiveSizePolicy -jar ${JAVA_NAME}