docker build 的上下文和工作目录(WORKDIR)

-
-
2024-04-08

 

写在前面

在编写Dockerfile时我们总会接触到上下文和工作目录这个两个名词,有时候这些位置搞不清楚,总是让我们陷入困境,本文就一起来看下这2个路径。

构建上下文

Docker Build是Docker提供的一个命令,用于根据Dockerfile构建自定义的镜像。通过Docker Build,可以将应用程序、环境和依赖项打包到一个可移植的容器中,使得应用在不同环境下都能以相同的方式运行。基本语法如下:

docker build [OPTIONS] PATH | URL | -

当使用PATH 时,表示要构建镜像的上下文路径,通常是包含 Dockerfile 的目录。关于构建上下文原理,可以参考深入理解 docker build 中的构建上下文这篇文章,即指定所在的目录打包为.tar包并发送到docker daemon,作为镜像在构建过程中上下环境。那该文件集就是Builder在构建期间可以访问的文件集。构建指令可以引用上下文中的任何文件和目录。

Dockerfile文件的COPY指令,拷贝的源文件就是基于上下文目录来查找的,语法如下:

COPY <src> <dest>

详解:复制构建上文环境下 <src>内容到镜像中的 <dest>,目标路径不存在时,会自动创建。

  • <src>:可以是上下文环境目录的一个相对路径(文件或目录),路径必须在构建的上下文中
  • <dest>:可以是镜像内绝对路径,或者相对于工作目录(WORKDIR)的相对路径

到底什么是上下文路径,我们需要先来看下,而要解释清楚什么是上下文路径,必须先看下当执行docker build时的执行流程,该流程如下:

1:将当前所在的目录打包为.tar包并发送到docker daemon
2:docker daemon将tar包解压到一个临时目录,比如docker daemon的/var/lib/tmp目录(实际不是这个目录)

这里tar压缩文件的最终解压目录就是我们上下文了,比如我们有如下的目录:

dongyunqi@dongyunqi-virtual-machine:~$ tree helloworld-app/
helloworld-app/
├── docker
│   ├── hello.txt
│   └── html
│       └── index.html
└── Dockerfile

2 directories, 3 files

Dockerfile如下:

dongyunqi@dongyunqi-virtual-machine:~$ cat helloworld-app/Dockerfile 
FROM busybox
COPY hello.txt .
COPY html/index.html .

然后我们在helloworld目录执行docker build,如下:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t hello-app:2.0 helloworld-app/
Sending build context to Docker daemon   5.12kB # tar包成功到docker daemon,后面就是docker daemon的工作了
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : COPY hello.txt .
COPY failed: stat /var/lib/docker/tmp/docker-builder375982663/hello.txt: no such file or directory

COPY failed: stat /var/lib/docker/tmp/docker-builder375982663/hello.txt: no such file or directory我们可以得到如下的信息:

1:docker客户端打包生成的tar包名字叫做`docker-builder375982663.tar`。
2:docker daemon解压tar包的目录是/var/lib/docker/tmp
3:这里的上下文目录是/var/lib/docker/tmp/docker-builder375982663
4:在上下文目录里无法找到文件hello.txt

其中4找不到文件的原因是,因为文件在/var/lib/docker/tmp/docker-builder375982663/docker/hello.txt,因此我们只需要修改Dockerfiie将COPY hello.txt .修改为COPY docker/hello.txt .,如下:

dongyunqi@dongyunqi-virtual-machine:~$ cat helloworld-app/Dockerfile
FROM busybox
COPY docker/hello.txt . # 修改这一行
COPY html/index.html .

运行:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t hello-app:2.0 helloworld-app/
Sending build context to Docker daemon  6.144kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : COPY docker/hello.txt .
 ---> 83989744c05c
Step 3/3 : COPY html/index.html .
COPY failed: file not found in build context or excluded by .dockerignore: stat html/index.html: file does not exist

此时找不到html/index.html,同样的问题,修改为docker/html/index.html,如下:

dongyunqi@dongyunqi-virtual-machine:~$ cat helloworld-app/Dockerfile
FROM busybox
COPY docker/hello.txt .
COPY docker/html/index.html .

运行:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t hello-app:2.0 helloworld-app/
Sending build context to Docker daemon  7.168kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : COPY docker/hello.txt .
 ---> Using cache
 ---> 83989744c05c
Step 3/3 : COPY docker/html/index.html .
 ---> Using cache
 ---> 10fa588c5565
Successfully built 10fa588c5565
Successfully tagged hello-app:2.0

到这里上下文我们已经清楚了,

2:工作目录

工作目录默认就是根目录,如下的Dockerfile验证:

dongyunqi@dongyunqi-virtual-machine:~$ cat howPwd.txt 
FROM busybox
RUN pwd

运行:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t hello-app:2.0 -f howPwd.txt helloworld-app/
Sending build context to Docker daemon  8.751kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : WORKDIR / # 这里docker daemon也输出了当前的工作目录
 ---> Running in c1d493dc5ff6
Removing intermediate container c1d493dc5ff6
 ---> 4d065957678b
Step 3/3 : RUN pwd
 ---> Running in 7fc8f9b6b35a
/  # 这里我们输出了当前工作目录是根目录
Removing intermediate container 7fc8f9b6b35a
 ---> 578d72f80d16
Successfully built 578d72f80d16
Successfully tagged hello-app:2.0

当然可以通过WORKDIR来修改工作目录,如下:

dongyunqi@dongyunqi-virtual-machine:~$ cat howPwd.txt 
FROM busybox
WORKDIR /var
RUN pwd

运行:

dongyunqi@dongyunqi-virtual-machine:~$ docker build -t hello-app:2.0 -f howPwd.txt helloworld-app/
Sending build context to Docker daemon  8.751kB
Step 1/3 : FROM busybox
 ---> 827365c7baf1
Step 2/3 : WORKDIR /var # 这里docker daemon也输出了当前的工作目录是/var
 ---> Using cache
 ---> 89da7feb392e
Step 3/3 : RUN pwd
 ---> /var # 这里我们输出了当前工作目录是/var
Successfully built 7975c01019bd
Successfully tagged hello-app:2.0

所以可得WORKDIR即为docker在构建过程中各种指令的执行目录

写在后面

总结:

  • docker build上下文即通过docker build命令参数中指定路径文件压缩拷贝到daemon服务端临时解压后文件夹目录。用于明确镜像构建的时使用的上下文环境。也就是说在执行dockerfile各类构建指令时,可以访问的文件集。对于COPY或者ADD指令,作为第一个参数的相对目录。
  • WORKDIR即为docker在构建过程中各种指令的执行目录。工作目录(WORKDIR)的相对路径,作为第二参数,以工作目录(WORKDIR)的相对路径,也可以使用镜像的绝对路径。

 

 

 

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录