Docker(六)进阶:Dockerfile概述与用法(两万字入门到精通)

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

前言


学习本文需要一些了解Docker的概念以及一些名词。

个人网站:https://linzyblog.netlify.app/

一、Docker概述


1、Docker简介


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

2、为什么要用Dockerfile?


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

fd10655f029e484ba3c71e59291b2231.png

7c4f5ae57a54477bb12695813e9f5b0b.png

主要原因: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 | -


完整的镜像架构图:

ba384977505948fcaf7b84fb806dcf01.png


构建context是递归处理的。每条指令都是独立运行的,并会创建一个新的镜像层。

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

$ docker build .
Send build context to Docker daemon 6.51MB
...


构建由 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(上下文)包后,展开就会获得构建镜像所需的一切文件。


9e9ab8b7fcdf47e6ae32bc184f24bdc2.png


如果要在构建上下文中使用文件,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


  • 说明:


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"]


  • 说明:


镜像构建的时候需要运行的命令,有两种命令执行方式。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"]


  • 说明:


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


注意:

CMD不同于RUN,CMD在构建时不执行任何操作,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"]


  • 说明:


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


注意:

ENTRYPOINT与CMD非常类似,不同的是通过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"


  • 说明:


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


注意:

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


8、MAINTAINER (已弃用)


  • 作用:MAINTAINER指令设置生成的镜像的作者信息。
  • 格式:


格式:
  MAINTAINER <name>
示例:
    MAINTAINER linzy
    MAINTAINER xxx@qq.com
    MAINTAINER linzy <xxx@qq.com>


9、EXPOSE


  • 作用:EXPOSE指令告诉Docker容器在运行时监听指定的网口。
  • 格式:


格式:
  EXPOSE <port> [<port>/<protocol>...]
注:
  EXPOSE指令实际上并不发布端口。它在构建镜像的人和运行容器的人之间充当一种文档,说明哪些端口将被发布。
  要在运行容器时真正发布端口,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。
示例:
  EXPOSE 8080
同时在 TCP 和 UDP 上公开:
  EXPOSE 80/tcp
  EXPOSE 80/udp 


  • 说明:


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


注意:

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


10、ENV


  • 作用:ENV指令将设置环境变量。
  • 格式:


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


  • 说明:


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>] ["<src>",... "<dest>"]
注:
  该--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”添加到<WORKDIR>/relativeDir/
  ADD test.txt /absoluteDir/ # 使用绝对路径,将“test.txt”添加到/absoluteDir/


  • 说明:


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


ADD遵守以下规则:


1.<src>路径必须在构建的上下文中;你不能ADD ../something /something,因为docker build的第一步是将上下文目录(和子目录)发送到 docker 守护进程。


2.如果<src>是一个URL,且<dest>不是以斜杠结尾,则从该URL下载文件并复制到<dest>。


3.如果<src>是一个URL,且<dest>是以斜杠结尾,则从 URL 推断文件名并将文件下载到 <dest>/<filename>.。例如:ADD http://example.com/foobar /将创建文件/foobar。 URL 必须有一个重要的路径,以便在这种情况下可以找到适当的文件名(http://example.com 将不起作用)。


4.如果<src>是目录,则复制目录的全部内容,包括文件系统元数据。


5.如果<src>是可识别压缩格式(identity、gzip、bzip2 或 xz)的本地tar 存档,则将其解压缩为目录。来自远程URL 的资源不会被解压缩。当一个目录被复制或解包时,它的行为与 相同tar -x。

。文件是否被识别为可识别的压缩格式完全取决于文件的内容,而不是文件的名称。例如,如果一个空文件恰好以此结尾,.tar.gz则不会被识别为压缩文件,也不会生成任何类型的解压缩错误消息,而是将文件简单地复制到目标位置。


6.如果<src>是任何其他类型的文件,它将与它的元数据一起被单独复制。在这种情况下,如果<dest>以斜杠结尾/,它将被视为一个目录,其内容<src>将写入<dest>/base(<src>)。


7.<src>直接指定了多个资源,或者使用了通配符,则<dest>必须是目录,并且必须以斜杠结尾/。


8.如果<dest>不以斜杠结尾,它将被认为是一个普通文件,其<src>的内容将写入<dest>。


9.如果<dest>不存在,它会连同其路径中所有缺失的目录一起创建。


12、COPY


  • 作用:将本地文件添加到容器中,但是是不会自动解压文件,也不能访问网络资源。
  • 格式:


格式:
(1) COPY [--chown=<user>:<group>] <src>... <dest>
(2) COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
注:
  该--chown功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,不适用于 Windows 容器。
示例:
  COPY hom* /mydir/ # 添加所有以“hom”开头的文件
  COPY hom?.txt /mydir/ # ?替换为任何单个字符,例如“home.txt”
  COPY test.txt relativeDir/ # 使用相对路径,并将“test.txt”添加到<WORKDIR>/relativeDir/
  COPY test.txt /absoluteDir/ # 使用绝对路径,并将“test.txt”添加到/absoluteDir/


  • 说明:


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


COPY遵守以下规则:


1.<src>路径必须在构建的上下文中;你不能ADD ../something /something,因为docker build的第一步是将上下文目录(和子目录)发送到 docker 守护进程。


2.如果<src>是目录,则复制目录的全部内容,包括文件系统元数据。


3.如果<src>是任何其他类型的文件,它将与它的元数据一起被单独复制。在这种情况下,如果<dest>以斜杠结尾/,它将被视为一个目录,其内容<src>将写入<dest>/base(<src>)。


4.<src>直接指定了多个资源,或者使用了通配符,则<dest>必须是目录,并且必须以斜杠结尾/。


5.如果<dest>不以斜杠结尾,它将被认为是一个普通文件,其<src>的内容将写入<dest>。


6.如果<dest>不存在,它会连同其路径中所有缺失的目录一起创建。


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


  • 说明:


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


  • 说明:


指定运行容器时的用户名或 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


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.


  • 说明:


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


注意:

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


ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd


最终pwd命令的输出Dockerfile将是 /path/$DIRNAME。


如果未指定,默认工作目录为/。在实践中,如果你不是从头开始构建Dockerfile, WORKDIR可能由你正在使用的基础镜像设置。


因此,为了避免在未知目录中进行意外操作,最好是显式设置WORKDIR。


16、ARG


  • 作用:用于指定传递给构建运行时的变量(给Dockerfile传参),相当于构建镜像时可以在外部为里面传参
  • 格式:


格式:
  ARG <name>[=<default value>]
注:
  --build-arg <varname>=<value> 将变量传递给构建器。如果用户指定了未在Dockerfile中定义的构建参数,那么构建将输出一个警告。
示例:
  FROM busybox
  ARG user1
  ARG buildno
  # ...


  • 说明:


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


注意:

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


1)默认值


ARG指令可以设置默认值:


  FROM busybox
  ARG user1=someuser
  ARG buildno=1
  # ...


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


2)使用 ARG 变量


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


带有ENV 和 ARG指令的 Dockerfile 例子:


FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER


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


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


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


17、ONBUILD


  • 作用:向镜像添加了一条触发指令。
  • 格式:


格式:
  ONBUILD <INSTRUCTION>
注:
  任何构建指令都可以注册为触发器。
示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src


  • 说明:


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


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


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


注意:

ONBUILD指令可能不会触发FROM或MAINTAINER指令。


18、Dockerfile常用指令


3ed98ab805f941a0a643689b5f72f145.png


指令 描述
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 ,只有最后一个运行
  • 如果CMD和ENTRYPOINT共存,只有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


逐行解释该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 .

8095fbb7cb0d4b25be734733f0bd880a.png


如果出现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

f8e5220bf4994d9b9b4b5889b25f7ac4.png


2.进入到 yum 的 repos 目录


cd /etc/yum.repos.d/


3.修改 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-*


4.生成缓存更新(第一次更新,速度稍微有点慢,耐心等待两分钟左右)


yum makecache

63f1a054d2314e3885e8915102b7b470.png


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


yum update -y

1a80a011dfce4b76b59fabfb99460c08.png

a811cfa122f14f1f9b432cb3b473ca94.png


出现Complete的就是成功了


6.使用docker commit 将容器保存为新的镜像


docker commit c638ed426e64  mycentos:0.1

362a10e35f9a4d629a3523136d1380ce.png


7.修改一下我们的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


8.重新执行build命令


docker build -t mycentos:1.0 .

217f2be097074645a65625d51e5e3a31.png


构建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


2)运行容器,看看是否能够执行ifconfig 及vim命令


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月前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
95 2
|
3天前
|
Ubuntu 应用服务中间件 nginx
docker入门-快速学会docker
本文介绍了Docker的基本概念,包括镜像、容器、tar文件、Dockerfile和仓库,并通过实际操作演示了如何使用Docker。从拉取Nginx镜像、运行容器、修改容器内容、保存容器为新镜像,到使用Dockerfile构建自定义镜像,最后讲解了如何保存和恢复镜像。文中还推荐了一个在线实践平台Play with Docker,方便读者快速上手Docker。
27 4
docker入门-快速学会docker
|
1月前
|
Java 应用服务中间件 Linux
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
本文主要讲解了Docker的安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库以及Docker容器虚拟化与传统虚拟机比较。
540 11
【Docker容器化技术】docker安装与部署、常用命令、容器数据卷、应用部署实战、Dockerfile、服务编排docker-compose、私有仓库
|
20天前
|
数据库 Docker 容器
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。
Docker在现代软件开发中扮演着重要角色,通过Dockerfile自动化构建Docker镜像,实现高效、可重复的构建过程。Dockerfile定义了构建镜像所需的所有指令,包括基础镜像选择、软件安装、文件复制等,极大提高了开发和部署的灵活性与一致性。掌握Dockerfile的编写,对于提升软件开发效率和环境管理具有重要意义。
41 9
|
26天前
|
关系型数据库 MySQL Java
【Docker最新版教程】一文带你快速入门Docker常见用法,实现容器编排和自动化部署上线项目
Docker快速入门到项目部署,MySQL部署+Nginx部署+docker自定义镜像+docker网络+DockerCompose项目实战一文搞定!
|
29天前
|
运维 Kubernetes Cloud Native
云原生技术入门:Kubernetes和Docker的协同工作
【10月更文挑战第43天】在云计算时代,云原生技术成为推动现代软件部署和运行的关键力量。本篇文章将带你了解云原生的基本概念,重点探讨Kubernetes和Docker如何协同工作以支持容器化应用的生命周期管理。通过实际代码示例,我们将展示如何在Kubernetes集群中部署和管理Docker容器,从而为初学者提供一条清晰的学习路径。
|
1月前
|
Cloud Native 持续交付 Docker
Docker容器化技术:从入门到实践
Docker容器化技术:从入门到实践
|
1月前
|
应用服务中间件 PHP nginx
Docker-compose 编排lnmp(dockerfile) 完成Wordpress
通过使用Docker Compose,我们可以轻松编排LNMP环境并部署WordPress。本文详细介绍了各组件的Dockerfile和配置文件编写,并通过docker-compose.yml文件实现了整个环境的自动化部署。这种方法不仅简化了部署过程,还提高了环境的可移植性和一致性。希望本文能帮助你更好地理解和使用Docker Compose来管理和部署复杂的应用程序。
96 3
|
1月前
|
运维 持续交付 虚拟化
docker入门详解!!!
本文介绍了容器技术的发展历程,从物理机到虚拟化再到容器化,重点讲解了Docker的诞生及其优势。Docker通过轻量级的容器技术,实现了资源的高效利用、快速启动、环境一致性、持续交付和部署等优点。文章还详细解析了Docker的架构和工作原理,包括Docker Daemon、REST接口、Docker Client等组件,以及容器与虚拟机的差异。
79 2
|
1月前
|
负载均衡 监控 开发者
深入浅出:掌握 Docker Compose 的高级用法
【10月更文挑战第22天】本文深入探讨了 Docker Compose 的高级用法,包括环境变量、服务扩展、网络配置和数据卷管理。通过实例详细介绍了如何利用这些功能提升开发效率和应用部署的灵活性。适合希望深入了解 Docker Compose 的开发者阅读。
下一篇
DataWorks