07_Dockerfile
参考资料
Dockerfile是什么?
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令。
大白话:可用通过代码构建镜像,写的代码文件就是Dockerfile。
- Dockerfile构建镜像流程:
- 准备构建镜像需要的材料 -> 编写Dockerfile文件 -> 使用
docker build
构建镜像。
- 准备构建镜像需要的材料 -> 编写Dockerfile文件 -> 使用
注:编写Dockerfile需要一定的Linux基础,或者知道一些常用的Linux指令。
常用指令
常用指令表
分类 | 指令 | 说明 |
---|---|---|
构建指令 | FROM | 设置基础镜像 |
WORKDIR | 指定工作目录(类似cd到指定目录) | |
LABEL | 设置元数据 | |
VOLUME | 定义匿名数据卷 | |
运行指令 | RUN | 编译时运行后面的命令(类似在shell中执行命令) |
CMD | 启动时运行后面的命令,会被启动参数覆盖 | |
ENTRYPOINT | 与CMD类似,但不会被启动时参数覆盖 | |
参数指令 | ENV | 设置环境变量 |
ARG | 设置局部变量 | |
复制指令 | COPY | 拷贝文件,不解压 |
ADD | 添加文件,默认解压 |
常用指令详解
构建指令
FROM
设置基础镜像。有效的Dockerfile
必须从FROM
指令开始。
- 语法
FROM [--platform=<platform>] <image> [AS <name>]
# 或
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
# 或
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
- 示例
# 以centos:latest作为基础镜像
FORM centos
WORKDIR
指定工作目录。
- 语法
WORKDIR <容器内目录>
说明:WORKDIR可以在Dockerfile中多次使用,如果提供了相对路径,则它将相对于上一条
WORKDIR
指令的路径。例如:WORKDIR /a WORKDIR b WORKDIR c # 输出:/a/b/c RUN pwd
- 示例
# 设置工作目录
WORKDIR /path/to/workdir
# 输出:/path/to/workdir
RUN pwd
LABEL
标签。将元数据添加到镜像,一个镜像可以包含多个标签。
要查看镜像的标签,请使用docker image inspect
命令。可以使用该--format
选项仅显示标签。
- 语法
LABEL <key>=<value> <key>=<value> <key>=<value> ...
说明:在Docker 1.10之前的版本中,为减小镜像大小,尽可能的把多个标签写到一行,新版本会自动合并。
- 示例
# 添加维护者信息
LABEL maintainer="vv_lin<vv_lin@123.com>"
# 查看标签
docker image inspect --format='' myimage
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
在启动容器 docker run
的时候,我们可以通过 -v 参数修改挂载点。
- 语法
VOLUME ["<路径1>", "<路径2>"]
# 或
VOLUME <路径1> <路径2>
- 示例
# 在容器内部创建myvol目录
RUN mkdir /myvol
# 将myvol目录以匿名方式挂载到宿主机
VOLUME /myvol
注意:这里说的匿名挂载是站在宿主机角度看为匿名,容器内部的目录还是具名的。
运行指令
RUN
用于执行后面跟着的命令,只在编译时生效。
- 语法
# 执行命令,类似打开Linux的/bin/sh(或Window的cmd),并执行命令。
RUN <command>
# 或
RUN ["可执行文件", "参数1", "参数2"]
- 示例
# 1.使用yum安装wget
RUN yum install wget
# 2.下载tomcat包
RUN wget https://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.5.57/bin/apache-tomcat-8.5.57.tar.gz
# 3.解压tomcat
RUN tar -xvf apache-tomcat-8.5.57.tar.gz
# 或
# 执行HelloWorld.sh
# 类似 RUN ./HelloWorld.sh aaa bbb
RUN ["./HelloWorld.sh", "aaa", "bbb"]
注意:Dockerfile 的指令每执行一次都会在 Docker 镜像上新建一层。过多无意义的层,会造成镜像膨胀过大。以
&&
符号连接命令,这样执行后,只会创建 1 层镜像。如下:RUN yum install wget \ && wget https://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.5.57/bin/apache-tomcat-8.5.57.tar.gz\ && tar -xvf apache-tomcat-8.5.57.tar.gz
CMD
类似于 RUN
指令,用于运行程序。
RUN
和CMD
的区别:
-
RUN
是在docker build
时运行。 - CMD 在
docker run
时运行。
说明:
- Dockerfile中只能有一条
CMD
指令,如果有多条,只有最后一条生效。CMD
指令参数可被docker run
命令行参数覆盖。
- 语法
CMD ["可执行文件", "参数1", "参数2"]
# 或
# 该方式作为ENTRYPOINT的默认参数
CMD ["参数1", "参数2"]
# 或
CMD <命令> "参数1", "参数2"
示例
# 执行HelloWorld.sh
CMD ["./HelloWorld.sh", "aaa", "bbb"]
ENTRYPOINT
类似CMD
指令,但正常情况下不会被docker run
的命令行参数所覆盖。
如果非要覆盖,可以使用docker run
的 --entrypoint
选项强制覆盖。
说明:如果 Dockerfile 中如果存在多个
ENTRYPOINT
指令,仅最后一个生效。
- 语法
ENTRYPOINT ["可执行文件", "参数1", "参数2"]
# 或
ENTRYPOINT <命令> "参数1", "参数2"
- 示例
# 假设通过Dockerfile 构建了nginx:test镜像。
# Dockerfile如下:
FROM nginx
# 定参
ENTRYPOINT ["nginx", "-c"]
# 变参
CMD ["/etc/nginx/nginx.conf"]
- 不传参运行
# 命令
docker run nginx:test
# =>
# 容器内会默认运行以下命令(从CMD设定的参数取值)
nginx -c /etc/nginx/nginx.conf
- 传参运行
# 命令
docker run nginx:test -c /etc/nginx/nginx-custom.conf
# =>
# 容器内会默认运行以下命令(使用外部传递的参数)
nginx -c /etc/nginx/nginx-custom.conf
参数指令
ENV
设置环境变量。
若定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
- 语法
ENV <key> <value>
# 或
ENV <key>=<value> ...
- 示例
# 设置JAVA_HOME
ENV JAVA_HOME=/usr/lib/jvm/jdk8
# 使用
ENV PATH=$JAVA_HOME/bin:$PATH
ARG
构建参数,与 ENV类似。
ENV
和ARG
对比:
-
ENV
在Dockerfile和镜像中均可用; -
ARG
只在Dockerfile中可用。
说明:构建命令
docker build
中可以用--build-arg <参数名>=<值>
来覆盖。
- 语法
ARG <name>[=<default value>]
- 示例
# 设置参数
ARG hello_world=helloWorld!!
# 使用
RUN echo $hello_world
复制指令
COPY
复制,从上下文目录中复制文件或者目录到容器里指定路径。
- 语法
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
#或
# 包含空格的路径需要使用该形式
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
如果<源路径1>
是目录,则将复制目录的整个内容,目录本身不被复制,仅其内容被复制。
<src>
可以包含通配符。
注意:
--chown
仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用。
- 示例
# 1. 复制所有以“hom”开头的文件到容器的/mydir/目录下
COPY hom* /mydir/
# 2. "?"被替换为任何单个字符,例如“ home.txt”。
COPY hom?.txt /mydir/
# 3. 复制到相对路径中:<WORKDIR>/relativeDir/
COPY test.txt relativeDir/
ADD
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY),功能也类似。
不同之处如下:
-
ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
-
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
-
语法
ADD [--chown=<user>:<group>] <源路径1>... <目标路径>
# 或
# 包含空格的路径需要使用该形式
ADD [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
如果<源路径1>
是目录,则将复制目录的整个内容,目录本身不被复制,仅其内容被复制。
<src>
可以包含通配符。
注意:
--chown
仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用。ADD
可以通过远程文件URL添加文件。
- 示例
# 1. 复制所有以“hom”开头的文件到容器的/mydir/目录下
ADD hom* /mydir/
# 2. "?"被替换为任何单个字符,例如“ home.txt”。
ADD hom?.txt /mydir/
# 3. 复制到相对路径中:<WORKDIR>/relativeDir/
ADD test.txt relativeDir/
小试牛刀
通过Dockerfile构建一个最简单的镜像
- 通过Dockerfile构建一个最简单的镜像。
# 1. 编写Dockerfile文件
vim Dockerfile
# Dockerfile
FROM centos
RUN echo "Hello World!!" > hello_world.txt
- 根据Dockerfile构建镜像。
# 参数说明(注意后面有个“.”):
# -t mycentos:test 指定构建镜像的名称和标签
# . 指定镜像构建过程中的上下文环境的目录
docker build -t mycentos:test .
# 输出
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 0d120b6ccaa8
Step 2/2 : RUN echo "Hello World!!" > hello_world.txt
---> Running in f78e091a6c89
Removing intermediate container f78e091a6c89
---> efa3df984c1c
Successfully built efa3df984c1c
Successfully tagged mycentos:test
- 启动镜像。
# 查看所有镜像
docker images
# 使用交互模式运行镜像
docker run -it --name mycentos mycentos:test bash
# 在容器中查看目录结构
ls
# 输出结果,能看到hellow_world.txt
bin dev etc hello_world.txt home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 查看文件内容
[root@a5b50d7fa748 /]# cat hello_world.txt
# 输出结果
Hello World!!
构建镜像参数后面的".
",的意思
参考资料:
当构建的时候,由用户指定构建镜像的上下文路径,而docker build
会将这个路径下所有的文件都打包上传给 Docker引擎,引擎内将这些内容展开后,就能获取到所有指定上下文中的文件了。
比如:
Dockerfile中的COPY ./package.json /project
,其实拷贝的并不是本机目录下的package.json文件,而是Docker引擎中展开的构建上下文中的文件,所以如果拷贝的文件超出了构建上下文的范围,Docker引擎 是找不到那些文件的。
.dockerignore
文件的作用
参考资料:
.dockerignore
文件中指定在传递给 docker引擎
时需要忽略掉的文件或文件夹。
比如:
在前端项目中,node_modules
文件夹在构建镜像过程中如果用不到,但是又异常庞大,那么向 docker引擎
传递其实是并没有必要的,这个时候就可以将 node_modules
文件夹加入 .dockerignore
文件中。
通过Dockerfile构建Tomcat
- 使用vim编写Dockerfile
vim Dockerfile
# Dockerfile
# jdk + tomcat
FROM centos
# 添加标记
LABEL maintainer="vv_lin<vv_lin@123.com>"
# 创建目录
RUN mkdir -p /usr/local/java \
&& mkdir -p /usr/local/tomcat
# 设置工作空间
WORKDIR /usr/local
# 添加jdk
ADD jdk-8u202-linux-x64.tar.gz /usr/local/java/
# 添加tomcat
ADD apache-tomcat-8.5.57.tar.gz /usr/local/tomcat/
# 设置环境变量
# 设置java环境变量
ENV JAVA_HOME=/usr/local/java/jdk1.8.0_202
ENV CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar
# 设置tomcat环境变量
ENV CATALINA_HOME=/usr/local/tomcat/apache-tomcat-8.5.57
# 追加到PATH中
ENV PATH=$CATALINA_HOME/bin:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
# 挂载匿名磁盘
VOLUME ["/usr/local/tomcat/apache-tomcat-8.5.57/logs", "/usr/local/tomcat/apache-tomcat-8.5.57/webapps"]
# 声明端口
EXPOSE 8080
# 启动
ENTRYPOINT ["catalina.sh", "run"]
- 编译成镜像
# 注意后面的“.”
docker build -t mytomcat .
# 或
docker build -f Dockerfile -t mytomcat:latest .
# 或
docker build -f Dockerfile -t mytomcat .
说明:
docker build
默认读取名为Dockerfile,如果是其他名称,则需要使用-f <Dockerfile文件名>
指定文件名。
- 启动镜像
docker run -it --name mytomcat -p 8080:8080 mytomcat bash
- 通过浏览器访问,发现正常
- 查看挂载的目录
# 1. 查看所有挂载的目录
docker volume ls
# 输出
DRIVER VOLUME NAME
local 0ea11ee5a377263e6a62a61afdd554f12f3f61e0e69fb603794363637668f270
local 1c2c7f656fdea4a16471e9c066353d7b3423614f4dc6b9abfd3e8a0e6f163b5b
local 28ad647f7dc23b3a04c96f8ba8eeca08c0766a1b2669bc42162e43ddcd585164
local 85a5ba99cf1ca1a52e745685bede94be81f6d79e44ef108192d2d27817460331
local 9438df2f42126d5ac47a63916ae888f6c2d0dfb65e65634df6916c55ad231e0d
local 26817b63add34160593e512468510fbfa0e1d3326ef826c01f8d4a1a3d10ce8c
local testvolume
# 2. 查看挂载目录的元数据
docker volume inspect 1c2c7f656fdea4a16471e9c066353d7b3423614f4dc6b9abfd3e8a0e6f163b5b
# 输出
[
{
"CreatedAt": "2020-08-19T17:00:07+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/1c2c7f656fdea4a16471e9c066353d7b3423614f4dc6b9abfd3e8a0e6f163b5b/_data",
"Name": "1c2c7f656fdea4a16471e9c066353d7b3423614f4dc6b9abfd3e8a0e6f163b5b",
"Options": null,
"Scope": "local"
}
]
# 4. 查看挂载目录的内容
ls /var/lib/docker/volumes/1c2c7f656fdea4a16471e9c066353d7b3423614f4dc6b9abfd3e8a0e6f163b5b/_data
# 输出
docs examples host-manager manager ROOT