容器是 Linux 内核两个能力(namespace + cgroup)”打包”出来的产品——本质上是进程隔离 而非虚拟化。本文从内核机制讲到 K8s 调度。
容器的两个内核基础 graph TB
KERNEL[Linux Kernel]
KERNEL --> NS[Namespace 资源视图隔离]
KERNEL --> CG[Cgroup 资源消耗限制]
NS --> N1[mnt:文件系统]
NS --> N2[pid:进程树]
NS --> N3[net:网络栈]
NS --> N4[uts:主机名]
NS --> N5[ipc:进程通信]
NS --> N6[user:用户/UID]
NS --> N7[cgroup:cgroup 视图]
NS --> N8[time:时间]
CG --> CG1[CPU]
CG --> CG2[内存]
CG --> CG3[IO]
CG --> CG4[PID 数]
CG --> CG5[device 访问]
容器 = 一组进程绑定到一组 namespace + cgroup。
namespace:视图隔离 1 2 3 4 5 6 7 8 9 10 11 12 ls -l /proc/$$/ns/ nsenter -t <pid> -n ip addr nsenter -t <pid> -m unshare --net --pid --fork bash
每个 namespace 独立一份资源视图——容器内的 PID 1 是宿主机的 PID 12345。
cgroup:资源限制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ls /sys/fs/cgroup/ mount | grep cgroup2cat /proc/<pid>/cgroupecho "100000 100000" > /sys/fs/cgroup/<group>/cpu.max echo "1G" > /sys/fs/cgroup/<group>/memory.max
cgroup v1 vs v2 1 2 3 4 5 6 7 8 9 10 cgroup v1(2007): - 每个 controller 独立树 - CPU / memory / blkio 各管各的 - 复杂,难统一 cgroup v2(2016+,2022 默认): - 统一树 - controller 在节点上启用 - 内核优化更多 - K8s 1.25+ 默认 cgroup v2
OCI 标准:容器的”协议” 容器市场曾经只有 Docker——后来 OCI(Open Container Initiative)标准化:
graph TB
IMG[OCI Image Spec 镜像格式标准]
RUN[OCI Runtime Spec 运行时标准]
DIST[OCI Distribution Spec 镜像仓库标准]
IMG --> R1[Docker / containerd 镜像]
IMG --> R2[Buildah 构建]
RUN --> R3[runc 默认运行时]
RUN --> R4[crun C 实现]
RUN --> R5[kata-runtime VM 后端]
RUN --> R6[gVisor runsc 用户态内核]
任何符合 OCI 的工具链都可以互操作——这就是容器生态成功的关键。
容器运行时的演进 graph LR
D[Docker 2013] --> D2[Docker + libcontainer]
D2 --> CD[containerd 2017]
CD --> CDV2[containerd 2.x K8s 默认]
D --> RUN[runc 2015 拆出]
CRIO[CRI-O K8s 专用]
Docker 1 2 3 4 5 6 7 8 9 Docker(2013): - 第一个让"容器易用"的工具 - 镜像分层 / Dockerfile / 仓库 - 早期是 daemon 单体 Docker 现状: - 桌面开发仍主流(Docker Desktop) - 服务器运行时已被 containerd 替代 - K8s 1.24+ 不再原生支持 Docker
containerd 1 2 3 4 5 6 7 8 9 10 11 containerd: - Docker 拆出的运行时层 - K8s 默认运行时 - 简洁、稳定、性能好 - Apache 2.0 开源 工具: ctr - containerd CLI nerdctl - 类似 docker CLI 配置文件: /etc/containerd/config.toml
CRI-O 1 2 3 4 5 CRI-O: - Red Hat 主推 - K8s CRI(Container Runtime Interface)专用 - 最小化运行时 - OpenShift 默认
runc / crun 1 2 3 4 5 6 7 8 runc: - Go 实现的 OCI 运行时 - Docker / containerd 默认 crun: - C 实现,启动快 50% - Red Hat 主推 - Podman / CRI-O 推荐
Docker / containerd 实战 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 docker run -d -p 80:80 nginx docker ps docker logs <container> docker exec -it <container> bash docker images docker pull nginx:alpine ctr image pull docker.io/library/nginx:latest ctr run -d docker.io/library/nginx:latest nginx-container nerdctl run -d -p 80:80 nginx nerdctl ps nerdctl logs <container> podman run -d -p 80:80 nginx podman ps
镜像分层 1 2 3 4 5 FROM ubuntu:22.04 # Layer 1 RUN apt update # Layer 2 RUN apt install nginx -y # Layer 3 COPY config /etc/nginx/ # Layer 4 CMD ["nginx", "-g", "daemon off;"]
每个 Layer 是只读 tarball——多容器共享相同 Layer,节省磁盘。
1 2 3 docker image history nginx:latest docker inspect nginx:latest | jq .[0].RootFS
镜像格式:
1 2 3 4 5 6 7 8 9 10 11 12 OCI Image Format: config.json layer1.tar.gz layer2.tar.gz ... manifest.json 仓库: Docker Hub(默认) GitHub Container Registry(ghcr.io) Quay.io 自建: Harbor / Nexus / Artifactory
容器网络 graph TB
NETMODES[容器网络模式]
NETMODES --> M1[bridge 默认 NAT]
NETMODES --> M2[host 共享主机]
NETMODES --> M3[none 无网络]
NETMODES --> M4[overlay 跨主机]
NETMODES --> M5[macvlan 每容器独立 MAC]
NETMODES --> M6[CNI K8s 用]
CNI(Container Network Interface) K8s 网络抽象,K8s 通过 CNI 调用网络插件:
1 2 3 4 5 6 7 8 9 10 CNI plugin 主流: Flannel: 简单,VXLAN Calico: BGP,性能好 Cilium: eBPF,最现代 Weave: 端到端加密 Multus: 多网卡 CNI 适配器 调用方式: K8s 创建 Pod → kubelet 调 CNI plugin → plugin 创建 veth pair / 配置 IP / 路由
Cilium:eBPF-based CNI 1 2 3 4 5 6 Cilium 是 2024-2026 年趋势: - 数据面用 eBPF(不用 iptables) - L3-L7 策略 - 服务网格能力(Cilium Mesh) - 完全替代 kube-proxy - 性能:vs iptables / IPVS 快几倍
Kubernetes 架构 graph TB
subgraph CP["控制面"]
APIS[API Server]
SCH[Scheduler]
CTRL[Controller Manager]
ETCD[etcd 状态存储]
CCM[Cloud Controller]
end
subgraph WK["Worker Node × N"]
KUBELET[kubelet]
KP[kube-proxy / Cilium]
CRI[containerd]
CNI[CNI plugin]
KUBELET --> CRI
KUBELET --> CNI
end
APIS --> KUBELET
CTRL --> APIS
SCH --> APIS
ETCD --- APIS
K8s 核心概念:
1 2 3 4 5 6 7 8 9 10 11 12 13 Pod: 一组容器(共享 net + storage namespace) Deployment:声明式管理 Pod 副本 Service: 负载均衡 + 服务发现 ConfigMap / Secret:配置和密钥 Namespace(K8s 概念,与内核不同): 租户/项目隔离 PersistentVolume: 持久化存储 Ingress: L7 路由 DaemonSet: 每节点一份 StatefulSet: 带状态副本 Job / CronJob: 一次性 / 定时任务 CRD: 扩展资源类型 Operator: 用 CRD + Controller 实现自动化运维
K8s 调度器 graph TB
POD[新 Pod 创建]
POD --> SCH[Scheduler]
SCH --> F1[Filter 过滤不能放的节点]
F1 --> F2[节点亲和 / 反亲和]
F1 --> F3[资源够不够]
F1 --> F4[Taint / Toleration]
F1 --> SC[Score 剩余节点评分]
SC --> S1[资源平衡]
SC --> S2[镜像本地化]
SC --> S3[拓扑分布]
SC --> SEL[选最优节点]
SEL --> KUB[kubelet 启动 Pod]
调度过程:
1 2 3 4 5 6 7 1. 用户提交 Pod yaml → APIs Server 2. APIs 写 etcd 3. Scheduler 读到未绑定的 Pod 4. Filter 阶段:排除不合适的节点 5. Score 阶段:剩下节点打分 6. 选最高分节点,写绑定到 etcd 7. 该节点 kubelet 收到 → 启动容器
调度策略:
1 2 3 4 5 节点亲和(NodeAffinity): "只在 GPU 节点跑" Pod 亲和(PodAffinity): "和 X Pod 同节点" 反亲和(AntiAffinity): "和 X Pod 不同节点" Taint / Toleration: "节点专用,只接受能容忍的 Pod" Topology Spread: "Pod 均匀分布在多个 zone"
kubelet 与 Node Agent 每节点上跑 kubelet:
1 2 3 4 5 6 7 8 9 10 11 kubelet 职责: - 接 APIs Server 的 Pod 创建/删除 - 通过 CRI 调 containerd 启动容器 - 通过 CNI 配置网络 - 通过 CSI 挂载存储 - 心跳上报节点状态 - 健康检查(Liveness / Readiness) - 资源监控(CPU/MEM)上报 systemd 单元: kubelet.service 日志: journalctl -u kubelet
CSI:存储插件 1 2 3 4 5 6 7 8 9 10 11 CSI(Container Storage Interface): - 把存储和 K8s 解耦 - 各厂家实现自己 CSI driver - K8s 不需要硬编码各种存储 主流 CSI: AWS EBS / Azure Disk / GCP PD Ceph CSI(RBD / CephFS) NFS CSI local-path / Longhorn 存储厂家:Pure / NetApp / 戴尔 / 华为 OceanStor
K8s 网络模型 K8s 网络的 4 个要求:
1 2 3 4 5 6 7 8 9 10 1. Pod 与 Pod 之间:不需要 NAT,直连 2. Pod 与 Node 之间:双向直连 3. Node 上有"集群 IP" → Pod IP 的路由 4. Service 提供稳定 VIP 实现方案: - Cilium:eBPF - Calico:BGP - Flannel:VXLAN / Host-GW - 各家云厂家自家网络
Service 与 kube-proxy 1 2 3 4 5 6 7 8 9 ClusterIP(默认): 集群内部 VIP NodePort: 每节点开同一端口,对外 LoadBalancer: 云提供 LB(AWS ELB 等) ExternalName: DNS 别名 kube-proxy 实现: iptables 模式: 规则数随 Service 数线性增(性能差) IPVS 模式: 哈希表,性能好 eBPF(Cilium): 最高性能,规则数 O(1)
可观测:metrics、logs、tracing 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Metrics: - Prometheus + Grafana(标准组合) - kube-state-metrics - cAdvisor(容器指标) - node-exporter(节点指标) Logs: - Fluent Bit / Fluentd(采集) - Elasticsearch / Loki(存储) - Kibana / Grafana(查询) Tracing: - OpenTelemetry(标准) - Jaeger / Tempo(后端)
K8s 在 AI 集群里的角色 1 2 3 4 5 6 7 8 9 10 11 12 13 传统 K8s: 微服务编排 AI K8s: - GPU 资源管理(nvidia-device-plugin) - 多 GPU Pod 调度 - 大模型训练 Pod 间通信(NCCL) - PyTorchJob / MPIJob CRD(Kubeflow) - Volcano / KAI Scheduler(gang scheduling) AI 集群专用 K8s 发行版: Run.ai(NVIDIA 收购): GPU 池化 Kubeflow: ML 平台 Determined AI: 训练管理 KubeRay: Ray on K8s
容器镜像安全 1 2 3 4 5 6 7 8 9 10 11 12 13 扫描镜像漏洞: Trivy: 最常用 Clair: CoreOS 出品 Snyk: 商业 Anchore: 商业 签名 / 验签: cosign: Sigstore 出品 Notary v2: Docker 老的 SBOM(Software Bill of Materials): 软件物料清单 syft: 生成 grype: 检测
容器的几个老坑 坑 1:忘记设资源限制 1 2 3 4 5 6 7 8 resources: requests: cpu: 100m memory: 128Mi limits: cpu: 1000m memory: 1Gi
不设限制就是定时炸弹——某个 Pod 内存泄漏把整节点 OOM。
坑 2:用 latest tag 1 2 3 4 5 6 7 image: nginx:latest → 各节点拉的可能不同版本 → 重启 Pod 后行为变了 → 难追溯 正确: image: nginx:1.26.2 更好: image: nginx@sha256:xxx
坑 3:root 用户运行 1 2 3 4 5 6 securityContext: runAsNonRoot: true runAsUser: 1000 readOnlyRootFilesystem: true capabilities: drop: ["ALL" ]
容器逃逸的第一道屏障——非 root + 只读文件系统。
坑 4:默认 ServiceAccount 权限过大 1 2 3 4 5 6 7 8 默认 namespace 的 default ServiceAccount → 自动挂载 token → 容器内可以 kubectl 操作集群 正确: - 用专用 ServiceAccount - 用 RBAC 限制 - automountServiceAccountToken: false
坑 5:镜像太大 1 2 3 4 5 6 7 8 9 10 11 基础镜像选择: ubuntu:24.04: ~80 MB debian:slim: ~30 MB alpine: ~5 MB distroless: ~20 MB(Google 出品,无 shell) scratch: 0 MB(静态二进制) 镜像越小: - 拉取快 - 攻击面小 - 节省存储
坑 6:忽视健康检查 1 2 3 4 5 6 livenessProbe: httpGet: { path: /healthz , port: 8080 } initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: { path: /ready , port: 8080 }
无健康检查 = 死了的容器还在收流量。
坑 7:节点资源碎片 1 2 3 4 5 6 7 8 节点 64 核,已用 40 核分散在多个 Pod 新建 Pod 要 32 核 → 找不到节点(虽然总剩余 24 核分散) → 调度失败 解决: - bin-packing 调度策略 - HPA / VPA 弹性扩缩 - 节点资源池规划
K8s 多集群和联邦 1 2 3 4 5 6 7 8 9 10 11 12 单集群上限:~5000 节点(API Server 性能瓶颈) 多集群方案: Karmada(华为开源): 联邦标准 Cluster API: K8s 风格管 K8s Rancher / OpenShift: 多集群管理面 Submariner: 跨集群网络 应用: - 跨地域容灾 - 法规合规(数据不能跨境) - 资源池突破单集群上限
云原生 vs 传统 1 2 3 4 5 6 7 8 9 10 11 12 云原生(Cloud Native)特征: - 容器化打包 - 微服务架构 - 声明式 API - 不可变基础设施 - DevOps 流程 - 12-Factor App CNCF(Cloud Native Computing Foundation): - K8s 主家 - 200+ 项目 - 全球云原生标准
一些查询命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 docker ps / nerdctl ps / crictl ps docker inspect <container> docker logs -f <container> docker exec -it <container> sh kubectl get nodes kubectl get pods -A kubectl describe pod <name> kubectl logs <pod> -c <container> -f kubectl exec -it <pod> -- sh kubectl top pods kubectl top nodes kubectl debug node/<node-name> -it --image=busybox kubectl get events --sort-by='.lastTimestamp' kubectl config get-contexts kubectl config use-context <ctx>
一些数字直觉 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 容器启动: 小镜像: 100-500 ms 大镜像(首次拉): 秒到分钟级 Pod 启动(含调度): 普通业务: 1-3 秒 GPU Pod: 5-10 秒(需要 device plugin) K8s 集群规模: 推荐: < 5000 节点 超大: 联邦 / 多集群 K8s 控制面消耗: 小集群: 1-2 vCPU + 4 GB 万节点: 8-16 vCPU + 32-64 GB(etcd 重)
国产云原生 1 2 3 4 5 6 7 8 9 10 11 12 13 14 阿里云 ACK: 深度定制 K8s 腾讯 TKE: K8s + 自家增强 华为 CCE: K8s + 容器服务 青云 KubeSphere: 国产 K8s 管理面(开源) Rancher: 原 SUSE,被广泛用 KubeEdge: 边缘计算 K8s(华为开源) 国产容器引擎: iSulad(华为开源): 轻量容器引擎 PouchContainer(阿里开源): 已停 国产容器仓库: Harbor(VMware / CNCF): 最广泛 Quay: Red Hat
待补充:国产 K8s 发行版的实际部署比例。
小结
容器 = namespace(视图隔离) + cgroup(资源限制)
OCI 标准化让生态健康
containerd 已替代 Docker 成为 K8s 默认运行时
Cilium / eBPF 是 K8s 网络的下一代
K8s 是云原生事实标准,调度器和 CRD 模型是核心
AI 集群有专用 K8s 发行版(Kubeflow / Volcano / Run.ai)
国产 K8s 发行版(阿里 ACK / 腾讯 TKE / 华为 CCE)已成熟
下一篇讲内核内部——调度器、网络栈、文件系统。