Zhonghui

每个不曾起舞的日子,都是对生命的辜负

User Tools

Site Tools


程序:操作系统:虚拟化和容器化

虚拟化和容器化

本篇笔记比较关注概念的辨析,大量参考了AI输出的内容,细节之处可能有些许错误


虚拟化

模拟一个完整的操作系统(也就是虚拟机)

硬件虚拟化

要实现虚拟机,首先需要硬件支持虚拟化

  • CPU虚拟化:
    • 同构:
      • 全虚拟化(Binary Translation):指令翻译,性能开销大
      • 硬件辅助虚拟化:VT-x/VMX(Intel)或 AMD-V/SVM(AMD)
      • 半虚拟化:
    • 异构(比如在Arm上模拟AMD64):
      • 用指令翻译器

内存虚拟化、IO设备虚拟化、网络虚拟化等,也要同步进行

软件虚拟化

KVM(Linux 内核)、Microsoft Hyper-V、VMware ESXi

共同点

  1. 本质上都是 hypervisor,用来运行隔离的虚拟机
  2. Hypervisor(虚拟机监控器)是位于硬件/宿主系统与虚拟机之间的一层系统软件,负责把 CPU、内存、I/O 等虚拟化并调度给每台虚拟机,让它们各自以为“我独享一台真机器”。
  3. KVM、Microsoft Hyper-V都直接消费硬件虚拟化(VT-x/AMD-V等)。

区分

  1. KVM(在 Linux 里):KVM 是 Linux 内核里的功能。装上 Linux → 加载 KVM → 用 QEMU/libvirt 去创建/运行虚拟机(Linux/Windows 都可以)。
  2. Microsoft Hyper-V:是一层 独立的 hypervisor 在最底下;Windows 本身作为“父分区”负责管理。
  3. VMware ESXi:是 VMware 的 裸金属 hypervisor/小型操作系统,直接装在服务器上。
[硬件]
  └─ Linux 内核 (含 KVM)
       └─ QEMU/管理层进程
            └─ 来宾OS(各虚拟机)

[硬件]
  └─ Hyper-V hypervisor
       ├─ 父分区(Windows,用来管理)
       └─ 子分区(各虚拟机)

[硬件]
  └─ ESXi (VMkernel)
       └─ 各虚拟机(集中管理通常用 vCenter)

分类

  1. Type-1(裸金属 / native)
  2. Type-2(托管 / hosted)
  3. 根据虚拟化的等级划分的类别,还不太理解细节
  4. AI:Type-1 往往更接近硬件、少一层依赖;Type-2 可能多绕宿主 OS 一层
# Type-1(裸金属)示意:
[硬件] ── Hypervisor ── [VM1][VM2][VM3]  (每台VM里都有各自的内核/OS)

# Type-2(托管型)示意:
[硬件] ── 宿主OS ──(应用形式的) Hypervisor ── [VM1][VM2]

容器化

容器化实际上不需要硬件支持虚拟化,容器必须共享宿主机的“同一种内核”
因为:容器实际上只是一个特殊进程,容器共享内核,本质是“进程级隔离”,而不是硬件虚拟化。
一般来说,我们跑的都是基于Linux的容器,所以一般需要一个Linux内核(也就是说,宿主机需要是Linux)。

OCI

OCI(Open Container Initiative):一种容器的标准

Docker结构

几乎是容器化的标准,非常常见和有名。

Docker是如何运行容器的?AI:不虚拟硬件。靠 namespaces 隔离视图(PID/网络/挂载等),cgroups 管资源,LSM/seccomp 做系统调用限制,overlayfs 管镜像分层;containerd→runc 用 clone/unshare/chroot 在同一个 宿主内核 下创建受限进程。

Docker是分为「客户端」和「服务器」两个部分的,服务器就是Docker的守护进程Docker Daemon。

docker CLI > Docker Daemon (dockerd) > containerd > runc(OCI 运行时)
  1. docker CLI
    1. 处理用户输入的命令(如 `docker run`)。
  2. dockerd(Docker Daemon)
    1. Docker 的守护进程,负责接收 CLI 请求、调度任务、构建镜像、管理网络/存储等。
    2. 是一个中心化的守护进程,需要 root 或 root-equivalent 权限。
    3. 这是早期 Docker 的“核心大脑”。(为什么是早期?)
  3. containerd
    1. 一个专注于容器生命周期管理的守护进程,负责“创建、运行、销毁”容器,属于运行时中间层。
  4. runc
    1. 最底层的 OCI 容器运行时,负责真正调用 Linux 内核(namespaces、cgroups、chroot)来启动容器进程。
    2. runc 遵循 OCI(Open Container Initiative)标准,成为容器运行的“最小单元”。

Podman结构

Podman 是一个开源的容器引擎,用来运行、管理和构建容器与容器镜像。它的全称是 Pod Manager,由 Red Hat 维护,设计理念和 Docker 类似。但是无守护进程,直接通过 libpod 调用 runc/crun。

# 本地用 Podman
Podman CLI > libpod > conmon > runc/crun

# 在 Kubernetes 里
kubelet > CRI-O > conmon > runc/crun
  1. CRI-O请参照下面的CRI的部分
  2. runc / crun:都属于 OCI 运行时,负责和 Linux 内核打交道(namespaces、cgroups 等),按规范创建/启动/停止容器进程。两者可以互换,CRI-O 可以配用其中任意一个。

Docker 和 Podman 的总结

  1. 两者都遵循 OCI(Open Container Initiative)标准。
  2. 都可以运行同样的容器镜像(例如 Docker Hub 上的镜像,使用的镜像是相同的)。
  3. 底层运行时可以相同(例如都用 runc),只是管理方式不同。

CRI

CRI (Container Runtime Interface) 是 Kubernetes 定义的一套 容器运行时标准接口

  1. 它的作用是让 Kubelet(K8s 节点管理进程) 可以通过统一接口调用不同的容器运行时。
  2. 这样,Kubernetes 就不需要关心底层运行时是 containerdCRI-O 还是其他,只要实现了 CRI,就能被 K8s 使用。
  3. 所谓 原生 CRI,指的是那些 直接实现了 CRI 标准 的运行时,无需额外兼容层。
  4. 原生 CRI:containerd、CRI-O —— 直接符合 Kubernetes 的标准接口。
  5. 非原生 CRI:Docker、Podman —— 需要通过额外的兼容方式才能被 K8s 用。
  1. CRI-O
    1. Red Hat 主导,专为 Kubernetes 设计,轻量化
    2. CRI-O 是 Kubernetes 的 CRI 实现,负责衔接 kubelet 与 OCI 运行时(如 runc、crun/等)
  2. containerd
    1. 由 Docker 拆分出来,现在是 CNCF 毕业项目,K8s 默认推荐
  3. Mirantis cri-dockerd
    1. 为 Docker 提供 CRI 支持,但属于兼容层,不算“原生”
  1. Kubelet 只会通过 CRI 与“容器运行时”对话。
  2. 所以:containerd / CRI-O:原生实现了 CRI → K8s 可直接用
  3. Docker Engine(dockerd):原生实现 CRI → 需要“转接头”(shim)。
  4. Podman 与 CRI-O 共享底层积木(conmon、runc/crun、libpod)。
  5. 但 CRI-O 是给 K8s 用的 CRI 实现,而 Podman 是本机容器引擎,不能作为 kubelet 的运行时。

容器编排和Kubernetes

Kubernetes(调度/服务发现/扩缩容/滚更)几乎就等于行业标准。
Docker 和 Podman 都能与 Kubernetes(K8s)一起使用(或者说它们的底层都和 K8s 兼容,而不是直接兼容)。
K8s 标准化后,要求运行时符合 CRI(Container Runtime Interface),而 Docker 本身并不是原生 CRI 实现。于是Kubernetes 不再直接支持 Docker 作为运行时。(如果还想在 K8s 上用 Docker,需要借助 cri-dockerd 这个兼容层。)在生产环境中,更常见的是使用 containerd(Docker的底层)或 CRI-O(Podman的底层)作为 K8s 运行时。

镜像兼容和容器兼容

  1. 镜像兼容(OCI)≠ 运行时接口兼容(CRI)。
  2. 用 Docker 构建/推送的镜像,K8s(无论用 containerd 还是 CRI-O)都能跑——这是镜像层面的兼容;
  3. K8s 能不能把 Docker Engine 当运行时直接管控,取决于有没有 CRI 适配层(现在是 cri-dockerd)。
  4. K8s 管不了你手动 `docker run` 启动的容器。
    1. Kubernetes 只管理它自己通过 kubelet→CRI(containerd/CRI-O 或 cri-dockerd) 创建的容器/Pod。外部用 Docker CLI 启起来的容器,K8s 不会“接管/收养”。
  5. 但 K8s 可以用“同一份镜像”在它自己的上下文里新建容器。
    1. 只要镜像在同一个仓库(或你提供可访问的镜像地址),K8s 会按需拉取并创建新的 Pod/容器。这是“镜像兼容(OCI)”与“运行时管理(CRI)”的区别。

devcontainer

AI:
devcontainer(全名 Development Container)是一套“可复现的开发环境”规范与配置。你把项目需要的系统依赖、语言运行时、工具链、编辑器设置等都写进一个配置里(通常放在仓库根目录的 .devcontainer/),支持的工具(VS Code Dev Containers、GitHub Codespaces 等)就能据此构建并启动一个容器,然后把你的编辑器“接入”到这个容器里进行开发。
Dockerfile 只描述“容器里装什么”;devcontainer 还描述“开发体验”:编辑器扩展与设置、端口转发、工作区挂载、首次初始化命令、非 root 用户、预置特性(Features)等。
起源在微软/VS Code 团队,并由微软主导开源维护(规范与站点、代码仓库都在微软版权或旗下组织名下,许可证为 CC-BY 与 MIT)。同时它是开放的,并被多方实现/支持(如 GitHub Codespaces、Visual Studio、IntelliJ 早期支持、Gitpod、CodeSandbox、DevPod 等)。

杂项

在Windows上使用Docker为什么要用Hyper-V / WSL2?

在Windows上跑 Linux 容器(最常见),你需要一个真正的 Linux 内核,而 Windows 自己不是 Linux 内核,所以在 Windows 上跑“Linux 容器”就得先弄来一个 Linux 内核,这一步通常就要借助 Hyper-V(或基于 Hyper-V 的 WSL2)。Docker Desktop 早年用 LinuxKit 小虚机(Hyper-V),现在主流是 WSL2 后端。WSL2 自己就是在 Hyper-V 虚拟化平台上跑的一个轻量 VM,里面有 Linux 内核。于是:Windows →(Hyper-V 平台)→ WSL2/Linux 内核 → Docker 守护进程 → Linux 容器进程。

容器仍是“进程”,只是这些进程运行在 Linux 内核(虚机里) 上,而不是直接在 Windows 内核上。

参考资料

/var/www/DokuWikiStick/dokuwiki/data/pages/程序/操作系统/虚拟化和容器化.txt · Last modified: 2025/09/22 14:09 by zhonghui