0.背景
通常情况下,我们通过docker build构建一个镜像的时候,需要在build命令中指明构建上下文。一般来说,我们会做两步前置操作:
1.文件名:确认文件名为 Dockerfile
2.目录:跳到Dockerfile文件所在目录
然后,再执行docker build -t imageName:1.0.0 .,所以我们会有两个误区,文件名必须为Dockerfile,且docker build后面的.就是Dockerfile所在的目录。
其实上面这种理解是错误的,要想准确理解其含义,首先我们需要先了解下 Docker 的架构和 docker build 的工作原理。
1.理解docker架构
docker是典型的C/S架构,所谓的CS架构,指的是 client客户端/server服务器 体系结构。即docker系统一共有两个程序,其中客户端负责运行用户命令远程控制服务器,服务器是服务进程,负责远程提供容器和资源,这种网络体系允许多用户共享资源。
1.1 docker客户端
docker客户端,就是平时我们输入docker命令的地方(例如:docker build),当我们输入命令之后,底层会转化为rest API发送给服务器,服务端接受请求返回响应。因此,我们构建镜像、创建容器、运行容器等这些工作都是在Docker服务端中完成的,完成后返回给客户端。客户端只是发送指令给服务器而已,不做任何处理。
1.2 docker 服务器
docker服务器,本身是一个服务进程。从下图可以看出,用户如果想要守护进程执行一些任务,只能通过client客户端来发送命令。
用户-客户端-守护进程 关系图
注意: Docker 客户端和服务端可以在同一个宿主机(即,都在本地电脑中),也可以在不同的宿主机,如果在同一个宿主机的话,Docker 客户端默认通过 UNIX 套接字( /var/run/docker.sock)和服务端通信,下图为客户端主机通信图:
注意点1: docker宿主机
宿主机,就是物理机。所以docker的服务器也可以在我们的本地电脑中。注意点2: 宿主机/宿主操作系统/虚拟机的关系
层级结构解析:
1.最低层的Computer Hardware就被称为宿主机,也就是我们的物理机电脑
2.host OS就是物理机上的操作系统,例如windows系统
3.hypervisor 是虚拟机和物理机中间的中介软件,例如vmWare
4.在hypervisor上就可以搭建虚拟机了,guestOS就是一个个虚拟机注意点3:Docker守护进程
进程守护(进程的守护),是用于监控指定的进程,当发现目标进程工作异常时,可以对该目标进程进行控制。如关闭该进程,并重新启动该进程。
守护进程的实现机制: 在守护进程中,守护者对目标进程的管理是利用心跳机制实现的。 目标进程会定时向守护者发送报告(发送心跳),表示该目标进程在正常运行,对外提供相应的服务。 当守护者长时间没有收到目标进程发送的报告(心跳),守护者会认为该目标进程运行异常,守护者会对目标进程进行关闭,然后重新启动该目标进程。
总结:docker架构主要掌握:
1.对docker客户端和服务端的通信关系有大致的了解,对客户端扮演的角色有感性的认知(客户端只是负责发动命令,底层是需要转化通信方式与服务端沟通的)
2.docker build工作原理
docker build的工作原理本质上就是要掌握build的构建流程:
step1: docker客户端会build命令后的上下文目录下所有的文件打包为tar包,发送给docker服务端
step2: 服务端接收到tar包之后,解压得到对应的文件系统,这里的文件系统就是构建上下文,服务端根据dockerfile内部的指令进行镜像的分层构建(构建镜像是在服务端构建的)。
3.docker build的构建上下文
构建上下文,即为docker build中制指定的工作目录
举例1:
项目hello-app的目录如下:
此时进入到helloworld-app 目录执行构建命令:
docker build -t hello-app:1.0 docker
这里的 -t hello-app:1.0是构建镜像的名称:版本号, docker是目录,即helloworld-app/docker文件夹下的所有文件会被打包。但是在客户端发送之前,会先去上下文中目录中寻找 Dockerfile 文件,这里的上下文目录下没有Dockerfile,因此报错:
解决1: 以当前目录为构建上下文路径
而如果指定
docker build -t hello-app:1.0 ., 即当前命令的执行目录为helloworld-app的路径,.表示当前命令的执行路径为构成上下文,且文件系统中存在Dockerfile,可以执行通过。
解决2: 还是以 docker 目录作为构建上下文,但是明确指定 Dockerfile 文件地址
docker build -f Dockerfile -t hello-app:1.0 docker,这里-f指令就是专门用来指定dockerfile文件路径的,-f Dockerfile表示相对路径,即当前路径下的Dockerfile,正好存在file文件
总结:-f dockerfile文件路径 和 构建上下文路径(发送的tar包系统)本质上没有直接联系,可以分开指定dockerfile文件运行特定的构建命令,指定特定的文件目录(文件系统)作为构建上下文。
举例2:
如果我们不指定-f dockerfile文件路径,并且将上下文路径设置为 . 当前路径,即
docker build -t hello-app:2.0 .,
此时,客户端发现没有-f指令,则通过上下文路径作为dockerfile的查找路径,可以找到dockerfile,第一点通过。然后上下文路径打包上下文。发送给服务端。
服务端拿到tar包,执行dockerfile文件,内容如下:
FROM busybox
COPY hello.txt .
COPY html/index.html .
执行到 COPY hello.txt .报错,因为hello.txt文件的查找路径都是上下文系统,即在tar的上下文中查找hello.txt,如下图1所示,hello.txt文件路径因为 上下文/docker/hello.txt,而上下文/hello.txt是找不到的,因此报错(图2)
图1
图2