应用系统定制开发【docker系列】逐行解析Nginx镜像Dockerfile(学习经典)

文章目录


应用系统定制开发我一直觉得学习程序最应用系统定制开发快的方式就是:应用系统定制开发首先自学一些基本概念,应用系统定制开发然后去看看大牛是怎么写代码的,应用系统定制开发通过模仿大牛的写法然后领悟,应用系统定制开发是学习编程最快的方法。 应用系统定制开发可能有的朋友会说:应用系统定制开发哪有那么多大牛的代码给你看啊,请去github应用系统定制开发上面有很多的开源组织官方代码。我们学习Dockerfile也不例外,应用系统定制开发尽量使用官方资源去学习,应用系统定制开发看看人家是怎么写的,应用系统定制开发此文就和大家一起逐行解析nginx应用系统定制开发官方的镜像构建文件Dockerfile。本文中涉及的脚本都可以在官方渠道获取。

一、什么是Dockerfile

Dockerfile是自动构建镜像的配置文件,将镜像构建过程通过指令的方式定义在Dockerfile中。配合docker build命令行可以实现自动化的Docker镜像的构建。

FROM debian:bullseye-slimLABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"ENV NGINX_VERSION   1.20.2ENV NJS_VERSION     0.7.0ENV PKG_RELEASE     1~bullseyeRUN set -x \  #节省篇幅,主要是学习Dcokerfile语法,这里省略了若干行linux的shell脚本COPY docker-entrypoint.sh /COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.dCOPY 20-envsubst-on-templates.sh /docker-entrypoint.dCOPY 30-tune-worker-processes.sh /docker-entrypoint.dENTRYPOINT ["/docker-entrypoint.sh"]EXPOSE 80STOPSIGNAL SIGQUITCMD ["nginx", "-g", "daemon off;"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

上图是:1.20.2版本docker镜像的Dockerfile,下面我们来逐行解析。

二、解析nginx的Dockerfile语法

我们在学习一门语言或文档语法的时候,最快的学习方式就是看别人是怎么写的。这里这个“别人”是谁就很重要,跟着臭棋篓子下棋越下越臭。所以学习Dockerfile语法,我们有必要找一个模范:大家可以去Dockerhub看一下那些开源软件官方提供的镜像,都可以找到对应的Dockerfile,看看别人是怎么写的。
我们就以上文中的nginx:1.20.2版本docker镜像的Dockerfile( 官方提供的),我们来逐行解析它的语法及构建过程。

FROM

一般我们构建镜像的都需要一个基础的linux操作系统的发行版镜像,并且在此基础上我们构建自己的镜像。

FROM debian:bullseye-slim
  • 1

所以FROM指令的作用就是指定基础镜像,nginx这里使用的基础linux镜像是debian:bullseye-slim。其中debian:bullseye是的linux发行本操作系统的一个版本,版本名称叫做bullseye。slim通常是指这个镜像是该发行版本中的最小安装版本,因为我们构建完成的镜像是要在后续的持续集成过程中,以及仓库和docker服务器之间网络传播的,所以尽可能让镜像的构建结果size最小化。基础镜像的选择要着重考虑size的大小,满足linux基本功能及你的程序运行的前提下越小越好

LABEL

LABEL用于给当前镜像添加一些描述、解释性信息,如:当前镜像的维护人及联系方式等信息。用键值对的方式自定义,一行可以定义多个。

LABEL <key>=<value> <key>=<value> <key>=<value> ...
  • 1

也可以定义多行,如maintainer维护人信息,description镜像描述信息。如果描述信息一行写不下,可以用“\”换行。Dockerfile语法中有一个指令叫做MAINTAINER,专门用于描述该镜像的维护人信息,但是现在已经不建议使用了,统一使用LABEL

LABEL maintainer="NGINX Docker Maintainers "LABEL description="This is a Docker image \for nginx 1.20.2. "
  • 1
  • 2
  • 3

ENV

ENV的作用是设置环境变量,该环境变量设置之后,可以在构建过程及容器运行时的shell脚本中使用该变量,使用方法如:${NGINX_VERSION}。学过JAVA的同学想想你的JAVA_HOME环境变量怎么设置的以及怎么使用的?ENV是同样的道理。只不过放到docker这里语法发生了变化而已,语法格式:ENV 环境变量KEY 环境变量Value

ENV NGINX_VERSION 1.20.2ENV NJS_VERSION 0.7.0ENV PKG_RELEASE 1~bullseye
  • 1
  • 2
  • 3

RUN

RUN指令的作用就是执行linux的shell脚本,通过下图可以看到在shell脚本中可以使用通过ENV定义的环境变量。

对于nginx镜像而言,RUN指令的作用就是执行一系列shell命令行(脚本)来完成nginx的安装。所以说要想掌握RUN指令的重点不在于RUN指令本身,关键在于:

  • 你会不会手动安装nginx?
  • 你会不会linux的shell脚本语法?
  • 你能不能把nginx的安装过程写成shell脚本?

如果上面三个问题的答案都是肯定的,用RUN指令即可执行shell脚本完成软件的安装。这也是Dockerfile编写内容的核心所在,linux shell并不是本文要为大家说明的内容。

COPY

COPY指令的作用是将本地文件(执行镜像构建所在的服务器),拷贝到镜像文件中。语法是:COPY <本地文件路径>:<镜像文件路径>,镜像文件路径同时也是容器运行时文件系统的路径。

COPY docker-entrypoint.sh /COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.dCOPY 20-envsubst-on-templates.sh /docker-entrypoint.dCOPY 30-tune-worker-processes.sh /docker-entrypoint.d
  • 1
  • 2
  • 3
  • 4

如果本地文件路径只有文件名,就是表示文件和Dockerfile在同一个目录下(相对路径语法)。即:下面的这些文件在同一个目录(这些文件在我上文给出的nginx官方Dockerfile连接中都可以看到)。

另外可以使用WORKDIR 指令为 Dockerfile 中跟随它的任何 RUN、CMD、ENTRYPOINT、COPY、ADD 指令设置本地工作目录。这样上文提到的相对路径,就是相对WORKDIR指定路径的相对路径。但是通常情况下,不建议使用WORKDIR,因为很难保证执行构建的开发者工作主机的工作路径和Dockerfile编写者的工作路径都是一致的。

WORKDIR  /root
  • 1

ENTRYPOINT

一个Dockerfile中如果定义多个ENTRYPOINT,只有最后一条ENTRYPOINT生效,并且每次启动docker容器,都会执行ENTRYPOINT指定的脚本。对于nginx:1.20.2而言,"/docker-entrypoint.sh"脚本中定义了nginx配置检查及nginx服务的启动指令。所以通常情况下ENTRYPOINT指定的脚本通常都是镜像内核心服务的启动脚本

ENTRYPOINT ["/docker-entrypoint.sh"]
  • 1

这个脚本中最后执行了nginx服务启动,需要配合CMD命令完成,参考下文的CMD命令。

EXPOSE

Docker 容器在运行时暴漏指定的网络端口,可用于容器端口映射,默认协议是 TCP。格式如下:

EXPOSE <端口号>EXPOSE <端口号>/<协议>
  • 1
  • 2

将容器端口暴露出去后,可以与宿主机的端口建立映射关系,这样可以通过访问宿主机的端口来访问容器内部的服务。比如同时在 TCP、UDP 上暴露容器的80端口。

EXPOSE 80/tcpEXPOSE 80/udp
  • 1
  • 2

STOPSIGNAL

这个指令笔者也并不常用,我查询了docker-nginx在github上的issues里面给出的答案是,之所以加上STOPSIGNAL信号的目的是:避免docker容器停止后,nginx服务不能正确终止造成僵尸进程的存在。

STOPSIGNAL SIGQUIT
  • 1

CMD

CMD指令也是用来执行linux命令或脚本,这一点和RUN指令是一致的。二者的区别在于

  • CMD指令是在执行docker run指令时被执行,也就是创建容器时执行;而RUN指令实在镜像构建的时候执行,即docker bulid时候执行。
  • 也正因为指令的执行期不同,RUN命名执行的写入操作被写入到镜像层。CMD指令执行结果包含写入操作,被写入到容器层。(可以参考我之前文章《镜像分层原理》学习理解)。
  • 所以CMD和ENTRYPOINT 指令有点相似,都是在创建容器时运行。需要注意的是:一旦Dockerfile中包含ENTRYPOINT指令,CMD指令就作为ENTRYPOINT指定的脚本的参数存在。参考下文格式语法。

CMD包含三种格式:

  • 第一种为ENTRYPOINT指定的脚本传参,上文中的ENTRYPOINT脚本最后一行的exec "$@"就是在执行CMD传递的命令及参数。来完成nginx服务的启动。这种用法是各官方Dockerfile常用的做法(如:nginx、redis),就是在ENTRYPOINT指定的脚本中做一些配置准备工作,然后在ENTRYPOINT脚本的最后一行通过exec "$@"调用CMD命令进行容器服务的启动。
CMD ["nginx", "-g", "daemon off;"]
  • 1
  • 第二种 执行一个命令或shell脚本,可以传参,注意是双引号。与第一种格式语法是一样的,只是没有ENTRYPOINT指定脚本,所以不作为ENTRYPOINT指定脚本的参数存在。
CMD ["executable","param1","param2"]
  • 1
  • 第三种为普通的执行shell脚本的语法,如执行echo "This is a test." | wc -cshell命令行。笔者说:在Dockerfile中这种方法不要用,没必要知道为什么
CMD echo "This is a test." | wc -c
  • 1
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发