cloud-sre

Apple container、Docker 和 Kubernetes 里的 container 到底差在哪

把 Apple container、Docker 和 Kubernetes 放在同一张图里看:谁负责镜像,谁负责启动进程,谁负责 Pod 和集群编排。

Jun 28, 2026
ContainersDockerKubernetesOCImacOS

同样叫 container,Apple 的 container、Docker、Kubernetes 说的其实不是同一层东西。

最容易混淆的是这句话:Kubernetes 里也有 container,但 Kubernetes 并不亲自实现 Linux container。它把 Pod 调度到某台 node 后,由那台 node 上的 kubelet 调 CRI runtime,再由 containerd、CRI-O、runc 这类组件把进程真正跑起来。

Apple 的 container 又是另一条路线。它兼容 OCI 镜像和运行习惯,但在 macOS 上不是复刻 Linux namespace,而是把每个 Linux container 放进一个轻量虚拟机里跑。

文中用语说明

用语含义
OCI imageOpen Container Initiative 定义的镜像格式。Docker、containerd、Kubernetes runtime 和 Apple container 都围绕它工作。
Runtime负责把镜像变成运行中进程的组件。不同语境里可能指 Docker daemon、containerd、CRI-O、runc,或者 Apple container 的 runtime helper。
Namespace / cgroupLinux container 的核心隔离能力。namespace 隔离进程、网络、挂载点等视图;cgroup 限制 CPU、内存等资源。
VM-backed container容器进程跑在 Linux VM 里。对 macOS 这种非 Linux host 来说,这是运行 Linux container 的常见边界。
Pod sandboxKubernetes/CRI 里的 Pod 基础运行环境。它先建立 Pod 的网络等共享边界,再让业务 container 加进去。
CRIKubernetes 的 Container Runtime Interface。kubelet 通过它调用 container runtime。
CNIContainer Network Interface。Kubernetes 用它给 Pod 配网络。

先给结论

如果只看“谁启动了 container 里的进程”,三者可以这样拆:

系统它处在哪一层谁最后启动进程隔离边界
Apple containermacOS 本机 OCI container 工具和运行时host 上的 runtime helper 启动轻量 Linux VM,VM 里的 vminitd 再启动 OCI 进程每个 Linux container 一个轻量 VM
Docker Engine本机镜像、构建、网络、volume 和 container 生命周期工具Docker daemon 通过 containerd/runc 等 runtime 启动进程Linux 上主要是 namespace/cgroup;macOS Docker Desktop 也需要 Linux VM
Kubernetes集群编排系统node 上的 kubelet 调 CRI runtime,runtime 再创建 Pod sandbox 和 containerPod 是调度单位,container 是 Pod 内的进程单元

所以它们不是简单替代关系。

Docker 和 Apple container 更接近“本机运行容器”的层。Kubernetes 是“让一组机器长期按期望状态运行 Pod”的层。

Apple container 是怎么做的

Apple 的 container 是一个 Swift 写的命令行工具和本机服务。它消费和产出 OCI 镜像,所以你看到的体验会接近:

container run alpine uname -a

但它底层不是让 macOS kernel 直接提供 Linux container 隔离。macOS 没有 Linux namespace/cgroup 那套接口。Apple 选择的实现是:每个 Linux container 背后都有一个轻量 Linux VM。

启动链路大致是:

container CLI
  -> container-apiserver
    -> container-core-images / container-network-vmnet / container-runtime-linux
      -> apple/containerization Swift package
        -> macOS Virtualization.framework
          -> Linux VM
            -> /sbin/vminitd
              -> OCI process

这里有几个关键点。

第一,host 侧有 apiserver 和几个 helper。Apple 的技术说明里把 container-apiserver、镜像服务、网络服务、Linux runtime helper 分开描述。CLI 不是直接 fork 出 Linux 进程,而是把请求交给这些服务。

第二,真正的 Linux 边界来自 Virtualization.frameworkapple/containerization 代码里有 VZVirtualMachineInstance,它包装 VZVirtualMachine,配置 Linux kernel 和启动参数。kernel command line 里会指定 init=/sbin/vminitd

第三,VM 里的 vminitd 是这套设计的关键。host 通过 vsock/gRPC 跟它通信,让它在 guest Linux 内部完成 mount、网络、runtime spec 和进程启动。

也就是说,Apple container 不是“macOS 版 runc”。它更像一个面向 OCI 的 macOS 原生 VM-backed runtime。

Docker 的 container 是怎么做的

Docker 的抽象更老也更常见:

docker CLI
  -> Docker daemon
    -> container runtime stack
      -> isolated Linux process

在 Linux host 上,container 的本质是被 namespace、cgroup、mount、capability 等机制隔离起来的普通 Linux 进程。镜像提供 root filesystem 和 metadata,runtime 按 OCI spec 准备环境,最后 exec 业务进程。

在 macOS 上,情况会多一层。因为 macOS kernel 不能直接运行 Linux container,Docker Desktop 需要一个 Linux VM 来承载 Docker Engine 和 Linux container。也就是说,Docker Desktop for Mac 也是 VM-backed,只是它通常是“共享 Linux VM 里跑多个容器”的模型。

这和 Apple container 的关键差异在 VM 粒度:

Docker Desktop for MacApple container
VM 粒度通常一个共享 Linux VM 承载多个 container每个 Linux container 一个轻量 VM
生态Docker CLI、Dockerfile、Compose、registry workflow 成熟Apple Silicon/macOS 原生实验性路线,更贴近 Apple Virtualization.framework
隔离感多个 container 共享同一个 Linux VM kernelcontainer 间 VM 边界更硬
Kubernetes 关系Docker 本身不是 Kubernetes;历史上有 dockershim,现在 Kubernetes 不再内置 dockershim不是 Kubernetes runtime,除非未来额外适配 CRI

所以不要只用“有没有 VM”判断二者差异。macOS 上二者都绕不开 Linux VM;真正不同的是谁管理 VM、VM 的粒度、runtime API 和生态兼容面。

Kubernetes 里的 container 是谁启动的

Kubernetes 的核心对象不是 container,而是 Pod。

一次常见启动链路是:

kubectl apply / controller
  -> API Server 保存 Pod 或 Deployment
    -> Scheduler 选择 node
      -> 目标 node 上的 kubelet 发现需要运行这个 Pod
        -> kubelet 调 CRI runtime
          -> containerd 或 CRI-O 创建 Pod sandbox
            -> runtime 创建并启动业务 container
              -> CNI plugin 配 Pod 网络

在这个链路里,Kubernetes 做的是期望状态和编排:

  • 这个 Pod 应该存在。
  • 它应该有几个副本。
  • 它应该调度到哪类 node。
  • 它失败后要不要重启。
  • 它怎样通过 Service 暴露。
  • 它需要哪些 Secret、ConfigMap、volume 和 service account。

真正创建 container 进程的是 node 上的 runtime stack。

现在的 Kubernetes 通过 CRI 跟 runtime 对话。常见 runtime 是 containerd 和 CRI-O。Docker Engine 不是现代 Kubernetes 的直接默认 runtime;以前 Kubernetes 内置过 dockershim,用来把 Docker Engine 接进 kubelet,但这个组件已经从 Kubernetes 1.24 移除。

Pod 里的多个 container 通常共享同一个网络命名空间,所以它们可以通过 localhost 互相访问。这也是为什么 Kubernetes 要先建 Pod sandbox:sandbox 先占住 Pod 级别的网络边界,后面的业务 container 再加入这个边界。

一个更直观的分层图

把三者放到同一个图里,大概是这样:

Kubernetes
  -> kubelet on each node
    -> CRI runtime: containerd / CRI-O
      -> low-level runtime: runc / crun / VM-based runtime
        -> Linux process

Docker Engine on Linux
  -> dockerd
    -> container runtime stack
      -> Linux namespace + cgroup
        -> Linux process

Docker Desktop on macOS
  -> Docker Desktop VM
    -> Docker Engine inside Linux VM
      -> Linux container process

Apple container on macOS
  -> container-apiserver
    -> container-runtime-linux
      -> Virtualization.framework
        -> one lightweight Linux VM per container
          -> vminitd
            -> OCI process

这张图能解释几个常见问题。

第一,Kubernetes 不是 Docker 的同类产品。Docker 偏本机构建和运行,Kubernetes 偏集群编排。生产里常见的是 Kubernetes 通过 containerd 跑 OCI 镜像,而开发机上用 Docker 或 Apple container 构建和测试镜像。

第二,Pod 不是 container 的改名。Pod 是 Kubernetes 调度和网络共享单位;container 是 Pod 里的运行进程。一个 Pod 可以只有一个 container,也可以有 sidecar。

第三,Apple container 兼容 OCI,不代表可以直接变成 Kubernetes node runtime。要接 Kubernetes,关键不是能不能跑镜像,而是能不能实现 kubelet 需要的 CRI 语义:Pod sandbox、container lifecycle、日志、exec、port forwarding、stats、image service 等。

实际怎么选

如果是在 Mac 上快速跑一个 Linux 镜像,Docker Desktop 和 Apple container 都是候选。Docker 的优势是生态成熟,Compose、BuildKit、registry workflow、团队习惯都在那。Apple container 的看点是每个容器独立轻量 VM、Swift 实现、和 macOS Virtualization.framework 深度集成。

如果是在生产或测试集群里长期跑服务,讨论点就不该停在 Docker 或 Apple container。你需要的是 Kubernetes 这类编排层,以及 node 上稳定的 CRI runtime、CNI、CSI、镜像仓库、监控和发布策略。

如果是在理解“container 到底是什么”,可以记这个边界:

镜像格式是 OCI。
本机运行容器靠 runtime。
集群里运行服务靠 Kubernetes 编排。
macOS 跑 Linux container 必须经过 Linux VM。

把这几层分开后,Apple container、Docker 和 Kubernetes 的关系就清楚很多:它们都围绕 container 工作,但真正负责的层不同。

References

  1. Apple container README: https://github.com/apple/container
  2. Apple container technical overview: https://github.com/apple/container/blob/main/docs/technical-overview.md
  3. Apple containerization README: https://github.com/apple/containerization
  4. Apple containerization VZVirtualMachineInstance: https://github.com/apple/containerization/blob/main/Sources/Containerization/VZVirtualMachineInstance.swift
  5. Docker overview: https://docs.docker.com/get-started/docker-overview/
  6. Docker Desktop Mac settings: https://docs.docker.com/desktop/settings/mac/
  7. Kubernetes Container Runtime Interface: https://kubernetes.io/docs/concepts/architecture/cri/
  8. Kubernetes container runtimes: https://kubernetes.io/docs/setup/production-environment/container-runtimes/
  9. Kubernetes Pods: https://kubernetes.io/docs/concepts/workloads/pods/
  10. Kubernetes dockershim removal FAQ: https://kubernetes.io/blog/2022/02/17/dockershim-faq/