Dockerfile是一个用来构建镜像的文本文件,里面包含了指令,配置,环境,环境变量等等信息。
查看镜像的Dockerfile
打开https://hub.docker.com/网页,搜索想要查找的镜像。
这就是mysql8的Dockerfiel文件内容
Dockerfile指令说明
FROM
位于Dockerfile开头,表示基于什么镜像构建。
# 语法:FROM <基础镜像>
# 例如:
FROM centos # 表示基于centos开始构建镜像
FROM openjdk:8-jdk-alpine # 表示基于openjdk开始构建镜像
复制代码
LABEL
Dockerfile的元数据,描述作用。
# 语法:LABEL <key>=<value> <key>=<value> <key>=<value> ...
# 例如:
LABEL version="1.0" author="codelong" description="dockerfile demo"
复制代码
RUN
运行命令,每次run都会生成一个图层,所以最好将命令合并执行,有以下俩种格式:
shell格式:
# 语法:RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
# 例如:
RUN yum -y update \ # '\'代表换行
&& yum install -y vim # '&&'代表合并多条
复制代码
exec格式:
# 语法:RUN ["可执行文件", "参数1", "参数2"]
# 例如:
RUN ["/bin/bash", "-c", "echo hello"] 等价于 RUN /bin/bash -c echo hello
复制代码
WORKDIR
用于指定工作目录,切换路径。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
WORKDIR /code # 没有则自动创建code目录
WORKDIR demo
RUN pwd
复制代码
输出 /code/demo。
最好不要用RUN cd来切换目录,而使用WORKDIR,这样可以减少不必要的图层,尽量使用绝对目录。
ADD ©
ADD和COPY都可以将构建环境中的文件或目录复制到镜像中。
# 语法:ADD <当前主机的文件或目录> <容器内部的文件或路径>
# 例如:
WORKDIR /demo
ADD data.txt code/data.txt
复制代码
# 语法:COPY <当前主机的文件或目录> <容器内部的文件或路径>
# 例如:
WORKDIR /demo
COPY data.txt code/data.txt
复制代码
最终都会将data.txt文件添加到/demo/code/目录下。
区别:
- ADD 添加的文件是压缩文件的话,会自动解压。
- COPY 只能复制构建目录下的文件,ADD可以添加一个构建上下文中的文件或目录,也可以是一个URL。
ADD https://www.baidu.com/data.zip /
复制代码
ENV
这个指令很简单,就是设置环境变量,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。它有如下两种格式:
# 语法1:ENV <key> <value>
# 语法2:ENV <key1>=<value1> <key2>=<value2>...
# 例如:
ENV MYSQL_VERSION 1.12
ENV GOSU_VERSION=1.12 JAVA_HOME=/app/jdk1.8/
#RUN使用环境变量
RUN echo "${JAVA_HOME}"
复制代码
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
# 语法1:CMD <shell 命令>
# 语法2:CMD ["<可执行文件或命令>","<param1>","<param2>",...]
# 语法3:CMD ["<param1>","<param2>",...] # 该写法是为 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
复制代码
VOLUME
该指令使容器中的一个目录具有持久化存储的功能,该目录可被容器本身使用,也可共享给其他容器。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。如 VOLUME /tmp
这里的 /tmp 目录就会在运行时自动挂载为匿名卷,任何向 /tmp 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:docker run -d -v mydata:/tmp xxxx
EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
- 要将
EXPOSE
和在运行时使用-p <宿主端口>:<容器端口>
区分开来。-p
,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而EXPOSE
仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
Shell和Exec格式说明
在Dockerfile中,命令的写法有Shell格式和Exec格式:
Shell格式的Dockerfile如下:
RUN apt-get install -y vim
CMD echo "hello world"
ENTRYPOINTT echo "hello world"
复制代码
Exec格式如下所示:
RUN ["apt-get","install","-y","vim"]
CMD ["/bin/echo","hello world"]
ENTRYPOINTT ["/bin/echo","hello world"]
复制代码
在使用Exec格式的时候需要注意和常量的搭配使用问题,比如在Shell格式下:
FROM ubuntu
ENV name codelong
ENTRYPOINTER echo "hello $name"
复制代码
创建镜像,运行容器后输出:hello codelong。
但是在Exec格式下:
FROM ubuntu
ENV name codelong
ENTRYPOINTER ["/bin/echo","hello $name"]
复制代码
创建镜像,运行容器后输出:hello $name。
正确的写法是:
FROM ubuntu
ENV name codelong
ENTRYPOINTER ["/bin/bash","-c","echo hello $name"]
复制代码