docker入门:提问式一条龙式夯实基础!

0x01.首先,为什么需要docker?如何理解docker?

给出一个场景:如果要打开许多网站给不同客户来使用,
那么我们采用什么方式实现呢?
须知打开一台虚拟机需要几个GB,而且还很慢,许多台虚拟机更是恐怖如斯。
全部放在主机上更不可取,依赖冲突直接崩掉。
但是仔细想想🤔,用户分配到的是一台电脑?一台虚拟机?进程呀!那么我们直接把一个进程隔离掉使相互之间不冲突、互相影响,包装成一个“电脑”,这样就可以“骗”到用户了。
docker容器本质就是进程级别的隔离,把一个或多个普通的linux进程(一个进程集合)经过Namespace和Cgroups隔离和限制,包装成一个“小电脑”,一个只需几十MB,秒级启动。
同样是隔离,和虚拟机不同的是,容器只隔离进程,直接共享宿主机内核,而虚拟机是完全独立的内核,这就是二者很大的区别。

同时容器也带来一个隐藏的好处:一台物理机上,如果进程列表中有nginx进程,python进程,它们共享一个网络端口空间,如果它们都需要8080端口,那么就很难受了。直接用容器打包隔离起来我们就可以实现资源隔离,实现互不干扰。

0x02.docker基本逻辑是什么?
不妨先回归基础,理解docker世界的三大基石。

1)镜像(Image): docker的镜像我们可以类比进程镜像来理解。
一个进程肯定包含各种数据对吧?磁盘上存着该进程对应的各种可执行文件,里面包含着代码段,数据段...而这些都是进程运行时所需的,全是一堆静态的、等待加载的二进制数据。
镜像就是磁盘上这些可执行文件的总和。可以想象成买回家存在冰箱里的食材,进程就是这些食材入锅后成为的食物。
docker镜像同理,就是打包好的完整环境,等待运行。
学过进程镜像我们都知道,进程镜像是分层的。那么,docker镜像是不是也分层呢?

是的,大致可分为3层,每一层都只读不能写、改。

底层:linux基础层
提供/etc,/bin等目录、系统库、基础环境,基本命令行工具(这些就是系统文件结构)

中间层:Nginx软件层
在linux纯净的基础层上,通过apt install nginx 或源码编译,存入Nginx可执行文件、配置文件、依赖库。

最上层:业务代码/网页层
将代码、静态文件、配置拷进去
可进一步细分为不可写层、可写层。

注:我们对容器所有的操作都在这一层,比如写入日志,修改配置文件,甚至删除容器也是只是去掉这一层中用户写入部分,下面两层毫发无损。
只读层原件不可改,想修改,只会是内核从只读层拿出复制品供你修改。这就是写时复制思想。

从分层结构来定义容器就是,容器=镜像层(基础linux层,Nginx层,包括最上层中的拷贝网页文件)+可写层(最上层用户写入部分)。
那么,为什么要分层?
这里涉及计算机系统的一个设计哲学:

共享与复用机制。

举一个例子,简单阐明:假如我们有两个进程,它们都需要ubuntu 22.04这个共同的镜像。
如果没有分层机制,我们需要下两个ubuntu,但是使用分层机制,我们可以复用,一个ubuntu就够用了。

2)容器(Container):就是镜像运行后的动态运行时例。
就像上文例子中锅里的食物。

3)仓库(Register):顾名思义,存东西的地方。存什么呢?镜像。
镜像不是存在磁盘里吗?但是就像食材,一开始就在冰箱里吗?也是先从商店里买回来吧。这里的商店对应着就是仓库。

所以,基本逻辑就是:从仓库里得到镜像放在你的磁盘里,运行时从磁盘里取出加载到内存里成为容器。

0x03.docker是怎样工作的?

我们用的docker命令,本质上是一个客户端(CLI),真正为进程干活的并非docker,而是后台的dockerd(docker daemon的缩写,deamon是守护进程的意思),二者通过unix套接字/var/run/docker.sock(本机文件系统上的一个特殊文件)来通信。
(套接字:不同进程进行通信的通道,传递指令和结果。为什么是unix而不是linux?因为这项技术本身是unix系统发明的)

工作流程是: user敲docker run → Docker客户端→发送指令给dockerd→dockerd管理镜像、容器、网络、存储
学过OS的同学说说,这是什么架构?
显然是C/S(客户端/服务端)架构
客户端docker:我们直接打交道的命令行程序
服务端dockerd:在后台长期运行的守护进程,管理镜像,容器,网络,存储。

这里需要注意的是,docker客户端进程,dockerd守护进程属于两个进程,前者属于属于docker run/docker ps时的宿主机上临时启动进程,执行完就退出,后者是宿主机上常驻后台的Docker服务主进程,是容器的创建者和管理者,它们都不是容器进程。

0x04.那么,真正的容器进程是怎样的?

上文提到,容器就是被隔离、限制资源的进程集合。
视图隔离由Namespace决定,资源限制由Cgroups决定。
Namespace:给进程划定边界,划定在指定区域内,实现该进程看不到外界,外界也看不到它。
linux中有6种核心的Namespace(重在理解而非死记硬背):
1)PID Namespace:
容器中进程PID从1开始独立编号,容器内看不到宿主机进程,但宿主机能看到容器(否则你就驾驭不了容器了)
2)Network Namespace:
容器有独立的网卡、IP、端口、路由表,不和主机互通(否则无法模拟新的“电脑”)
或问:一台主机不就1-2张网卡吗?哪里有多余的网卡分配给容器?注意这分配的不是物理网卡,而是通过linux内核网络虚拟化的虚拟网卡。这个了解即可。
3)Mount Namespace:
容器有自己独立的文件挂载目录,看不到宿主机的根目录完整结构
4)User Namespace:
容器内root管理员,在宿主机里是普通用户,降低权限风险(可以看成容器的root是宿主机root的客人,容器的root对容器有所有权,但是宿主机上的东西不是你容器的,你不能同时当宿主机的root)
5)IPC Namespace:
容器内进程间通信独立,不能直接和宿主机通信(至关重要!如果不隔离,禁止互通,黑客入侵了容器,拿到容器权限后直接连接宿主机所有进程,读取宿主机文件,篡改系统,拿服务器最高权限...)
6)UTS Namespace:
容器有独立主机名,域名,与宿主机互不干扰
Cgroups:
本质就是限制进程对硬件资源的使用上限
比如:
占用CPU情况,
内存使用量,
磁盘读写速度,
最大网络带宽。

Namespace和Cgroups组成容器最底层的核心技术,务必掌握

0x05.讲了这么多,该讲docker指挥系统了

讲讲重要名词:
1)docker-ce(docker社区版引擎)
即docker community Edition,
ubuntu上apt install docker-ce装的就是它。
这是一个很大的概念,我们可以把它拆解成三大项:
docker-ce = dockerd + docker-cli + containerd与runc,下面一一讲起
2)dockerd
docker Daemon(Daemon:守护进程)
Docker早期顶层核心服务,属于Docker Engine 上层服务,工作是:
1.常驻后台,自启动
2.统一管理镜像、容器、网络、存储、端口映射
3.接收docker-cli的请求
4.向下调用containerd,由containerd指挥runc造容器

3)docker-cli
Docker Command Line Interface(docker命令行)
我们敲命令docker run、docker ps、docker pull就是它在运行,是纯客户端
它没有别的功能、权限,仅仅是
接收用户输入的命令→把命令组装成请求→通过/var/run/docker.sock套接字(上文讲过,就是进程间的通信通道)发给dockerd
→运行。
是个短命进程,返回结果就退出,且它完全依赖dockerd

4)containerd
container Daemon:容器运行时。命名方式和dockerd一样,但如果翻译成守护进程不太合适,我个人会看成容器大管家。
它的工作内容也佐证这一点:
1.接收到dockerd相关指令后,对容器进行创建、启动、停止、删除
2.管理容器生命周期、镜像解压、文件系统挂载
3.再往下调用runc(马上讲)

它可以屏蔽系统差异,专门负责容器生命周期。它的存在主要是为了标准化,kubernetes可以直接调用它而跳过dockerd

5)runc
Runtime for Containers,
是最低层、最贴近linux内核的轻量工具,完全遵循容器标准。

还记得我们上文讲的Namespace、Cgroup嘛?谁来实现?就是runc。
runc的工作是:
1.创建Namespace隔离(进程/网络/文件系统)
2.配置Cgroups资源限制(CPU/内存上限)
3.拼接挂接层、启动容器里的业务进程

显然,更合理的说法是containerd 负责“指挥”runc造容器,而不是containerd造容器
runc怎么造容器呢?调用linux内核来完成。所以从容器创建的角度去定义容器,可以是:容器本质=runc+内核隔离技术

好,部件讲完了,以容器创建为例将这些部件一条龙串下来:
用户输入命令 → docker-cli (命令行客户端)→ dockerd(docker的顶层守护进程) → containerd (容器生命周期管理)→ runc(底层内核工具) → linux内核(Namespace + Cgroup + 挂载)

image

下期我们再见!

posted on 2026-04-30 12:28  richu  阅读(39)  评论(1)    收藏  举报