Kubernetes之容器
一、容器
1. 简介
容器是一种打包应用及其运行环境的方式,为应用打包所有软件及其所依赖的环境,并且可以实现跨平台部署,它是一系列内核特性的统称。
2. 基本技术
一个应用程序的运行环境的总和(内存中的数据、寄存器里的值、堆栈中的指令、被打开的文件,以及各种设备的状态信息的集合)被称为一个进程。容器技术的核心就是通过约束和修改进程的动态表现,从而为其创造出一个逻辑的“边界”。
容器技术本质上为应用解决了两个核心问题:应用的资源隔离限制和应用的可移植性(即在新的环境中可以直接运行)。
(1)namespace
Linux namespace 机制是为实现容器虚拟化而开发的一套轻量级、高效率的系统资源隔离方案。它对 Linux 系统的所有全局资源进行封装、抽象,每个 namespace 里面的资源对其他 namespace 都是透明的、互不干扰的,每个 namespace 里面的进程只能看到当前所处 namespace 所限定的系统资源,但它们都会以为自己是直接运行在一个系统上的,并且好像拥有独立的全局系统资源一样。
在用 clone 系统调用创建新进程时,设定相关的 flag,就会创建一个对应系统资源的新的 namespace,Linux 的每个进程都包含多种 namespace(如 PID、IPC、mount、network、UTS 等)。
容器在创建容器进程时,就指定了这个进程所需启用的一组 namespace 参数,从而为每个应用进程都创建了一个完全隔离的环境,让每个应用进程都觉得自己拥有整个系统。
(2)cgroup
cgroup 是 Linux 内核中的一项功能,它可以对进程进行分组,并在分组的基础上限制进程组能够使用的资源上限(如 CPU 事件、系统内存、网络带宽等)。
cgroup 技术将系统中的所有进程组织成进程树,树的每个节点都是一个进程组。cgroup 中的资源被称为 subsystem。进程树与 subsystem 进行关联。进程树的作用是将进程分组,而 subsystem 的作用是监控、调度或限制每个进程组的资源。
容器就是通过 cgroup 来为进程设置资源限制的。
(3)rootfs
在 Linux 中有一个 chroot 命令,它的作用就是将进程的根目录变更到指定的位置,通过它可以为容器进程提供一个新的根目录及新的文件系统。为了能够让容器的根目录看起来更像是一个真实的操作系统的目录,一般会在容器启动时在其根目录下挂载一个完整的操作系统的文件系统,这个文件系统就是容器镜像,被称为 rootfs(根文件系统),用来为容器进程提供隔离后运行环境。
rootfs 只是一个操作系统的文件系统,并不包括操作系统内核,同一台宿主机上的所有容器,都共享宿主机操作系统的内核。
容器使用了 rootfs 技术,使得容器镜像中打包的内容不只有应用本身,还包括整个操作系统的文件和目录,实现了应用环境的强一致性。
3. 优缺点
优点:
(1)轻量化:相比虚拟机,镜像更小,构建与启动速度更快,更适合需要批量快速上线和快速弹性伸缩的应用。
(2)细粒度(资源管控):创建容器时可以指定 CPU、内存及 I/O 资源,运行容器时强制执行这些资源限制。
(3)高性能(资源利用率高):容器使用的是操作系统级别的虚拟化机制,以进程形态运行,其性能更接近裸机的性能。
(4)环境一致性:容器实现了操作系统的解耦,打包了整个操作系统以保证应用运行环境的高度一致。
(5)管理便捷性:使应用生命周期管理更加便捷。
缺点:
(1)安全隔离性:容器只是运行在宿主机上的一种特殊进程,因此多个容器之间共享的还是同一台宿主机的操作系统内核,从而大大增加了安全攻击面。
二、Docker
1. 容器运行时
Docker 容器运行时的发展主要经历了以下四个阶段:
(1)使用 LXC 来创建容器。
(2)开发属于自己的 libcontainer 库,可与 Linux 内核功能进行交互,用于容器生命周期管理。

(3)把底层容器管理部分单独剥离出来作为一个底层容器运行时,称作 runC,包含了原来的 libcontainer 库,可以独立于 Docker 引擎。
(4)使用 containerd 作为上层容器运行时,负责容器生命周期的管理,而底层的 runC 容器运行时只负责运行容器。
containerd 向上为 Docker 守护进程提供了 gRPC 接口,屏蔽了底层细节,向下通过 containerd-shim 操控 runC,使得上层 Docker 守护进程和底层容器运行时相互独立。
整体工作流程:

<1>Docker 引擎创建容器并将其传递给 containerd。
<2>containerd 调用 containerd-shim。
<3>containerd-shim 使用 runC 来运行容器——即使容器死亡,containerd-shim 也会保证文件描述符为打开状态。
<4>runC 在容器启动后退出。
2. 镜像
所谓 Docker 镜像,其实就是一个压缩包,这个压缩包直接由一个完整的操作系统的所有文件和目录构成,即包含了这个应用运行所需的所有依赖。
Docker 镜像的制作并没有沿用以前制作 rootfs 的标准流程,而是在镜像的设计过程中引入了层(layer)的概念。用户制作镜像的每一步操作都会生成一个层,整个文件系统的增量机制是基于 UnionFS 的。UnionFS 是 Linux 内核中的一项技术,它将多个处于不同位置的目录联合挂载到同一目录下。而 Docker 就是利用这种联合挂载的能力,将容器镜像里的多层内容呈现为统一的 rootfs 的。在 Docker 中使用的 UnionFS 是通过 aufs 来实现的。
Docker 镜像主要分为三层:
(1)只读层:容器的 rootfs 最下面的五层,以增量的方式分别包含整个文件系统。
(2)可读/写层:容器的 rootfs 最上面的一层,在没有写入文件之前,这个层是空的。可读/写层专门用来存放修改 rootfs 后产生的增量内容,可使用“docker commit”和“push”命令保存这一层的修改。
(3)init 层:这是 Docker/kubernetes 单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等配置信息。这一层的修改只对当前的容器有效,在执行“docker commit”命令时会被忽略。
三、kubernetes 与容器
1. CRI(Container Runtime Interface)
Kubernetes 集群中负责与容器运行时交互的是 Node 上的 kubelet 组件,其交互所依赖的是一个称作 CRI 的远程调用接口,这个接口定义了容器运行时的各项内容和核心操作,比如启动一个容器需要的所有参数。
Kubernetes 并不关心容器运行时是什么(可以是 Docker 也可以是其他),只需确保容器运行时符合 OCI 规范,就可以通过实现 CRI 接入 Kubernetes 中。而具体的容器运行时再通过 OCI(开放容器标准) 规范与底层的 Linux 进行交互,将 CRI 请求翻译成对 Linux 的调用(操作 Linux namespace 和 cgroup 等)。
CRI 接口规范主要定义了两个 gRPC 接口服务:
(1)ImageService:提供了从仓库获取镜像,查看、移除镜像等功能。
(2)RuntimeService:负责实现 Pod 和容器的生命周期管理,以及与容器的交互。
以容器运行时 containerd 为例,CRI 接口规范的工作原理如下:

2. RuntimeClass
RuntimeClass:在一个 Kubernetes 集群中配置并启用多种 Container Runtime,不同类型的 Pod 可以选择不同特性的 Container Runtime 来运行,以实现资源占用或者性能、稳定性方面的优化。
参考:
《Kubernetes 权威指南第 5 版》
分类:
Kubernetes
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)