一篇复现Dockerfile指令

制作镜像

当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改:

  • 从已经创建的容器中更新镜像,并提交这个镜像
  • 使用docker指令来创建一个新的镜像

基于dockerfile制作镜像

dockerfile介绍

  • docker中有个非常重要的概念叫做镜像(image)。docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序,库,资源,配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷,环境变量,用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
  • 镜像的定制实际上就是定制每一层所添加的配置,文件如果我们可以把每一层修改,安装,构建,操作的命令都写入一个脚本用这个脚本来构建,定制镜像,那么之前提及的无法重复的问题,镜像构建透明性的问题,体积的问题就都会解决。这个脚本就是dockerfiledockerfile是一个文本文件其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

(1)dockerfile编写的基本结构

  • dockerfile一般分为四部分:基础镜像信息,维护者信息,镜像操作指令和容器启动时执行指令,"#"为dockerfile中的注释

(2)一台主机可以有多个dockerfile

  • 要使用多个dockerfile创建镜像,可以在不同目录编写dockerfile然后在dockerfile所在的目录下构建新的镜像

(3)docker build是基于dockerfile制作镜像的命令

注意

dockerfile中所包含需要的内容;如copy的文件,目录等,都需要在dockerfile同级目录下存在

格式

基本语法如下:

docker build [OPTIONS] PATH | URL | -

其中:

  • OPTIONS 是可选参数,用于配置构建过程的行为。例如,--tag-t 用于指定镜像的名称和标签。
  • PATHDockerfile 所在的目录路径Docker 会在该目录下查找名为 Dockerfile(默认的文件名,除非使用 -f 参数指定了其他文件名)的文件,并按照其中的指令构建镜像。
  • URL 是 Git 仓库的 URL如果 Dockerfile 位于远程 Git 仓库中,可以通过这个 URL 直接构建。
  • - 表示从标准输入(stdin)读取 Dockerfile 内容,这通常与管道操作符 | 结合使用,以便从其他命令的输出中直接构建镜像。
    在这里插入图片描述

PATH

  • 一般用.(即当前工作目录)作为上下文路径
  • 说明:Docker 在运行时分为 Docker 引|擎(也就是服务端守护进程)和客户端工具。 Docker 的引擎提供了一组REST API,被称为Docker Remote AP!,而如 docker 命令这样的客户端工具,则是通过这组 API与Docker引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计,让我们操作远程服务器的 Docker 引擎变得轻而易举。
  • 经常会需要将一些本地文件复制进镜像,比如通过 COPY 指当我们进行镜像构建的时候,并非所有定制都会通过 RUN 指令完成,会ADD 指令等,而 docker build 命令构建镜像、其实并非在本地构建,而是在服务端,也就是 Docker 引整中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?
  • 这就引入了上下文的概念。 当构建的时候,用户会指定构建镜像上下文的路径, docker build 命令得知这个路径后, 会将路径下的所有内容打包,然后上传给 Docker 引擎。这样Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。

上下文路径

  • 在Docker构建过程中,上下文路径是一个关键概念。当用户执行docker build命令时,需要指定一个构建镜像上下文的路径。Docker会将这个路径下的所有内容打包,然后上传给Docker引擎。这个路径通常包含Dockerfile,以及其他构建镜像所需的文件和目录。

  • 默认情况下,如果不额外指定Dockerfile,Docker会在上下文目录下查找名为Dockerfile的文件作为构建依据。但实际上,Dockerfile的文件名并不要求必须为Dockerfile,而且并不要求必须位于上下文目录中。用户可以通过-f--file参数来指定某个文件作为Dockerfile,例如docker build -f dockerfiles/Dockerfile .

  • 此外,最佳实践建议是使用.dockerignore文件来排除不需要加入到build context中的文件,类似于.gitignore文件。这样可以确保构建镜像时只包含必要的文件,从而提高构建效率和镜像质量。

  • 在指定上下文路径时,可以使用.来表示当前路径作为上下文路径,或者提供具体的文件或目录路径。请注意,构建过程中的网络、缓存等策略也可以通过相应的选项进行配置。

URL

docker build还支持从URL构建,docker build http://server/context.tar.gz,如果所给出的URL是个tar压缩包,那么docker引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建

-

docker build还支持从标准输入中读取dockerfile进行构建:

  • docker build - < dockerfile或者cat dockerfile | docker build -

如果标准输入传入的是文本文件,则将其视为dockerfile,并开始构建这种形式由于直接从标准输入中读取dockerfile的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件copy进镜像之类的事情。

  • docker build - < context.tar.gz

如果发现标准输入的文件格式是gzip、bzip2以及xz的话,将会使其为上下文压缩包,直接将其展开将里面的内容视为上下文,并开始构建。

Dockerfile指令-FROM指令

  • FROM 指令必须是 Dockerfile 中非注释行的第一个指令,即一个 Dockerfile 从FROM语句开始
  • FROM 指令用于为镜像文件构建过程指定基础镜像后续的指令运行于此基础镜像所提供的运行环境
  • 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会自动从 Docker 的公共库 pull 镜像下来。如果找不到指定的镜像文件,docker build 会返回一个错误信息
  • 如果有需求在一个 Dockerfile 中创建多个镜像,FROM可以在一个 Dockerfie 中出现多次
  • 如果FROM语句没有指定镜像标签,则默认使用latest标签。
  • 除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch这个镜像是虚拟的概念, 并不实际存在,它表一个空白的镜像。
  • 如果你以 scratch 为基础镜像的话, 意味着你不以任何镜像为基础, 接下来所写的指令将作为镜像第一层开始存在。 不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如swarm、coreos/etcd。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch 会让镜像体积更加小巧。 使用Go 语言开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go是特别适合容器微服务架构的语言的原因之一。

格式

FROM 镜像名[:tag]
或
FROM 镜像名@digest

示例

[root@server ~]# mkdir -v docker
mkdir: 已创建目录 'docker'
[root@server ~]# cd docker/

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest      

Dockerfile指令-MAINTAINER指令

maintainer

介绍

  • 用于让docker制作者提供本人的详细信息
  • dockerfile并不限制maintainer指令可以出现的位置,但推荐将其放置于FROM指令之后

Dockerfile中的MAINTAINER指令用于指定镜像的维护者信息。然而,值得注意的是,这个指令已经在较新的Docker版本中被弃用,取而代之的是使用LABEL指令来设置镜像的元数据,包括维护者信息。

  • 使用LABEL指令来设置维护者信息的示例如下:
LABEL maintainer="你的名字<你的邮箱>"
  • 在早期的Docker版本中,MAINTAINER指令的格式通常如下:
MAINTAINER <name>
  • 其中,<name>可以是任意字符串,通常包含维护者的名字和联系方式,如邮箱地址。

示例

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"   

Dockerfile指令-COPY指令

介绍

  • 从上下文目录中复制文件或目录到镜像里的指定路径

在Dockerfile中,COPY 指令用于从构建的上下文(context)中复制文件或目录到镜像中。构建的上下文通常是你在执行 docker build 命令时指定的目录或文件路径。COPY 指令在镜像构建过程中执行,确保必要的文件被包含在最终的镜像中。

COPY 指令的基本语法如下:

COPY <src>... <dest>
  • <src>:源文件或目录的路径,可以是一个或多个,支持通配符。
  • <dest>:目标路径,即文件或目录在镜像中的位置。

下面是一些 COPY 指令的示例:

  1. 复制单个文件到镜像的根目录:
COPY myfile.txt /
  1. 复制多个文件到镜像的某个目录:
COPY file1.txt file2.txt /mydir/
  1. 使用通配符复制多个文件到镜像:
COPY *.txt /mydir/
  1. 复制目录及其内容到镜像:
COPY mydir /mydir
  • 需要注意的是,如果目标路径 <dest> 在镜像中不存在,Docker 会尝试创建它。如果 <dest> 是一个已存在的文件,COPY 指令会替换它。如果 <dest> 是一个已存在的目录,COPY 指令会将源文件或目录复制到该目录中。

  • 此外,COPY 指令和 ADD 指令在功能上有些相似,ADD 指令具有一些额外的功能,比如支持从URL中下载文件和自动解压缩tar文件。然而,由于 ADD 指令的这些额外功能可能使得构建过程更加复杂和难以预测,因此官方推荐在大多数情况下使用 COPY 指令。

  • 在编写Dockerfile时,应尽可能使用 COPY 指令来复制文件,因为它比 ADD 指令更直观且易于理解。只有在确实需要 ADD 指令的额外功能时,才考虑使用它。

  • 要复制的文件必须使docker build上下文中的路径,不能是其父目录中的文件

  • 如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制

  • 使用copy指令,源文件的各种元数据都会保留,比如读,写,执行权限,文件变更时间等;

  • 目标路径,即正在创建的image的文件系统路径,建议使用绝对路径

  • 目标路径不需要事先创建,如果目录不存在会在复制文件前先行在镜像中创建目录

示例1

[root@server docker]# echo "hello world" > index.html
[root@server docker]# ls  #要确保dockerfile的同级路径下有index.html文件 
dockerfile  index.html


[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY  index.html  /data/web/html/  


[root@server docker]# docker build -t busyboxhttpd:v1  ./   #制作镜像
[+] Building 0.2s (7/7) FINISHED                                                                         docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 158B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 31B                                                                                   0.0s
 => [1/2] FROM docker.io/library/busybox:latest                                                                    0.0s
 => CACHED [2/2] COPY index.html /data/web/html/                                                                   0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:a5a8571e609a0206d515d12b13b8f2ecc017e6a3de61a9b7b4d2faba6610921a                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v1                                                                 0.0s


[root@server docker]# docker images
REPOSITORY     TAG       IMAGE ID       CREATED         SIZE
busyboxhttpd   v1        a5a8571e609a   3 minutes ago   1.24MB


[root@server docker]# docker run --name web -itd busyboxhttpd:v1   #运行镜像生成容器
2da1daa0f76049acb0b3fb1d5b7ddd89fdcb2f905f19a2aba3e4c90eceebc84e
[root@server docker]# docker exec -it web sh #进入容器
/ # cd /data/web/html  
/data/web/html # ls
index.html
/data/web/html # cat index.html
hello world

示例2

[root@server docker]# cp -r /etc/yum.repos.d/ ./
[root@server docker]# ll
总用量 8
-rw-r--r-- 1 root root 121  329 16:47 dockerfile
-rw-r--r-- 1 root root  12  329 16:36 index.html
drwxr-xr-x 2 root root  70  329 17:11 yum.repos.d


[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY index.html /data/web/html/
COPY ./yum.repos.d  /etc/yum.repos.d/

#如果是复制目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制
#在dockerfile的同级目录下准备好yum.repos.d目录


[root@server docker]# docker build -t busyboxhttpd:v2 ./     #制作镜像
[+] Building 0.2s (8/8) FINISHED                                                                         docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 198B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/3] FROM docker.io/library/busybox:latest                                                                    0.0s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 2.86kB                                                                                0.0s
 => CACHED [2/3] COPY index.html /data/web/html/                                                                   0.0s
 => [3/3] COPY ./yum.repos.d  /etc/yum.repos.d/                                                                    0.0s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.1s
 => => writing image sha256:2141dc00c0c0a3850e43c086f06cbca040aac603b65c3cd043c940faac974c41                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v2                                                                 0.0s


[root@server docker]# docker run --name web1 -itd busyboxhttpd:v2  #运行容器
0fc2106fc16f66b59a105c185c595545a5ac9aafe4c7488c0af997ea58a300fe
[root@server docker]# docker exec -it web1 sh
/ # cd /etc/yum.repos.d/   #进入容器
/etc/yum.repos.d # ls
RHELserver.repo  docker-ce.repo   redhat.repo
/etc/yum.repos.d # cd
/ # cd /data/web/html
/data/web/html # ls
index.html

Dockerfile指令-ADD指令

介绍

  • ADD指令类似于COPY指令,ADD支持使用tar文件和URL文件

Dockerfile中的ADD指令是一个强大的工具,用于将文件、目录或URL标记的文件从构建上下文(通常是Dockerfile所在的目录)复制到镜像中。以下是关于ADD指令的详细解释:

基本语法

ADD <src>... <dest>
  • <src>指定了要添加到镜像中的源文件或目录的路径,也可以是URL。
  • <dest>指定了在镜像中的目标路径。

功能特性

  1. 自动解压:如果源文件(本地系统上,不是URL上的)是tar类型的压缩文件,ADD指令会自动解压它到目标路径。
  2. 网络资源支持:ADD指令可以从URL获取文件并添加到镜像中,类似于wget命令。然而,为了保持镜像尽可能小,官方推荐在获取网络资源后使用RUN命令结合curl或wget来删除不再需要的文件,以避免在镜像中额外添加不必要的层。
  3. 路径创建:如果目标路径不存在,ADD指令会自动创建它。

使用注意事项

  1. 路径要求:源文件或目录的路径必须是构建上下文中的路径,不能是相对于WORKDIR的路径。因此,如果使用了相对路径,它会相对于Dockerfile的所在目录进行解析。
  2. 避免使用ADD从远程URL获取包:虽然ADD指令支持从URL获取文件,但官方建议通过RUN命令结合curl或wget来完成这一操作,并在文件提取后删除不再需要的文件,以减小镜像的大小。

与COPY指令的区别

COPY指令与ADD指令在功能和使用方式上类似,但COPY指令不支持自动解压和从网络获取文件。因此,在不需要这些额外功能的情况下,使用COPY指令更为简单和直接。

示例

  1. 将本地文件添加到镜像:
ADD myfile.txt /mydir/
  1. 将目录及其内容添加到镜像:
ADD mydir/ /mydir/
  1. 从URL添加文件到镜像:
ADD https://example.com/myfile.txt /mydir/
  • 如果是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于"tar-x"命,然而,通过URL获取到的tar文件将不会自动展开;

示例

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY index.html /data/web/html/
COPY ./yum.repos.d  /etc/yum.repos.d/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz  /usr/local/src/  



[root@server docker]# docker build -t busyboxhttpd:v3 ./
[+] Building 3.4s (10/10) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 265B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/4] FROM docker.io/library/busybox:latest                                                                    0.0s
 => [4/4] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  /usr/local/src/                                       3.1s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 198B                                                                                  0.0s
 => CACHED [2/4] COPY index.html /data/web/html/                                                                   0.0s
 => CACHED [3/4] COPY ./yum.repos.d  /etc/yum.repos.d/                                                             0.0s
 => [4/4] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  /usr/local/src/                                       0.1s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:7251cc27a9053f755582ae72aff9d92d3d14f728a89c44c0a3b6d0ae106fd3f8                       0.0s
 => => naming to docker.io/library/busboxhttpd:v3                                                                  0.0s



[root@server docker]# docker run --name web -itd busyboxhttpd:v3
ff95162ff1f3b6591274d6f482ae933be85b19a2d88d88113e047b0f33d435ec
[root@server docker]# docker exec -it web sh
/ # ls /usr/local/src  #可以看到没有解压
nginx-1.15.8.tar.gz   

Dockerfile指令-WORKDIR指令

workdir

介绍

  • 用于为dockerfile中所有的run,cmd,copy,add等指令设定工作目录

WORKDIR指令在Dockerfile中用于设置工作目录,或者称为当前目录。当使用相对目录时,WORKDIR会采用上一个WORKDIR指定的目录作为基准。这个指令相当于在Linux中的cd命令,但不同的是,指定了WORKDIR后,容器启动时执行的命令会在该目录下执行。

WORKDIR指令的语法如下:

WORKDIR /path/to/workdir

其中,/path/to/workdir是你想要设置的工作目录的路径。如果目录不存在,WORKDIR会自动创建它,无需显式创建。

WORKDIR指令不仅影响RUN、CMD、ENTRYPOINT指令,还影响COPY和ADD指令。这意味着这些指令会在你指定的WORKDIR中执行。

下面是一个使用WORKDIR指令的示例:

# 基础镜像
FROM centos

# 设置工作目录为/app
WORKDIR /app

# 在/app目录下执行一些命令,比如安装软件或复制文件
RUN yum install some-package -y
COPY myfile.txt .

# 启动容器时执行的命令会在/app目录下执行
CMD ["some-command"]
  • 在这个例子中,我们首先设置工作目录为/app,然后在这个目录下执行RUNCOPY指令。最后,CMD指令启动的命令也会在/app目录下执行。

  • 需要注意的是,虽然WORKDIR会自动创建不存在的目录,但如果你想要创建的目录已经存在并且包含文件,那么这些文件可能会被WORKDIR指令覆盖。因此,在使用WORKDIR时,最好确保指定的目录路径是明确的,并且不会意外地覆盖重要文件。

  • 在dockerfile文件中,workdir指令可以出现多次

  • 如果该目录不存在,workdir会帮你建立目录

示例

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY index.html /data/web/html/
COPY ./yum.repos.d  /etc/yum.repos.d/
WORKDIR /huazi/home/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/


[root@server docker]# docker build -t busyboxhttpd:v4 ./  #创建镜像
[+] Building 1.0s (11/11) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 278B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/5] FROM docker.io/library/busybox:latest                                                                    0.0s
 => CACHED [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                         0.8s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 198B                                                                                  0.0s
 => CACHED [2/5] COPY index.html /data/web/html/                                                                   0.0s
 => CACHED [3/5] COPY ./yum.repos.d  /etc/yum.repos.d/                                                             0.0s
 => [4/5] WORKDIR /huazi/home/                                                                                     0.0s
 => [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                                0.0s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:5413ad4f732008c16d639d267b9b341ff15b46da2b02ff66bc6eae520c2c7aff                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v4                                                                 0.0s


[root@server docker]# docker run --name web -itd busyboxhttpd:v4  #运行镜像
0c3898fb881228fbc52e47e043a76739120f20206f90152d29d4111e45a9f03c
[root@server docker]# docker exec -it web sh  #进入镜像,可以发现,一进来就会进入/huazi/home目录下
/huazi/home # cd /
/ # cd /huazi/home
/huazi/home # ls
src
/huazi/home # cd src
/huazi/home/src # ls
nginx-1.15.8.tar.gz

Dockerfile指令-VOLUME指令

volume

Dockerfile中的VOLUME指令用于在Docker镜像中声明一个或多个目录作为挂载点。当Docker容器基于这个镜像运行时,这些目录可以挂载到宿主机上的目录或者其他容器上,从而允许数据在容器和宿主机之间共享或者在不同容器之间共享。

VOLUME指令的基本语法如下:

VOLUME ["/path/to/volume1", "/path/to/volume2"]

你可以指定一个或多个目录作为挂载点。这些目录在容器运行时会自动创建(如果不存在的话),并且会被标记为挂载点,以供后续挂载操作使用。

以下是一个使用VOLUME指令的Dockerfile示例:

# 基础镜像
FROM ubuntu:latest

# 声明一个挂载点
VOLUME ["/data"]

# 其他指令...
  • 在这个例子中,/data目录被声明为一个挂载点。当基于这个Dockerfile构建的镜像运行容器时,/data目录将自动创建,并且可以被挂载到宿主机或者其他容器上。

  • 需要注意的是,VOLUME指令只是声明了挂载点,并不会自动执行挂载操作。挂载操作是在容器运行时通过Docker命令行或者其他Docker API进行的。你可以使用docker run命令的-v--volume参数来指定挂载关系。

例如,你可以这样运行容器并将宿主机的某个目录挂载到容器的/data目录:

docker run -v /host/data:/data myimage
  • 在这个例子中,宿主机的/host/data目录被挂载到了容器的/data目录上。这样,容器和宿主机之间就可以通过这个挂载点共享数据了。

  • VOLUME指令的一个主要好处是它使得数据持久化和共享变得容易。通过将数据存储在挂载点中,你可以避免在容器删除时丢失数据,并且可以在多个容器之间共享数据。

  • 需要注意的是,虽然VOLUME指令在Dockerfile中声明了挂载点,但它不会创建或修改宿主机的目录。你需要确保挂载的宿主机目录是存在的,并且具有适当的权限供Docker进程访问。

示例

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY index.html /data/web/html/
COPY ./yum.repos.d  /etc/yum.repos.d/
WORKDIR /huazi/home/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/
VOLUME /data/mysql   #这是容器中的挂载点


[root@server docker]# docker build -t busyboxhttpd:v5 ./  #创建镜像
[+] Building 1.0s (11/11) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 297B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                                0.9s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 198B                                                                                  0.0s
 => [1/5] FROM docker.io/library/busybox:latest                                                                    0.0s
 => CACHED [2/5] COPY index.html /data/web/html/                                                                   0.0s
 => CACHED [3/5] COPY ./yum.repos.d  /etc/yum.repos.d/                                                             0.0s
 => CACHED [4/5] WORKDIR /huazi/home/                                                                              0.0s
 => CACHED [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                         0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:deedcfdefb575ec612003e2c6809038bf3fa9dbe73092d21bdb6208ba4a8a622                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v5                                                                 0.0s


#在主机上创建共享目录
[root@server ~]# mkdir /data


[root@server docker]# docker run --name web -itd -v /data:/data/mysql busyboxhttpd:v5
2287b5c7866b6b09327a6e2df9ad9c472c8e9c55b9b35883d66ab9a599e0ba05
[root@server docker]# docker exec -it web sh
/huazi/home # cd /
/ # cd /data/mysql
/data/mysql # ls
/data/mysql # touch file1.txt
/data/mysql # ls
file1.txt
/data/mysql # exit

[root@server ~]# cd /data
[root@server data]# ls   #看到了在容器中创建的file1.txt
file1.txt  

Dockerfile指令-EXPOSE指令

expose

介绍

Dockerfile中的EXPOSE指令用于声明容器运行时所监听的网络端口。它的主要作用是告诉Docker守护进程,容器在运行时需要监听哪些网络端口,以便外部可以访问这些端口。

EXPOSE指令的语法格式如下:

EXPOSE <port> [<port>/<protocol>...]
  • 其中<port>表示需要被监听的端口号,而[<port>/<protocol>...]是可选的,用于指定协议类型,如TCP或UDP等。如果未指定协议,则默认为TCP。

  • 需要注意的是,EXPOSE指令声明的端口必须与容器内应用程序所监听的端口一致,否则无法正常通信。此外,EXPOSE指令并不会自动将这些端口映射到主机上的任何端口。它只是向用户以及后续的Dockerfile指令传达这个信息,以便更好地配置和管理容器。

  • 要在容器运行时将EXPOSE指令声明的端口映射到宿主机的端口,需要使用docker run命令的-p--publish参数。例如:

docker run -p <宿主机端口号>:<容器端口号> <镜像名>
  • 或者,如果你想要自动映射所有EXPOSE指令声明的端口到宿主机的随机高阶端口,可以使用-P参数(大写P)。

  • 在某些特殊情况下,如使用了--net=host宿主机网络模式,容器内EXPOSE指令暴露的端口会直接使用宿主机对应的端口,不存在映射关系。

  • 总的来说,Dockerfile中的EXPOSE指令为容器提供了网络端口监听的信息,但真正的端口映射工作还需要在容器运行时通过Docker命令来完成。这种设计使得Dockerfile更加灵活,可以根据不同的运行环境进行不同的端口映射配置。

  • expose指令可以一次指定多个端口,例如:EXPOSE 11211/udp 11211/tcp

示例

[root@server docker]# vim dockerfile
#description: test image
FROM nginx:latest
LABEL maintainer="huazi <huazi@163.com>"
COPY index.html /data/web/html/
COPY ./yum.repos.d  /etc/yum.repos.d/
WORKDIR /huazi/home/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/
VOLUME /data/mysql
EXPOSE 80/tcp



[root@server docker]# docker build -t busyboxhttpd:v6 ./
[+] Building 0.9s (11/11) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 307B                                                                               0.0s
 => [internal] load metadata for docker.io/library/nginx:latest                                                    0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/5] FROM docker.io/library/nginx:latest                                                                      0.1s
 => CACHED [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                         0.6s
 => [internal] load build context                                                                                  0.1s
 => => transferring context: 198B                                                                                  0.0s
 => [2/5] COPY index.html /data/web/html/                                                                          0.1s
 => [3/5] COPY ./yum.repos.d  /etc/yum.repos.d/                                                                    0.1s
 => [4/5] WORKDIR /huazi/home/                                                                                     0.0s
 => [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                                0.0s
 => exporting to image                                                                                             0.1s
 => => exporting layers                                                                                            0.1s
 => => writing image sha256:0259da332cba5bfcee40d9ebc6f0b39a9660a7f993c108747a65b462e6a1b23a                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v6                                                                 0.0s



[root@server docker]# docker run --name web -P -itd busyboxhttpd:v6
56d99631ac8ce2af67cadb92d1ef0afb382ef3cfce4b0f934706a5ff9eb9d6ea
[root@server docker]# docker ps
CONTAINER ID   IMAGE             COMMAND                   CREATED         STATUS         PORTS
            NAMES
56d99631ac8c   busyboxhttpd:v6   "/docker-entrypoint.…"   8 seconds ago   Up 6 seconds   0.0.0.0:32769->80/tcp, :::32769->80/tcp   web

#另外打开一个终端,验证nginx服务的80端口
[root@server ~]# docker port web
80/tcp -> 0.0.0.0:32769
80/tcp -> [::]:32769
[root@server ~]# wget 127.0.0.1:32769
--2024-03-29 18:46:12--  http://127.0.0.1:32769/
正在连接 127.0.0.1:32769... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:615 [text/html]
正在保存至: “index.html”

index.html                    100%[=================================================>]     615  --.-KB/s  用时 0s

2024-03-29 18:46:12 (4.72 MB/s) - 已保存 “index.html” [615/615])

Dockerfile指令-ENV指令

介绍

  • Dockerfile中的ENV指令用于设置容器中的环境变量。这些环境变量在后续的指令(如RUN)和容器运行时都可以直接使用。

  • ENV指令的基本语法格式如下:

ENV <key>=<value> ...
  • 你可以在Dockerfile中设置单个或多个环境变量,每个环境变量通过键值对的形式进行定义。例如:
ENV VERSION=1.0 DEBUG=on
  • 此外,你也可以在一行中设置多个环境变量,只需用空格分隔即可:
ENV VAR1=value1 VAR2=value2
  • 如果环境变量的值包含空格,你可以使用双引号将其括起来,或者使用反斜杠\进行转义。例如:
ENV NAME="Happy Feet"
  • 在Dockerfile后续的指令中,你可以使用${variable_name}$variable_name的格式来引用这些环境变量。例如,在RUN指令中使用环境变量:
ENV DIR=/app
RUN mkdir $DIR
  • 此外,ENV指令中的环境变量还支持一些bash修饰符,如${variable:-word},它表示如果variable设置了,则使用其值;如果未设置,则使用word作为默认值。

  • 需要注意的是,环境变量是在构建镜像时设置的,并且在容器运行时保持不变。它们可以用于配置容器内的应用程序,提供必要的参数和设置。

示例

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
ENV doc_root=/data/web/html/
COPY index.html $doc_root
COPY ./yum.repos.d  /etc/yum.repos.d/
WORKDIR /huazi/home/
ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/
VOLUME /data/mysql
EXPOSE 80/tcp



[root@server docker]# docker build -t busyboxhttpd:v7 ./
[+] Building 1.0s (11/11) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 333B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/5] FROM docker.io/library/busybox:latest                                                                    0.0s
 => [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                                0.9s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 198B                                                                                  0.0s
 => CACHED [2/5] COPY index.html /data/web/html/                                                                   0.0s
 => CACHED [3/5] COPY ./yum.repos.d  /etc/yum.repos.d/                                                             0.0s
 => CACHED [4/5] WORKDIR /huazi/home/                                                                              0.0s
 => CACHED [5/5] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                         0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:9bd4cbe6740c6519b6b4189763115957c11999d83ae2aeab811b86eb8f1da699                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v7                                                                 0.0s


[root@server docker]# docker run --name web -itd busyboxhttpd:v7
acb15d9ed65706c625faeb297032de5cfe58fde50471d276cb58f5021fbbd29b
[root@server docker]# docker exec -it web sh
/huazi/home # cd /data/web/html
/data/web/html # ls
index.html
#在启动容器时,使用docker run -e 设置修改变量
[root@server docker]# docker run --name web -e doc_root=/huazi  -itd busyboxhttpd:v7

Dockerfile指令-RUN指令

介绍

Dockerfile中的RUN指令是用于在构建镜像时执行命令的。这些命令可以是任何在基础镜像中可用的命令,包括安装软件包、设置环境变量、复制文件等RUN指令执行的结果会被缓存,并作为新的镜像层提交。

RUN指令的基本语法如下:

  • Shell 格式:RUN <command>。这种格式会在一个shell环境中执行命令,类似于在终端中直接运行命令。
  • Exec 格式:RUN ["executable", "param1", "param2"]。这种格式不会启动shell环境,而是直接运行指定的可执行文件及其参数。

以下是一些使用RUN指令的示例:

  1. 安装软件包:
RUN apt-get update && apt-get install -y package-name
  1. 设置环境变量:
RUN export VARIABLE_NAME=value

注意:使用RUN来设置环境变量会在构建时设置,但不会保留在最终容器中。如果需要环境变量在容器运行时也生效,应该使用ENV指令。

  1. 复制文件或目录:
    虽然通常使用COPY指令来复制文件或目录到镜像中,但RUN指令也可以结合shell命令来实现类似的操作,例如:
RUN mkdir /mydir && cp /source/file.txt /mydir/
  1. 执行脚本:
RUN chmod +x /path/to/script.sh && /path/to/script.sh
  1. 使用Exec格式执行命令:
RUN ["/bin/bash", "-c", "echo Hello, World!"]

在构建镜像时,Docker会按照Dockerfile中的顺序执行RUN指令。每次RUN指令执行后,都会创建一个新的镜像层。因此,为了保持镜像的轻量级和高效,应尽量减少不必要的RUN指令,并将多个命令合并成一个RUN指令执行,这样可以减少镜像的层数,从而提高构建和运行的效率。

另外,如果RUN指令中的命令依赖于之前的步骤(比如安装某个软件包),那么这些步骤应该被放在同一个RUN指令中,或者使用多个RUN指令并按顺序排列,以确保依赖关系正确。

需要注意的是,RUN指令在构建镜像时执行,而不是在容器运行时执行。因此,它主要用于构建镜像时的配置和准备工作,而不是用于定义容器运行时的行为。容器运行时的行为通常由CMDENTRYPOINT指令来定义。

示例

通过RUN解压ADD指令的URL的tar.gz压缩包

[root@server docker]# vim dockerfile
#description: test image
FROM busybox:latest
LABEL maintainer="huazi <huazi@163.com>"
ENV doc_root=/data/web/html/ web_server_package="nginx-1.15.8.tar.gz"
COPY index.html $doc_root
COPY ./yum.repos.d  /etc/yum.repos.d/
WORKDIR /huazi/home/
ADD http://nginx.org/download/${web_server_package}  ./src/
VOLUME /data/mysql
EXPOSE 80/tcp
RUN cd ./src && tar -zxvf ${web_server_package}



[root@server docker]# docker build -t busyboxhttpd:v8 ./
[+] Building 2.5s (12/12) FINISHED                                                                       docker:default
 => [internal] load build definition from dockerfile                                                               0.0s
 => => transferring dockerfile: 423B                                                                               0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                  0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [1/6] FROM docker.io/library/busybox:latest                                                                    0.0s
 => [internal] load build context                                                                                  0.0s
 => => transferring context: 198B                                                                                  0.0s
 => [5/6] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                                0.8s
 => CACHED [2/6] COPY index.html /data/web/html/                                                                   0.0s
 => CACHED [3/6] COPY ./yum.repos.d  /etc/yum.repos.d/                                                             0.0s
 => CACHED [4/6] WORKDIR /huazi/home/                                                                              0.0s
 => CACHED [5/6] ADD http://nginx.org/download/nginx-1.15.8.tar.gz  ./src/                                         0.0s
 => [6/6] RUN cd ./src && tar -zxvf nginx-1.15.8.tar.gz                                                            1.4s
 => exporting to image                                                                                             0.2s
 => => exporting layers                                                                                            0.2s
 => => writing image sha256:055e6f67f2af7679593b2b35c34d426cc1d6f0a6bd1d2fcc9150141f4b6e450a                       0.0s
 => => naming to docker.io/library/busyboxhttpd:v8                                                                 0.0s



[root@server docker]# docker run --name web -itd busyboxhttpd:v8
d181e873b02bc901205015043398ef51531e5a87e1720f8515dc93b105c8175b
[root@server docker]# docker exec -it web sh
/huazi/home # cd src
/huazi/home/src # ls
nginx-1.15.8         nginx-1.15.8.tar.gz
/huazi/home/src # cd nginx-1.15.8/
/huazi/home/src/nginx-1.15.8 # ls   #可以看到已经解压了
CHANGES     LICENSE     auto        configure   html        src
CHANGES.ru  README      conf        contrib     man

Dockerfile指令-CMD指令

介绍

Dockerfile中的CMD指令用于定义容器启动时要执行的命令及其参数。这个指令在构建镜像时不会执行,而是在基于该镜像创建并启动容器时执行。CMD指令有助于为容器提供一个默认的启动行为。

CMD指令有三种格式:

  1. exec格式CMD ["executable","param1","param2"]。这是首选的格式,因为它避免了shell字符串解析的问题,并且它是以exec方式运行的,这意味着它不会启动一个额外的shell。

  2. shell格式CMD command param1 param2。在这种格式中,命令会在/bin/sh -c中执行,这意味着它会启动一个shell。注意,如果你的命令依赖于shell的特性(如变量替换或通配符扩展),那么你应该使用shell格式。

  3. 参数列表格式CMD ["param1","param2"]。这种格式用于为ENTRYPOINT提供默认参数。

一个Dockerfile中只能有一个CMD指令,如果写了多个,那么只有最后一个会生效。当运行容器时,可以使用docker run命令的命令行参数来覆盖CMD指令指定的默认命令。

下面是一个简单的示例,展示了如何在Dockerfile中使用CMD指令:

# 基础镜像
FROM ubuntu:latest

# 安装所需的软件包
RUN apt-get update && apt-get install -y nginx

# 将nginx的配置文件复制到容器中
COPY nginx.conf /etc/nginx/nginx.conf

# 定义容器启动时执行的命令
CMD ["nginx", "-g", "daemon off;"]

在这个例子中,当基于这个Dockerfile构建的镜像创建并启动容器时,nginx会以守护进程模式关闭的方式启动。

需要注意的是,CMD指令定义的命令可以被docker run命令行的参数所覆盖。例如,你可以使用docker run -d myimage /bin/bash来启动一个基于myimage镜像的容器,并运行/bin/bash,而不是CMD指令中定义的命令。

此外,CMD指令也可以与ENTRYPOINT指令结合使用,以提供更灵活的容器启动配置。ENTRYPOINT指令用于配置容器,使其可执行化,而CMD指令则可以为ENTRYPOINT提供默认参数或定义容器启动时要执行的命令。

示例

CMD指令在Dockerfile中用于定义容器启动时的默认命令和参数。当容器以docker run命令启动并且没有指定其他命令时,CMD中定义的命令会被执行。以下是一些使用CMD指令的示例:

示例1:运行一个简单的echo命令

FROM ubuntu:latest

# 定义CMD指令来运行echo命令
CMD ["echo", "Hello, World!"]

当你基于这个Dockerfile构建并启动一个容器时,它将输出Hello, World!

示例2:启动一个Web服务器

FROM nginx:latest

# 复制配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 容器启动时启动nginx
CMD ["nginx", "-g", "daemon off;"]

在这个例子中,我们使用了官方的nginx镜像,并复制了一个自定义的配置文件。CMD指令确保了当容器启动时,nginx会以非守护进程模式运行。

示例3:运行一个Python脚本

FROM python:3.8

# 将工作目录设置为/app
WORKDIR /app

# 将当前目录内容复制到容器的/app内
COPY . /app

# 安装任何需要的包
RUN pip install --no-cache-dir -r requirements.txt

# 定义CMD指令来运行Python脚本
CMD ["python", "app.py"]

在这个例子中,我们基于python:3.8镜像构建了一个容器,其中包含了Python环境和一个名为app.py的Python脚本。CMD指令确保当容器启动时,app.py脚本会被执行。

示例4:使用shell格式运行命令

FROM ubuntu:latest

# 安装curl
RUN apt-get update && apt-get install -y curl

# 使用shell格式定义CMD
CMD echo "Fetching Google" && curl http://google.com

在这个例子中,CMD指令使用了shell格式来运行两个命令。首先,它输出一条消息,然后使用curl命令访问Google。请注意,使用shell格式时,整个命令字符串会被/bin/sh -c解释,这可能会导致一些特殊字符或变量扩展被处理。

示例5:结合ENTRYPOINT和CMD

ENTRYPOINTCMD同时存在时,CMD的内容会被作为参数传递给ENTRYPOINT

FROM ubuntu:latest

# 复制脚本到容器中
COPY entrypoint.sh /entrypoint.sh

# 设置ENTRYPOINT为脚本
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]

# CMD指令定义的参数会被传递给ENTRYPOINT的脚本
CMD ["arg1", "arg2"]

在这个例子中,如果entrypoint.sh是一个bash脚本,它可以使用$@来获取所有传递给它的参数,这些参数在docker run命令中没有额外指定的情况下,将是CMD指令中定义的arg1arg2

CMD指令在Dockerfile中提供了很大的灵活性,允许你定义容器启动时的默认行为。但是,需要注意的是,CMD指令可以被docker run命令中的参数所覆盖。如果需要更稳定的容器启动行为,可以考虑使用ENTRYPOINT

Dockerfile指令-ENTRYPOINT指令

entrypoint
Dockerfile中的ENTRYPOINT指令用于配置容器启动时执行的命令及其参数与CMD指令类似, ENTRYPOINT也是定义容器启动行为的指令,但两者在功能和用法上有一些区别。

ENTRYPOINT指令有两种格式:

  1. exec格式ENTRYPOINT ["executable", "param1", "param2"]。这是推荐的方式,因为它不会通过shell来执行,而是直接调用exec函数来启动程序,这样可以避免shell解析带来的问题,并减少容器启动时的开销。
  2. shell格式ENTRYPOINT command param1 param2。这种格式会在/bin/sh -c中执行,即会启动一个shell来执行命令。这种格式在某些情况下可能更灵活,但请注意它可能带来额外的开销和安全问题。

与CMD指令不同的是,ENTRYPOINT指令配置的命令是容器启动时一定会执行的,即使运行docker run时没有指定其他命令这使得ENTRYPOINT非常适合用于设置容器为可执行文件,并将容器转变为一个特定的应用或服务。

此外,ENTRYPOINT指令还允许在运行docker run时传递参数给ENTRYPOINT命令。这些参数会作为ENTRYPOINT命令的额外参数。例如,如果Dockerfile中的ENTRYPOINT指令设置为ENTRYPOINT ["/bin/echo", "Hello"],那么在运行docker run image -it world时,输出将会是Hello world

另外,需要注意的是,ENTRYPOINT指令定义的命令也可以通过docker run命令的--entrypoint参数进行覆盖。这意味着你可以在运行容器时动态地替换ENTRYPOINT指令中定义的命令。

示例

ENTRYPOINT指令在Dockerfile中非常有用,它允许你定义容器启动时默认执行的命令。下面是一些使用ENTRYPOINT指令的示例:

示例1:使用exec格式运行一个可执行文件

假设你有一个名为my_app的可执行文件,你想要在容器启动时运行它:

FROM ubuntu:latest

# 将可执行文件复制到容器中
COPY my_app /usr/local/bin/my_app

# 设置ENTRYPOINT为my_app
ENTRYPOINT ["/usr/local/bin/my_app"]

当你基于这个Dockerfile构建并运行一个容器时,my_app会自动执行。

示例2:传递参数给ENTRYPOINT

你可以在docker run命令后面添加参数,这些参数将会传递给ENTRYPOINT指令指定的命令。

FROM ubuntu:latest

# 复制脚本到容器中
COPY entrypoint.sh /entrypoint.sh

# 设置ENTRYPOINT为脚本,并传递参数
ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh可能看起来像这样:

#!/bin/bash
echo "Running with arguments: $@"
exec "$@"

运行容器时,你可以传递额外的参数给ENTRYPOINT

docker run -it --name mycontainer myimage arg1 arg2 arg3

在这个例子中,arg1, arg2, 和 arg3 将会被传递给/entrypoint.sh脚本,并且脚本中的$@会扩展为这些参数。

示例3:结合CMD和ENTRYPOINT

CMD指令可以作为ENTRYPOINT指令的默认参数。如果ENTRYPOINT是一个可执行文件,那么CMD将作为默认参数传递给这个文件。如果ENTRYPOINT是一个shell脚本,那么CMD会被当作是传递给shell脚本的参数。

FROM ubuntu:latest

# 复制脚本到容器中
COPY my_cmd.sh /my_cmd.sh

# 设置ENTRYPOINT为shell脚本
ENTRYPOINT ["/bin/bash", "/my_cmd.sh"]

# CMD指令定义的参数会被传递给ENTRYPOINT的脚本
CMD ["arg1", "arg2"]

在这个例子中,如果你运行容器时没有提供任何额外的参数,arg1arg2会被传递给/my_cmd.sh脚本。如果你提供了额外的参数,它们会覆盖CMD指令中定义的参数。

示例4:使用ENTRYPOINT运行服务

如果你正在构建一个运行服务的容器(比如一个web服务器),你可能会使用ENTRYPOINT来启动这个服务。

FROM nginx:latest

# 复制配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 设置ENTRYPOINT来启动nginx服务
ENTRYPOINT ["nginx", "-g", "daemon off;"]

在这个例子中,容器启动时会直接运行nginx命令,并且以非守护进程模式运行,这样可以让nginx在前台运行,避免容器立即退出。

通过使用ENTRYPOINT指令,你可以控制容器启动时的默认行为,并且提供灵活的方式来传递参数或覆盖默认行为。

Dockerfile指令-HEALTHCHECK指令

healthcheck

介绍

Dockerfile中的HEALTHCHECK指令是用于配置容器健康检查的。通过HEALTHCHECK指令,可以定义容器运行时的健康检查行为,以便及时监控容器的状态,并在发现问题时进行处理。

HEALTHCHECK指令有两种形式:

  1. HEALTHCHECK [options] CMD :这种形式包含一个或多个选项,如interval(间隔)、timeout(超时)等。从容器运行起来开始计时,每隔interval秒进行一次健康检查。如果命令执行超过timeout秒,则视为超时并标记为错误状态。

例如:

HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost/ || exit 1

在这个例子中,容器每5秒执行一次健康检查,如果curl命令在3秒内没有响应,则认为容器不健康。

  1. HEALTHCHECK NONE:这种形式用于禁止从父镜像继承的HEALTHCHECK指令生效。如果基础镜像中已经定义了健康检查,而你不希望使用它,可以在你的Dockerfile中使用这个指令来禁用它。

HEALTHCHECK指令的返回值决定了该次健康检查的成功与否:

  • 0:表示健康检查成功,容器状态为healthy。
  • 1:表示健康检查失败,容器状态可能变为unhealthy(如果连续失败次数达到一定阈值)。
  • 2:保留值,不要使用这个返回值。

只有当HEALTHCHECK指定的命令返回0时,Docker才认为容器已经处于正常状态。否则,Docker会认为容器还在启动中。

通过合理配置HEALTHCHECK指令,可以确保容器在运行过程中保持健康状态,从而提供稳定可靠的服务。

示例

Dockerfile中的HEALTHCHECK指令允许你指定一个命令来检查容器是否健康。这对于确保服务在运行并且能够响应请求非常有用。以下是一些HEALTHCHECK指令的示例:

示例1:简单HTTP检查

如果你正在运行一个Web服务器,你可以使用curl命令来检查服务是否正在运行并响应HTTP请求。

FROM nginx:latest

# 复制自定义的nginx配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 健康检查:检查nginx是否响应HTTP请求
HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
  CMD curl --fail http://localhost/ || exit 1

在这个例子中,HEALTHCHECK指令设置了三个重要的参数:

  • interval=5s:每5秒检查一次。
  • timeout=3s:每次健康检查命令运行的最大时间为3秒。
  • retries=3:如果命令失败,则重试3次。

如果curl命令返回非零状态码(由于服务器未响应或返回了错误),则容器被视为不健康。

示例2:脚本检查

你可以编写一个脚本来执行更复杂的健康检查,并在HEALTHCHECK指令中调用这个脚本。

FROM ubuntu:latest

# 安装必要的工具
RUN apt-get update && apt-get install -y curl

# 复制自定义的健康检查脚本
COPY healthcheck.sh /healthcheck.sh
RUN chmod +x /healthcheck.sh

# 健康检查:运行自定义脚本
HEALTHCHECK --interval=30s --timeout=10s --retries=5 \
  CMD ["/healthcheck.sh"]

healthcheck.sh脚本中,你可以编写逻辑来检查服务的状态,比如:

#!/bin/bash
# healthcheck.sh

# 检查服务的逻辑...
if [ some_condition ]; then
    exit 0  # 健康
else
    exit 1  # 不健康
fi

示例3:禁用继承的健康检查

如果你基于一个带有HEALTHCHECK指令的基础镜像构建镜像,但你想要禁用这个健康检查,你可以使用HEALTHCHECK NONE

FROM some-base-image-with-healthcheck

# 禁用继承的健康检查
HEALTHCHECK NONE

# ... 其他指令 ...

在上面的示例中,some-base-image-with-healthcheck是一个带有健康检查指令的基础镜像,通过在新的Dockerfile中使用HEALTHCHECK NONE,你禁用了这个继承的健康检查。

通过合理地使用HEALTHCHECK指令,你可以确保你的容器在出现问题时能够被及时发现,并采取适当的措施,比如重启容器或触发警报。

Dockerfile指令-ONBUILD指令

onbuild

介绍

ONBUILD 是 Dockerfile 中的一个指令,它用于定义触发器,这些触发器将在构建的子镜像中执行。换句话说,当当前镜像作为其他镜像的基础镜像时,ONBUILD 指令后面的命令会被执行。

ONBUILD 指令的基本语法是:

ONBUILD <INSTRUCTION>

这里的 <INSTRUCTION> 可以是任何有效的 Dockerfile 指令,如 RUNCOPYADD 等。当一个新的镜像基于当前镜像构建时,这些指令会被插入到子镜像的 Dockerfile 中,并在适当的时机执行。

这个特性对于构建可复用的基础镜像特别有用,比如创建一个包含特定配置或依赖的基础镜像,其他项目可以直接基于这个基础镜像构建,无需重复相同的配置和依赖安装步骤。

下面是一个简单的 ONBUILD 指令的示例:

FROM ubuntu:latest

# 假设这是一个基础镜像,我们希望在其上自动执行一些命令
ONBUILD RUN apt-get update && apt-get install -y some-package
ONBUILD COPY ./some-directory /app/some-directory

# ... 其他基础配置 ...

在这个例子中,当另一个 Dockerfile 使用 FROM 指令基于这个镜像构建时,RUNCOPY 指令会在子镜像的构建过程中自动执行。

需要注意的是,ONBUILD 指令的触发时机是在子镜像的 FROM 指令之后,但在子镜像的其他指令之前。因此,它们可以用于在子镜像的构建过程中添加一些前置操作。

使用 ONBUILD 指令时要谨慎,因为它可能会引入一些难以察觉的副作用,特别是当基础镜像的 ONBUILD 指令与子镜像的指令发生冲突或产生不必要的重复时。因此,在创建基础镜像时,最好明确文档化 ONBUILD 指令的用途和行为,以便其他开发者能够理解和正确使用。

示例

ONBUILD 指令在 Dockerfile 中用于定义一些指令,这些指令将在基于当前镜像构建的子镜像时自动执行。这在创建可复用的基础镜像时非常有用,因为你可以将通用的配置和安装步骤放在基础镜像中,并在派生镜像中自动应用这些步骤。

下面是一个 ONBUILD 指令的示例:

# 基础镜像,这里以 Ubuntu 为例
FROM ubuntu:latest

# 设置工作目录
WORKDIR /app

# 使用 ONBUILD 指令来定义一个 RUN 指令,该指令将在基于这个镜像构建的新镜像中执行
ONBUILD RUN apt-get update && apt-get install -y curl

# 使用 ONBUILD 指令来复制一个文件到派生镜像中
ONBUILD COPY ./config.json /app/config.json

# 基础镜像的其它配置和安装步骤...

假设我们有一个名为 my-base-image 的镜像,它是基于上面的 Dockerfile 构建的。现在,如果我们想要创建一个新的镜像,并且希望自动执行在 my-base-image 中定义的 ONBUILD 指令,我们可以这样做:

# 新的镜像,基于 my-base-image
FROM my-base-image

# 由于 my-base-image 中有 ONBUILD 指令,下面的步骤会在构建时自动执行
# RUN apt-get update && apt-get install -y curl
# COPY ./config.json /app/config.json

# 新镜像的其它配置和步骤...

在构建基于 my-base-image 的新镜像时,ONBUILD 指令中定义的 RUNCOPY 会自动执行。这意味着,尽管这些指令没有直接写在新镜像的 Dockerfile 中,但它们仍然会被执行。

请注意,ONBUILD 指令只会在基于当前镜像构建新的镜像时触发,并不会在当前镜像的构建过程中执行。因此,在编写 ONBUILD 指令时,要确保它们是针对派生镜像有意义的,并且不会产生不必要的副作用。

最后,当使用 ONBUILD 指令时,务必在文档中清晰地说明这些指令的用途和行为,以便其他开发者能够理解和正确使用它们。

  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

^~^前行者~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值