华子目录
- 制作镜像
- 基于dockerfile制作镜像
- dockerfile介绍
- 注意
- 格式
- PATH
- 上下文路径
- URL
- -
- Dockerfile指令-FROM指令
- 格式
- 示例
- Dockerfile指令-MAINTAINER指令
- 介绍
- 示例
- Dockerfile指令-COPY指令
- 介绍
- 示例1
- 示例2
- Dockerfile指令-ADD指令
- 介绍
- 示例
- Dockerfile指令-WORKDIR指令
- 介绍
- 示例
- Dockerfile指令-VOLUME指令
- 示例
- Dockerfile指令-EXPOSE指令
- 介绍
- 示例
- Dockerfile指令-ENV指令
- 介绍
- 示例
- Dockerfile指令-RUN指令
- 介绍
- 示例
- Dockerfile指令-CMD指令
- 介绍
- 示例
- 示例1:运行一个简单的echo命令
- 示例2:启动一个Web服务器
- 示例3:运行一个Python脚本
- 示例4:使用shell格式运行命令
- 示例5:结合ENTRYPOINT和CMD
- Dockerfile指令-ENTRYPOINT指令
- 示例
- 示例1:使用exec格式运行一个可执行文件
- 示例2:传递参数给ENTRYPOINT
- 示例3:结合CMD和ENTRYPOINT
- 示例4:使用ENTRYPOINT运行服务
- Dockerfile指令-HEALTHCHECK指令
- 介绍
- 示例
- 示例1:简单HTTP检查
- 示例2:脚本检查
- 示例3:禁用继承的健康检查
- Dockerfile指令-ONBUILD指令
- 介绍
- 示例
制作镜像
当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改:
- 从已经创建的容器中更新镜像,并提交这个镜像
- 使用docker指令来创建一个新的镜像
基于dockerfile制作镜像
dockerfile介绍
- docker中有个非常重要的概念叫做镜像(image)。docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序,库,资源,配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷,环境变量,用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
- 镜像的定制实际上就是定制每一层所添加的配置,文件。如果我们可以把每一层修改,安装,构建,操作的命令都写入一个脚本,用这个脚本来构建,定制镜像,那么之前提及的无法重复的问题,镜像构建透明性的问题,体积的问题就都会解决。这个脚本就是dockerfile。dockerfile是一个文本文件,其内包含了一条条的指令(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
用于指定镜像的名称和标签。PATH
是 Dockerfile 所在的目录路径。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
指令的示例:
- 复制单个文件到镜像的根目录:
COPY myfile.txt /
- 复制多个文件到镜像的某个目录:
COPY file1.txt file2.txt /mydir/
- 使用通配符复制多个文件到镜像:
COPY *.txt /mydir/
- 复制目录及其内容到镜像:
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 3月 29 16:47 dockerfile
-rw-r--r-- 1 root root 12 3月 29 16:36 index.html
drwxr-xr-x 2 root root 70 3月 29 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>
指定了在镜像中的目标路径。
功能特性:
- 自动解压:如果源文件(本地系统上,不是URL上的)是tar类型的压缩文件,ADD指令会自动解压它到目标路径。
- 网络资源支持:ADD指令可以从URL获取文件并添加到镜像中,类似于wget命令。然而,为了保持镜像尽可能小,官方推荐在获取网络资源后使用RUN命令结合curl或wget来删除不再需要的文件,以避免在镜像中额外添加不必要的层。
- 路径创建:如果目标路径不存在,ADD指令会自动创建它。
使用注意事项:
- 路径要求:源文件或目录的路径必须是构建上下文中的路径,不能是相对于WORKDIR的路径。因此,如果使用了相对路径,它会相对于Dockerfile的所在目录进行解析。
- 避免使用ADD从远程URL获取包:虽然ADD指令支持从URL获取文件,但官方建议通过RUN命令结合curl或wget来完成这一操作,并在文件提取后删除不再需要的文件,以减小镜像的大小。
与COPY指令的区别:
COPY指令与ADD指令在功能和使用方式上类似,但COPY指令不支持自动解压和从网络获取文件。因此,在不需要这些额外功能的情况下,使用COPY指令更为简单和直接。
示例:
- 将本地文件添加到镜像:
ADD myfile.txt /mydir/
- 将目录及其内容添加到镜像:
ADD mydir/ /mydir/
- 从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
,然后在这个目录下执行RUN
和COPY
指令。最后,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 PORTSNAMES
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 用时 0s2024-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
指令的示例:
- 安装软件包:
RUN apt-get update && apt-get install -y package-name
- 设置环境变量:
RUN export VARIABLE_NAME=value
注意:使用RUN
来设置环境变量会在构建时设置,但不会保留在最终容器中。如果需要环境变量在容器运行时也生效,应该使用ENV
指令。
- 复制文件或目录:
虽然通常使用COPY
指令来复制文件或目录到镜像中,但RUN
指令也可以结合shell命令来实现类似的操作,例如:
RUN mkdir /mydir && cp /source/file.txt /mydir/
- 执行脚本:
RUN chmod +x /path/to/script.sh && /path/to/script.sh
- 使用Exec格式执行命令:
RUN ["/bin/bash", "-c", "echo Hello, World!"]
在构建镜像时,Docker会按照Dockerfile中的顺序执行RUN
指令。每次RUN
指令执行后,都会创建一个新的镜像层。因此,为了保持镜像的轻量级和高效,应尽量减少不必要的RUN
指令,并将多个命令合并成一个RUN
指令执行,这样可以减少镜像的层数,从而提高构建和运行的效率。
另外,如果RUN
指令中的命令依赖于之前的步骤(比如安装某个软件包),那么这些步骤应该被放在同一个RUN
指令中,或者使用多个RUN
指令并按顺序排列,以确保依赖关系正确。
需要注意的是,RUN
指令在构建镜像时执行,而不是在容器运行时执行。因此,它主要用于构建镜像时的配置和准备工作,而不是用于定义容器运行时的行为。容器运行时的行为通常由CMD
或ENTRYPOINT
指令来定义。
示例
通过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指令有三种格式:
-
exec格式:
CMD ["executable","param1","param2"]
。这是首选的格式,因为它避免了shell字符串解析的问题,并且它是以exec方式运行的,这意味着它不会启动一个额外的shell。 -
shell格式:
CMD command param1 param2
。在这种格式中,命令会在/bin/sh -c中执行,这意味着它会启动一个shell。注意,如果你的命令依赖于shell的特性(如变量替换或通配符扩展),那么你应该使用shell格式。 -
参数列表格式:
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
当ENTRYPOINT
和CMD
同时存在时,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
指令中定义的arg1
和arg2
。
CMD
指令在Dockerfile中提供了很大的灵活性,允许你定义容器启动时的默认行为。但是,需要注意的是,CMD
指令可以被docker run
命令中的参数所覆盖。如果需要更稳定的容器启动行为,可以考虑使用ENTRYPOINT
。
Dockerfile指令-ENTRYPOINT指令
entrypoint
Dockerfile中的ENTRYPOINT指令用于配置容器启动时执行的命令及其参数。与CMD指令类似, ENTRYPOINT也是定义容器启动行为的指令,但两者在功能和用法上有一些区别。
ENTRYPOINT指令有两种格式:
- exec格式:
ENTRYPOINT ["executable", "param1", "param2"]
。这是推荐的方式,因为它不会通过shell来执行,而是直接调用exec函数来启动程序,这样可以避免shell解析带来的问题,并减少容器启动时的开销。 - 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"]
在这个例子中,如果你运行容器时没有提供任何额外的参数,arg1
和arg2
会被传递给/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指令有两种形式:
- HEALTHCHECK [options] CMD :这种形式包含一个或多个选项,如interval(间隔)、timeout(超时)等。从容器运行起来开始计时,每隔interval秒进行一次健康检查。如果命令执行超过timeout秒,则视为超时并标记为错误状态。
例如:
HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost/ || exit 1
在这个例子中,容器每5秒执行一次健康检查,如果curl命令在3秒内没有响应,则认为容器不健康。
- 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 ]; thenexit 0 # 健康
elseexit 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 指令,如 RUN
、COPY
、ADD
等。当一个新的镜像基于当前镜像构建时,这些指令会被插入到子镜像的 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
指令基于这个镜像构建时,RUN
和 COPY
指令会在子镜像的构建过程中自动执行。
需要注意的是,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
指令中定义的 RUN
和 COPY
会自动执行。这意味着,尽管这些指令没有直接写在新镜像的 Dockerfile 中,但它们仍然会被执行。
请注意,ONBUILD
指令只会在基于当前镜像构建新的镜像时触发,并不会在当前镜像的构建过程中执行。因此,在编写 ONBUILD
指令时,要确保它们是针对派生镜像有意义的,并且不会产生不必要的副作用。
最后,当使用 ONBUILD
指令时,务必在文档中清晰地说明这些指令的用途和行为,以便其他开发者能够理解和正确使用它们。