看个例子:
# 定制镜像
FROM openjdk:8u191-jre-alpine3.9
RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone \
&& apk del tzdata
# 构建镜像
ARG JAR_FILE
COPY target/${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
定制镜像
FROM: 定制的镜像都是基于 FROM 的镜像,例子中的 openjdk:8u191-jre-alpine3.9 就是定制需要的基础镜像,为什么不用 Oracle JDK 呢,这是因为从2019年4月开始 Oracle JDK 8和11以上版本从 BCL 改为 OTN 协议,商用开始收费了。而 OpenJDK 是 GPL 的。
RUN: 用于执行后面的命令行。命令行有以下两种形式:
- shell 格式:以上例子FROM后的命令行就是 shell 格式的。
- exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
例子中我们可以看到主要执行了哪几个逻辑:
首先apk add tzdata 添加了一个 tzdata 的安装包。
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 设置了本地时间为上海时间。
echo "Asia/Shanghai" > /etc/timezone 修改本地时区为上海时区。
apk del tzdata 最后删除了 tzdata 安装包。
注意: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层镜像。
构建镜像
上下文路径,就是 docker 在构建镜像时所用的本机文件,会一起打包。没定义上下文路径的情况下,默认是 Dockerfile 所在的位置。
注意:上下文路径不要放无用的文件,不然会一起打包发送给 docker 引擎,文件过多会造成构建过程缓慢。
ENV: 设置环境变量,定义了环境变量,后边的指令中就可以使用这个变量。
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
ARG: 构建参数,与ENV作用一致,但作用域不一致。ARG设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
例子中的 JAR_FILE 实际获取的是 maven 中 pom.xml 文件配置的 JAR_FILE 参数。也就是编译后的 jar 包名称。
COPY: 复制执行,从上下文目录中复制文件或者目录到容器内指定路径。
ADD: 和 COPY 使用类似,官方推荐用 COPY,但是ADD 源文件为tar压缩文件,如gzip,bzip2 及 xz 文件,会自动复制并解压到目标路径。
CMD: 类似 RUN 指令,但是执行时间点不同,RUN 是在 docker build 时执行,CMD 是在 docker run 时执行。会被 docker run 时指定的指令覆盖,所以没啥用,变参感觉可以直接用 docker run 指定。定参用 ENTRYPOINT 更合适。
注意:多个 CMD 指令仅最后一个生效。
ENTRYPOINT: 类似 CMD 指令,但不会被 docker run 的命令行参数指定的指令覆盖,而且这些命令行参数会被当做参数送给ENTRYPIONT 指令指定的程序。
但是,如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
例子中执行了就是一个 java -jar app.jar 的命令, -Djava.security.egd=file:/dev/./urandom 是一个加快生成随机数的配置项。
VOLUME: 定义匿名数据卷。在启动容器时忘记挂在数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据丢失,因容器重启而丢失。
- 避免容器不断变大。
格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
EXPOSE: 仅声明端口。帮助镜像使用者理解这个服务的守护端口,方便配置映射。使用随机端口映射时,即docker run -P,会自动随机映射 EXPOSE 端口。
格式:
EXPOSE <端口1> [<端口2>...]
WORKDIR: 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
USER: 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户。格式:
USER <用户名>[:<用户组>]
LABEL: 用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...