1.Dockerfile概念
Dockerfile是一个文本格式的配置文件,用于定义Docker镜像的内容和构建步骤。它包含一系列指令,每个指令代表一个构建步骤,从基础镜像开始,逐步构建出最终的镜像。通过Dockerfile,用户可以精确地描述应用程序运行环境的配置、依赖项安装、文件复制等操作。这使得应用程序的部署和分发变得更加可控和可重复。Dockerfile的内容可以根据需求自定义,允许开发者根据应用程序的特性和需求来灵活配置镜像的构建过程,从而实现高效、可靠的容器化部署
2.Dockerfile的优缺点
优点:
简化部署:Dockerfile 使得应用的部署过程变得标准化和可重复
容器为单位的应用交付:开发者可以将应用和它的依赖打包到一个容器中,这就意味着应用可以在任何支持 Docker 的机器上运行
易于维护:Dockerfile 是代码,所以有版本控制
易于理解:Dockerfile 是一种声明式语言,可以让用户理解镜像是如何构建的
高效:使用 Dockerfile 构建的镜像层可以高度重用,因此镜像的大小也会小
缺点:
构建时间:每次构建都会重新安装所有依赖,这可能会增加构建时间
构建大小:每一层都会增加最终镜像的大小
安全问题:如果在 Dockerfile 中使用错误的指令或者将敏感信息暴露在 Dockerfile中,可能会引起安全问题
3.基本结构
Dockerfile由一行行命令语句组成,并且支持以 # 开头的注释行。
一般而言,Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
4.Dockerfile 指令详解
1. FROM:指定基础镜像,用于后续的指令构建
该指令有两种格式:
FROM
指定基础image为该image的最后修改的版本。或者:
FROM :
指定基础image为该image的一个tag版本。
例如:FROM ubuntu:20.04
2.RUN:构建镜像时运行的指令
# shell格式:就像在命令行中输入的Shell脚本命令一样。
RUN
# exec格式:就像是函数调用的格式。
RUN ["executable", "param1", "param2"]
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大
RUN apt-get update && apt-get install -y nginx
3.CMD:容器启动时要运行的命令
包含三种语法格式,如下所示:
# 第一种就是shell这种执行方式和写法
CMD command param1 param2
# 第二种是可执行文件加上参数的形式(推荐)
CMD ["executable","param1","param2"]
# 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
CMD ["","",...]
需要注意的是,一个Dockerfile中只能有一个有效的CMD,当定义多个CMD的时候,只有最后一个才会起作用。CMD会被docker run之后的参数替换,如果我们在Dockerfile中指定了CMD指令,通过在docker run命令行中也指定了要运行的命令,命令行中的指令会覆盖Dockerfile中的CMD指令
4.COPY:从上下文目录中复制文件或者目录到容器里指定路径
COPY <源路径> <目标路径>
# 复制宿主机文件index.html到容器/data/html/index.html
COPY index.html /data/html/index.html
# 复制宿主机data目录下文件(包括子目录)到容器/data/目录下,并不会复制目录本身
例:COPY data /data/
5.ADD:ADD 指令和 COPY 的使用类似(同样需求下,官方推荐使用COPY),功能也类似。除 此之外,ADD还支持使用tar文件和URL路径,并且会将tar压缩文件(gzip, bzip2以及 xz格式) 解压缩,如果指定的是url,会从指定的url下载文件放到目录中(如果url下载的文件为tar文件,则不会展开)
ADD
例:ADD /data/src/nginx-1.14.0.tar.gz /data/src/
6.ENV:在容器内部设置环境变量
ENV=
例:ENV JAVA_HOME=/usr/local/jdk1.7.0_79
ENV PATH=$JAVA_HOME/bin:$PATH
7.ENTRYPOINT:设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效
该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。
当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2 (shell内部命令)
比如:
# CMD指令将不会被执行,只有ENTRYPOINT指令被执行
CMD echo “Hello, World!”
ENTRYPOINT ls -l
另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分。ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。
FROM centos7
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
8.EXPOSE:EXPOSE指令用于告诉Docker容器监听哪些网络端口。在Dockerfile中使用EXPOSE指令并不会自动将容器的端口暴露出来,需要使用docker run命令的-p或者-P选项来映射容器内部端口到宿主机的端口
EXPOSE指令的语法格式为:
EXPOSE[/...]
其中,表示需要监听的端口号,可以是1-65535之间的整数;表示需要监听的协议,可以是tcp或udp。
如果需要监听多个端口,则可以在EXPOSE指令中多次指定端口号,或者使用“,”分隔多个端口号。
下面是一个示例:
FROM ubuntu:18.04
EXPOSE 80/tcp
EXPOSE 443/tcp
以上Dockerfile告诉Docker容器需要监听80和443端口,并使用tcp协议。在运行容器时,可以使用如下命令将容器内部的80端口映射到宿主机的8080端口:
docker run -p 8080:80 myimage
这样,就可以通过访问宿主机的8080端口来访问容器内部的80端口了
9.VOLUME:为容器创建挂载点或声明卷
作用:
避免重要的数据,因容器重启而丢失,这是非常致命的。
避免容器不断变大。
格式:VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
# 定义一个匿名卷
FROM ubuntu:16.04
VOLUME /data
# 定义多个匿名卷
FROM ubuntu:16.04
VOLUME ["/data", "/command"]
使用VOLUME指令后,Docker会在容器中创建一个或多个匿名卷(anonymous volume),这些匿名卷将持久化存储容器中的数据。当容器删除时,这些匿名卷不会被自动删除,需要手动删除它们。
10.USER:用于指定执行后续命令的用户和用户组
格式:USER <用户名>[:<用户组>]
USER user
USER user:group
11.ONBUILD:用于延迟构建命令的执行。简单的说,就是Dockerfile里用ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的Dockerfile 使用了之前构建的镜像FROM test-buil,这时执行新镜像的Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令
格式:ONBUILD <其它指令>
ONBUILD RUN mkdir test
12.ARG:构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile内有效,也就是说只有docker build 的过程中有效,构建好的镜像内不存在此环境变量。构建命令docker build 中可以用 --build-arg <参数名>=<值> 来覆盖
格式:ARG <参数名>[=<默认值>]
13.WORKDIR:指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录
格式:WORKDIR <工作目录路径>
WORKDIR /path/to/workdir
# 在 /p1/p2 下执行 vim a.txt
WORKDIR /p1 WORKDIR p2 RUN vim a.txt
14.LABEL:使用LABEL指令可以为镜像添加元数据,这些元数据可以包含关于镜像的描述、版本号、维护者信息等
LABEL指令的语法如下:
LABEL===...
比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors="runoob"
15.HEALTHCHECK:用于指定某个程序或者指令来监控 docker 容器服务的运行状态是否正常
语法格式如下:
# 设置检查容器健康状况的命令
HEALTHCHECK [OPTIONS] CMD <命令>
# 如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK NONE
5.示例