• Docker学习-Dockerfile概述与用法


    前言

    学习本文需要一些了解Docker的概念以及一些名词。
    个人网站:https://linzyblog.netlify.app/

    一、Docker概述

    1、Docker简介

    Docker 镜像是通过读取Dockerfile来构建镜像文件的。Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有命令来组装镜像,每条指令都是独立运行的,并会创建一个新的镜像层 。使用docker build 命令用户用户可以创建一个自动构建,该构建可以连续执行几个命令行指令。

    2、为什么要用Dockerfile?

    为什么要用Dockerfile?这个问题的本身其实是说为什么我们要自定义镜像,明明Docker Hub上有这么多镜像可以用,我们还要自己费心思做镜像。

    在这里插入图片描述

    在这里插入图片描述

    主要原因:Docker Hub上许多官方镜像只是基础包,很多功能都没有,需要我们自己对官方镜像做扩展,以打包成我们生产应用的镜像。
    参考我的第一篇文章Docker入门篇:https://blog.csdn.net/weixin_46618592/article/details/126317527?spm=1001.2014.3001.5501

    二、docker build工作原理

    1、镜像构建过程

    docker build命令从 Dockerfile 和 context 构建一个镜像。构建的 context 是位于指定位置PATH或URL的一组文件。PATH是本地文件系统上的一个目录。URL是Git存储库位置。

    docker build [OPTIONS] PATH | URL | -
    
    • 1

    完整的镜像架构图:
    在这里插入图片描述
    构建context是递归处理的。每条指令都是独立运行的,并会创建一个新的镜像层。

    例子中docker build后面使用(.)表示当前目录,作为指定context的路径:

    $ docker build .
    
    Send build context to Docker daemon 6.51MB
    ...
    
    • 1
    • 2
    • 3
    • 4

    构建由 Docker 守护程序运行,而不是由 CLI 运行。构建过程所做的第一件事是将整个 context(递归)发送到守护进程。

    2、context(上下文)

    Docker使用客户端-服务器架构。Docker客户端 与 Docker守护进程 通信,守护进程 负责构建、运行和分发Docker容器。Docker客户端 和 守护进程 可以运行在同一个系统上,或者将 Docker客户端 连接到远程的Docker守护进程。Docker客户端 和 守护进程 通过UNIX套接字或网络接口使用REST API进行通信。另一个 Docker客户端 是Docker Compose,它允许使用由一组容器组成的应用程序。

    Docker客户端(Docker) 是许多Docker用户与Docker交互的主要方式。使用docker 命令时,则是通过docker API 与 Docker守护进程进行交互,从而完成各种功能,Docker客户端 可以与多个 守护进程 通信。因此,虽然表面上我们是在本机执行各种 docker 功能,但实际上,客户端会将这些命令发送到 Docker守护进程 执行它们。也因为这种 C/S 设计,让我们操作远程服务器的 Docker守护进程 变得轻而易举。

    当我们进行镜像构建的时候,并非所有定制都会通过 RUN 指令完成,经常会需要将一些本地文件复制进镜像,比如通过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker守护进程构建的。

    那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?

    这就引入了context(上下文)的概念。当构建的时候,用户会指定构建镜像context(上下文)的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker守护进程。这样Docker守护进程收到这个context(上下文)包后,展开就会获得构建镜像所需的一切文件。

    在这里插入图片描述
    如果要在构建上下文中使用文件,Dockerfile引用指令中指定的文件,例如COPY指令。要提高构建的性能,可以通过在context目录中添加.dockerignore文件来排除文件和目录。

    传统上,Dockerfile位于上下文的根目录中。实际上,Dockerfile 的文件名并不要求必须为 Dockerfile,而且并不要求必须位于上下文目录中,在docker build中使用-f标志来指向文件系统中的任何位置的Dockerfile。

    一般大家习惯性的会使用默认的文件名 Dockerfile,以及会将其置于镜像构建上下文目录中。

    注意:不要将根目录/用作PATH构建上下文,因为它会导致构建将硬盘驱动器的全部内容传输到 Docker 守护程序。

    三、Dockerfile指令

    1、约定

    1. 指令必须大写,以便更容易地将它们与参数区分开来。
    2. Dockerfile必须以FROM指令开始
    3. 以# 开头视为注释。

    2、FROM

    • 作用:指定基础镜像,Dockerfile必须以FROM指令开始。
    • 格式:
    格式:
    (1)	FROM [--platform=<platform>] <image> [AS <name>]
    (2)	FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
    (3)	FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
    
    解释:
    	[--platform=< platform >]:如果引用多平台镜像,可选 --platform 标志可用于指定镜像的平台。
    	[AS <name>]:通过向FROM指令添加AS name,可以为新的构建阶段指定一个名称。
    
    注:
       tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
       
    示例:
    	FROM centos
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 说明:

    Docker Hub中的大部分镜像都是从基础镜像 FROM scratch构建的,在基础镜像之上构建软件和配置。FROM指令初始化一个新的构建阶段,并为后续指令设置基本镜像。因此,一个有效的Dockerfile必须以一个FROM指令开始。

    镜像可以是任何有效的镜像—从Docker Hub提取镜像尤其容易。

    3、RUN

    • 作用:构建镜像时需要执行的命令
    • 格式:
    格式:
    shell形式(命令运行在shell中,Linux默认为/bin/sh -c, Windows默认为cmd /S /C)
    (1)	RUN <command>
    	
    exec形式(exec形式可以避免shell字符串混杂,并使用不包含指定的shell可执行文件的基本镜像运行命令)
    (2)	RUN ["executable", "param1", "param2"]
    
    注:
    	RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。
    
    示例:
    	RUN ["executable", "param1", "param2"]
        RUN apk update
        RUN ["/etc/execfile", "arg1", "arg1"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 说明:

    镜像构建的时候需要运行的命令,有两种命令执行方式。RUN指令将在当前镜像之上的新层中执行任何命令并提交结果。生成的提交镜像将用于Dockerfile。

    注意:在下一次构建期间,RUN指令的缓存不会自动失效。像RUN apt-get distupgrade -y这样的指令的缓存将在下一次构建期间被重用。RUN指令的缓存可以通过使用--no-cache标志来失效,例如docker build——no-cache

    4、CMD

    • 作用:在构建镜像之后调用,容器启动时调用命令
    • 格式:
    格式:
    (1)	CMD ["executable""param1""param2"] (exec形式,这是首选形式)
    (2)	CMD ["param1""param2"](作为ENTRYPOINT的默认参数)
    (3)	CMD command param1 param2(shell形式)
    	
    注:
    	Dockerfile中只能有一个CMD指令。如果列出多个CMD,则只有最后一个CMD生效。
    
    示例:
    	FROM ubuntu
    	CMD echo "This is a test." | wc -
    
    	FROM ubuntu
    	CMD ["/usr/bin/wc","--help"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 说明:

    CMD的主要目的是为容器提供默认的执行命令。包括可执行文件,也可以省略可执行文件,在这种情况下,您必须同时指定一个ENTRYPOINT指令。

    注意:
    CMD不同于RUNCMD在构建时不执行任何操作,CMD是容器启动时执行的指令,RUN是镜像构建时执行的指令。

    5、ENTRYPOINT

    • 作用:在构建镜像之后调用,容器启动时调用命令
    • 格式:
    格式:
    (1)	ENTRYPOINT ["executable", "param1", "param2"](exec形式,这是首选形式)
    (2)	ENTRYPOINT command param1 param2(shell形式)
    
    注:
    	指定 ENTRYPOINT 指令为 exec 模式时,命令行上指定的参数会作为参数添加到 ENTRYPOINT 指定命令的参数列表中。
    
    示例:
    	FROM ubuntu
    	ENTRYPOINT ["top", "-b"]
    	CMD ["-c"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 说明:

    ENTRYOINT与CMD作用一样,都是在容器运行时执行命令,两者都是重要的指令。

    注意:
    ENTRYPOINTCMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给CMD。
    Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
    通常情况下, ENTRYPOINT 与CMD一起使用,ENTRYPOINT 写默认命令,当需要参数时候 使用CMD传参。

    6、CMD vs ENTRYPOINT

    Docker官方文档
    Dockerfile 的 CMD 与 ENTRYPOINT 傻傻分不清楚
    ENTRYPOINT vs CMD: Back to Basics

    7、LABEL

    • 作用:LABEL指令向镜像添加元数据。
    • 格式:
    格式:
    	LABEL <key>=<value> <key>=<value> <key>=<value> ...
    
    注:
    	一个镜像可以有多个标签,可以在一行中指定多个标签。
    
    示例:
    一条指令中指定多个标签:
    (1)	LABEL multi.label1="value1" multi.label2="value2" other="value3"
    (2)	LABEL multi.label1="value1" \
          multi.label2="value2" \
          other="value3"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 说明:

    LABEL指令向镜像添加元数据。LABEL是一个键-值对。要在LABEL值中包含空格,请在命令行解析中那样使用引号和反斜杠。

    注意:
    基础或父镜像(FROM行中的镜像)中包含的标签由你的镜像继承。如果标签已存在但具有不同的值,则最近应用的值将覆盖任何先前设置的值

    8、MAINTAINER (已弃用)

    • 作用:MAINTAINER指令设置生成的镜像的作者信息。
    • 格式:
    格式:
    	MAINTAINER <name>
    	
    示例:
        MAINTAINER linzy
        MAINTAINER xxx@qq.com
        MAINTAINER linzy <xxx@qq.com>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    9、EXPOSE

    • 作用:EXPOSE指令告诉Docker容器在运行时监听指定的网口
    • 格式:
    格式:
    	EXPOSE <port> [<port>/<protocol>...]
    
    注:
    	EXPOSE指令实际上并不发布端口。它在构建镜像的人和运行容器的人之间充当一种文档,说明哪些端口将被发布。
    	要在运行容器时真正发布端口,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。
    	
    示例:
    	EXPOSE 8080
    	
    同时在 TCP 和 UDP 上公开:
    	EXPOSE 80/tcp
    	EXPOSE 80/udp	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 说明:

    EXPOSE指令告诉Docker容器在运行时监听指定的网口。可以指定端口侦听的协议类型是TCP还是UDP,如果不指定协议类型,默认为TCP

    注意:
    如果没有发布端口,后期也可以通过-p 8080:80方式映射端口,但是不能通过-P形式映射

    10、ENV

    • 作用:ENV指令将设置环境变量。
    • 格式:
    格式:
    	ENV <key> <value>  
    	#之后的所有内容均会被视为其的组成部分,因此,一次只能设置一个变量。
        ENV <key>=<value> ...  
        #可以设置多个变量,每个变量为一个"="的键值对。
    
    注:
    	如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行。
    示例:
    	ENV MY_NAME="linzy"
    	ENV MY_DOG=Wang\ Cai
    	ENV MY_CAT=Mei\ Lao\ Ban
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 说明:

    ENV当容器从生成的图像运行时,使用ENV设置的环境变量将一直存在。你可以使用 docker inspect查看这些值,并使用 docker run --env < key >=< value > 更改它们。

    注意:
    ENV指令还允许使用另一种语法ENV < key > < value >,省略=,例如:
    ENV MY_VAR my-value

    11、ADD

    • 作用:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget。
    • 格式:
    格式:
    (1)	ADD [--chown=<user>:<group>] <src>... <dest>
    (2)	ADD [--chown=<user>:<group>] ["",... ""]
    
    注:
    	该--chown功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,不适用于 Windows 容器。由于用户和组所有权概念不能在 Linux 和 Windows 之间转换,因此使用/etc/passwd并/etc/group用于将用户和组名转换为 ID 会限制此功能仅适用于基于 Linux 操作系统的容器。
    
    示例:
    	ADD hom* /mydir/ # 添加所有以“hom”开头的文件
    	ADD hom?.txt /mydir/ # ?替换为任何单个字符,例如“home.txt”。
    	ADD test.txt relativeDir/ # 使用相对路径,将“test.txt”添加到/relativeDir/
    	ADD test.txt /absoluteDir/ # 使用绝对路径,将“test.txt”添加到/absoluteDir/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 说明:

    ADD指令从路径复制新文件、目录或远程文件 URL,并将它们添加到镜像的文件系统中可以指定多个资源,但如果它们是文件或目录,则它们的路径被解释为相对于构建context(上下文)的源。

    ADD遵守以下规则

    1. 路径必须在构建的上下文中;你不能ADD ../something /something,因为docker build的第一步是将上下文目录(和子目录)发送到 docker 守护进程。
    2. 如果是一个URL,且不是以斜杠结尾,则从该URL下载文件并复制到
    3. 如果是一个URL,且是以斜杠结尾,则从 URL 推断文件名并将文件下载到 /.。例如:ADD http://example.com/foobar /将创建文件/foobar。 URL 必须有一个重要的路径,以便在这种情况下可以找到适当的文件名(http://example.com 将不起作用)。
    4. 如果是目录,则复制目录的全部内容,包括文件系统元数据。
    5. 如果是可识别压缩格式(identity、gzip、bzip2 或 xz)的本地tar 存档,则将其解压缩为目录。来自远程URL 的资源不会被解压缩。当一个目录被复制或解包时,它的行为与 相同tar -x
      • 文件是否被识别为可识别的压缩格式完全取决于文件的内容,而不是文件的名称。例如,如果一个空文件恰好以此结尾,.tar.gz则不会被识别为压缩文件,也不会生成任何类型的解压缩错误消息,而是将文件简单地复制到目标位置。
    6. 如果是任何其他类型的文件,它将与它的元数据一起被单独复制。在这种情况下,如果以斜杠结尾/,它将被视为一个目录,其内容将写入/base()
    7. 直接指定了多个资源,或者使用了通配符,则必须是目录,并且必须以斜杠结尾/
    8. 如果不以斜杠结尾,它将被认为是一个普通文件,其的内容将写入
    9. 如果不存在,它会连同其路径中所有缺失的目录一起创建。

    12、COPY

    • 作用:将本地文件添加到容器中,但是是不会自动解压文件,也不能访问网络资源。
    • 格式:
    格式:
    (1)	COPY [--chown=<user>:<group>] <src>... <dest>
    (2)	COPY [--chown=<user>:<group>] ["",... ""]
    
    注:
    	该--chown功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,不适用于 Windows 容器。
    
    示例:
    	COPY hom* /mydir/ # 添加所有以“hom”开头的文件
    	COPY hom?.txt /mydir/ # ?替换为任何单个字符,例如“home.txt”
    	COPY test.txt relativeDir/ # 使用相对路径,并将“test.txt”添加到/relativeDir/
    	COPY test.txt /absoluteDir/ # 使用绝对路径,并将“test.txt”添加到/absoluteDir/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 说明:

    COPY指令从路径复制新文件或目录 并将它们添加到容器的文件系统中可以指定多个资源,但文件和目录的路径将被解释为相对于构建上下文的源。

    COPY遵守以下规则

    1. 路径必须在构建的上下文中;你不能ADD ../something /something,因为docker build的第一步是将上下文目录(和子目录)发送到 docker 守护进程。
    2. 如果是目录,则复制目录的全部内容,包括文件系统元数据。
    3. 如果是任何其他类型的文件,它将与它的元数据一起被单独复制。在这种情况下,如果以斜杠结尾/,它将被视为一个目录,其内容将写入/base()
    4. 直接指定了多个资源,或者使用了通配符,则必须是目录,并且必须以斜杠结尾/
    5. 如果不以斜杠结尾,它将被认为是一个普通文件,其的内容将写入
    6. 如果不存在,它会连同其路径中所有缺失的目录一起创建。

    13、VOLUME

    • 作用:用于指定持久化目录(指定此目录可以被挂载出去)
    • 格式:
    格式:
    	VOLUME ["/data"]
    
    注:
    	卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
    	1.卷可以容器间共享和重用
    	2.容器并不一定要和其它容器共享卷
    	3.修改卷后会立即生效
    	4.对卷的修改不会对镜像产生影响
    	5.卷会一直存在,直到没有容器在使用它
    	6.卷可以在 Linux 和 Windows 容器上运行。
    	
    示例:
    	VOLUME ["/data"]
        VOLUME ["/var/mysql", "/var/log/mysql", "/etc/mysql"]
        
    	FROM ubuntu
    	RUN mkdir /myvol
    	RUN echo "hello world" > /myvol/greeting
    	VOLUME /myvol
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 说明:

    VOLUME指令创建具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载卷。
    参考《Docker卷(volumes)》

    关于指定卷的注意事项:

    1. 基于 Windows 的容器上的卷:使用基于 Windows 的容器时,容器内卷的目标必须是以下之一:
      • 不存在或为空的目录
      • C盘以外的驱动器
    2. 从 Dockerfile 中更改卷:如果任何构建步骤在声明卷后更改了卷中的数据,则这些更改将被丢弃。
    3. JSON 格式:列表被解析为 JSON 数组。必须用双引号 ( ") 而不是单引号 ( ') 将单词括起来。
    4. 主机目录在容器运行时声明:主机目录(挂载点)本质上是依赖于主机的。这是为了保持镜像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。由于这个原因,你不能从Dockerfile内挂载主机目录。VOLUME指令不支持指定host-dir参数。在创建或运行容器时,必须指定挂载点

    14、USER

    • 作用:设置用户名(或 UID)和可选的用户组(或 GID)。
    • 格式:
    格式:
    (1)	USER <user>[:<group>]
    (2)	USER <UID>[:<GID>]
    
    注:
    	使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。
      镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
    
    示例:
    	USER linzy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 说明:

    指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。

    注意:
    在 Windows 上,如果用户不是内置帐户,则必须先创建用户。这可以通过net user作为 Dockerfile 的一部分调用的命令来完成。

    FROM microsoft/windowsservercore
    # Create Windows user in the container
    RUN net user /add linzy
    # Set it for subsequent commands
    USER linzy
    
    • 1
    • 2
    • 3
    • 4
    • 5

    15、WORKDIR

    • 作用:设置工作目录。
    • 格式:
    格式:
    	WORKDIR /path/to/workdir
    
    注:
    	通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。
    	在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
    
    示例:
    	WORKDIR /a  (这时工作目录为/a)
        WORKDIR b  (这时工作目录为/a/b)
        WORKDIR c  (这时工作目录为/a/b/c)
    	RUN pwd # 最终pwd命令的输出Dockerfile将是/a/b/c.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 说明:

    WORKDIR设置工作目录,类似于cd命令。设置工作目录后,Dockerfile中其后的命令RUNCMDENTRYPOINTADDCOPY等命令都会在该目录下执行。如果不存在,即使它没有在任何后续指令中使用,它也会被创建。

    注意:
    Dockerfile里WORKDIR指令使用之前设置的环境变量 ENV,例如:

    ENV DIRPATH=/path
    WORKDIR $DIRPATH/$DIRNAME
    RUN pwd
    
    • 1
    • 2
    • 3

    最终pwd命令的输出Dockerfile将是 /path/$DIRNAME
    如果未指定,默认工作目录为/。在实践中,如果你不是从头开始构建Dockerfile, WORKDIR可能由你正在使用的基础镜像设置。
    因此,为了避免在未知目录中进行意外操作,最好是显式设置WORKDIR

    16、ARG

    • 作用:用于指定传递给构建运行时的变量(给Dockerfile传参),相当于构建镜像时可以在外部为里面传参
    • 格式:
    格式:
    	ARG [=]
    
    注:
    	--build-arg = 将变量传递给构建器。如果用户指定了未在Dockerfile中定义的构建参数,那么构建将输出一个警告。
    
    示例:
    	FROM busybox
    	ARG user1
    	ARG buildno
    	# ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 说明:

    ARG指令定义了一个变量,用户可以在构建时通过使用 标志的docker build命令将其传递给构建器。

    注意:
    不建议使用构建时变量来传递 github 密钥、用户凭据等机密信息。使用该docker history命令的映像的任何用户都可以看到构建时变量值。

    1)默认值

    ARG指令可以设置默认值:

    	FROM busybox
    	ARG user1=someuser
    	ARG buildno=1
    	# ...
    
    • 1
    • 2
    • 3
    • 4

    如果ARG指令具有默认值并且在构建时没有传递任何值,则构建器将使用默认值。

    2)使用 ARG 变量

    可以使用ARGENV指令指定RUN指令可用的变量。使用ENV指令定义的环境变量总是覆盖同名的ARG指令。

    带有ENVARG指令的 Dockerfile 例子:

    FROM ubuntu
    ARG CONT_IMG_VER
    ENV CONT_IMG_VER=v1.0.0
    RUN echo $CONT_IMG_VER
    
    • 1
    • 2
    • 3
    • 4

    镜像是用这个命令构建的:

    docker build --build-arg CONT_IMG_VER=v2.0.1 .
    
    • 1

    RUN指令使用v1.0.0而不是ARG用户传递的设置。

    17、ONBUILD

    • 作用:向镜像添加了一条触发指令。
    • 格式:
    格式:
    	ONBUILD 
    
    注:
    	任何构建指令都可以注册为触发器。
    
    示例:
    	ONBUILD ADD . /app/src
    	ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 说明:

    ONBUILD指令向镜像添加了一条触发指令。

    NNBUID后面跟指令,当该镜像被用作另一个构建的基础镜像时,触发器将在其构建的上下文中执行。就好像它是FROM 在指令之后立即插入的一样Dockerfile。

    如果你正在构建一个镜像,该镜像将用作构建其他镜像的基础,例如可以特定于用户的配置定制的应用程序构建环境或守护进程。

    注意:
    ONBUILD指令可能不会触发FROMMAINTAINER指令。

    18、Dockerfile常用指令

    在这里插入图片描述

    指令描述
    FROM构建新镜像使用的基础镜像
    MAINTAINER(已弃用)构建镜像的作者或邮件地址
    RUN构建镜像时执行命令
    COPY拷贝文件或目录到镜像中
    ENV设置环境变量
    USER为RUN、CMD和ENTRYPOINT等执行命令指定运行用户
    EXPOSE声明容器运行的服务端口
    WORKDIR为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录
    ENTRYPOINT运行容器时执行,如果由多个ENTRYPOINT指令,最后一个生效,可以追加命令
    CMD运行容器时执行,如果由多个CMD 指令,最后一个生效,可被替代
    LABEL设置镜像的标签
    VOLUME设置容器的挂载卷
    ARG指令定义了一个变量
    ONBUILD向镜像添加了一条触发指令

    四、构建自己的镜像

    1、构建镜像步骤

    构建镜像步骤:

    1. 编写一个Dockerfile 文件
    2. 通过 docker build 命令构建成一个镜像
    3. docker run 命令运行镜像
    4. docker push 命令发布镜像到Docker Hub

    注意:

    • 如果有多个RUN,自上而下依次运行,每次运行都会形成新的层,建议&& 放入一行运行
    • 如果有多个CMD,只有最后一个运行
    • 如果有多个ENTRYPOINT ,只有最后一个运行
    • 如果CMDENTRYPOINT共存,只有ENTRYPOINT 运行,且最后的CMD会当做ENTRYPOINT 的参数

    2、编写Dockerfile文件

    # 基础镜像
    FROM centos
    
    #MAINTAINER 维护者信息
    MAINTAINER linzy<2350621012@qq.com>
    
    #ENV 设置环境变量
    ENV MYPATH /usr/local
    
    #WORKDIR 相当于cd
    WORKDIR $MYPATH
    
    #RUN 执行命令
    RUN yum -y install vim 
    RUM yum -y install net-tools
    
    #EXPOSE 映射端口
    EXPOSE 80
    
    #CMD 运行命令
    CMD echo $MYPATH
    CMD echo "-----end----"
    CMD /bin/bash
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    逐行解释该Dockerfile文件的指令:

    1. FROM centos :该image文件继承官方的centos,他会先在你本地寻找centos镜像
    2. ENV MYPATH /usr/local:设置环境变量MYPATH
    3. WORKDIR $MYPATH:直接使用上面设置的环境变量,指定/usr/local为工作目录
    4. RUN yum -y install vim && RUM yum -y install net-tools:在/usr/local目录下,运行yum -y install vim和yum -y install net-tools命令安装工具,注意安装后的所有依赖和工具都会打包到image文件中
    5. EXPOSE 80·:将容器80端口暴露出来,允许外部连接这个端口
    6. CMD:指定容器启动的时候运行命令
      • CMD echo $MYPATH:输出MYPATH环境变量
      • CMD echo “-----end----”:输出-----end----
      • CMD /bin/bash:进入/bin/bash命令行

    3、执行build命令构建镜像

    执行build命令生成image文件。

    docker build -t mycentos:1.0 .
    
    • 1

    在这里插入图片描述
    如果出现Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist 错误,不要惊慌!

    报错信息的意思是:从仓库 ‘appstream’ 下载元数据失败:由于镜像列表中没有 URL,不能准备内部镜像列表。

    错误原因:

    1. 可能的情况便是网络连接问题。检查是否可以连接外部网络,可以使用 ping baidu.com 查看是否有丢包情况。如果丢包,则进一步检查网络连接是否正常;如果没有丢包,继续阅读下文
    2. 第二种情况,便是 CentOS 已经停止维护的问题。2020 年 12 月 8 号,CentOS 官方宣布了停止维护 CentOS Linux 的计划,并推出了 CentOS Stream 项目,CentOS Linux 8 作为 RHEL 8 的复刻版本,生命周期缩短,于 2021 年 12 月 31 日停止更新并停止维护(EOL)。

    解决Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist错误

    因为我们的Dockerfile的基础镜像是可以基于本地的镜像,所以我们只需要修改本地的centos镜像,再用我们的commit指令生成新的镜像用来当我们Dockerfile的基础镜像
    commit指令参考文章《Docker镜像概述和分层原理

    1. 运行centos镜像,并进入交互界面
    docker run -it -P centos
    
    • 1

    在这里插入图片描述

    1. 进入到 yum 的 repos 目录
    cd /etc/yum.repos.d/
    
    • 1
    1. 修改 centos 文件内容
    sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
    sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
    
    • 1
    • 2
    1. 生成缓存更新(第一次更新,速度稍微有点慢,耐心等待两分钟左右)
    yum makecache
    
    • 1

    在这里插入图片描述

    1. 运行 yum update (更新的东西很多,大约五分钟)
    yum update -y
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    出现Complete的就是成功了

    1. 使用docker commit 将容器保存为新的镜像
    docker commit c638ed426e64  mycentos:0.1
    
    • 1

    在这里插入图片描述

    1. 修改一下我们的Dockerfile里的FROM基础镜像这块
    # 基础镜像 修改为mycentos:0.1
    FROM mycentos:0.1
    
    #MAINTAINER 维护者信息
    MAINTAINER linzy<2350621012@qq.com>
    
    #ENV 设置环境变量
    ENV MYPATH /usr/local
    
    #WORKDIR 相当于cd
    WORKDIR $MYPATH
    
    #RUN 执行命令
    RUN yum -y install vim 
    RUN yum -y install net-tools
    
    #EXPOSE 映射端口
    EXPOSE 80
    
    #CMD 运行命令
    CMD echo $MYPATH
    CMD echo "-----end----"
    CMD /bin/bash
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 重新执行build命令
    docker build -t mycentos:1.0 .
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    构建centos镜像成功!

    4、测试运行

    1)使用 docker history 镜像id 查看镜像构建过程

    E:\dockerfile>docker history  2b92daa4f916
    IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
    2b92daa4f916   29 minutes ago   CMD ["/bin/sh" "-c" "/bin/bash"]                0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   CMD ["/bin/sh" "-c" "echo \"-----end----\""]    0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   CMD ["/bin/sh" "-c" "echo $MYPATH"]             0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   EXPOSE map[80/tcp:{}]                           0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   RUN /bin/sh -c yum -y install net-tools # bu…   28.7MB    buildkit.dockerfile.v0
    <missing>      29 minutes ago   RUN /bin/sh -c yum -y install vim # buildkit    67.2MB    buildkit.dockerfile.v0
    <missing>      29 minutes ago   WORKDIR /usr/local                              0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   ENV MYPATH=/usr/local                           0B        buildkit.dockerfile.v0
    <missing>      29 minutes ago   MAINTAINER linzy<2350621012@qq.com>             0B        buildkit.dockerfile.v0
    <missing>      32 minutes ago   /bin/bash                                       302MB
    <missing>      11 months ago    /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      11 months ago    /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
    <missing>      11 months ago    /bin/sh -c #(nop) ADD file:805cb5e15fb6e0bb0…   231MB
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2)运行容器,看看是否能够执行ifconfigvim命令

    E:\dockerfile>docker run -it mycentos:1.0
    [root@392bed5a0bcd local]# pwd
    /usr/local
    [root@392bed5a0bcd local]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
            ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
            RX packets 11  bytes 906 (906.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    [root@392bed5a0bcd local]# vim
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    MATLAB语言 实验一 MATLAB工作环境熟悉及简单命令的执行
    负数取余问题
    GBase 8s gcadmin之rmnodes命令解析
    HDLbits: Dualedge
    Go语言学习(二) 函数
    LeetCode只出现一次的数字
    Java电子招投标采购系统源码-适合于招标代理、政府采购、企业采购、等业务的企业
    【学习笔记】AGC018
    ASPICE标准快速掌握「5.2. ASPICE与V模型」
    PCIE1—快速实现PCIE接口上下位机通信(一)
  • 原文地址:https://blog.csdn.net/weixin_46618592/article/details/126680623