
很多人把云计算理解为"把物理机切成虚拟机卖"。这个理解在 2010 年成立,在今天已经严重过时。
现代云的本质是:用 Linux 内核提供的一组隔离、计量、调度与可观测原语,把物理资源切分成可计费、可编排、可自愈的逻辑单元,再用控制面软件把这些单元组织成服务。
拆开看,云的每一层都对应内核的具体能力:
云的能力 | 内核/系统机制 |
|---|---|
租户隔离 | namespaces、cgroups v2、seccomp、IOMMU |
资源计量与计费 | cgroups v2 统计、CPU/内存/IO 压力指标 |
弹性伸缩 | cgroup 动态调整、快速冷启动(微虚机/容器) |
软件定义网络 | netfilter/nftables、tc、veth/bridge、VXLAN、eBPF |
软件定义存储 | device-mapper、NVMe、io_uring、文件系统/对象存储 |
安全与审计 | audit、eBPF tracing、LSM(SELinux/AppArmor) |
性能诊断 | perf、eBPF/bpftrace、PSI、/proc 与 /sys 接口 |
因此,"学 Linux 云计算"的正确顺序不是先学 K8s,而是先理解内核给你了哪些原语、它们的边界在哪。 K8s 只是把这些原语包装成 API 的一层;不理解底层,故障排查就只能靠猜。
Linux 提供 mount / pid / net / ipc / uts / user / cgroup / time 等命名空间。容器的"隔离感"主要来自这里。
1# 新建一个 mount + pid + net 隔离的环境,进去看就是"另一台机器"
2sudo unshare --mount --pid --net --fork --mount-proc bash
3
4# 进去后验证
5echo $$ # PID 可能是 1
6ip a # 只有 lo,没有宿主网卡
7cat /proc/mounts | wc -l关键认知:
cgroup v2 是统一层级(unified hierarchy),所有控制器挂在一棵树上,比 v1 的分散层级更清晰,也是当前主流发行版默认。
1# 创建一个 cgroup 并限制 CPU/内存/IO
2sudo mkdir -p /sys/fs/cgroup/mywork
3echo "+cpu +memory +io +pids" | sudo tee /sys/fs/cgroup/mywork/cgroup.subtree_control
4
5echo 200000 > /sys/fs/cgroup/mywork/cpu.max # 每 100ms 周期最多用 200ms => 2 核
6echo 1073741824 > /sys/fs/cgroup/mywork/memory.max # 1 GiB
7echo 4096 > /sys/fs/cgroup/mywork/pids.max # 防 fork 炸弹
8
9# 把进程放进去(写 PID 而不是 cgroup.procs 的旧写法)
10echo $! | sudo tee /sys/fs/cgroup/mywork/cgroup.procs
11
12# 观察实际用量与压力
13cat /sys/fs/cgroup/mywork/cpu.stat # usage_usec, nr_throttled, throttled_usec
14cat /sys/fs/cgroup/mywork/memory.current
15cat /sys/fs/cgroup/mywork/memory.pressure # PSI:some/full avg10/60/300
16cat /sys/fs/cgroup/mywork/io.stat必须理解的三个点:
cpu.max 是配额不是保证。想保证独占,要用 cpu.weight(相对权重)配合宿主整体负载,或直接做 CPU 亲和绑定(见第六节)。nr_throttled / throttled_usec 是排查"莫名变慢"的第一现场。应用没有报错、CPU 使用率看着不高,但被 CFS 限流了,延迟会呈周期性尖刺。memory.pressure 的 full 表示所有任务都被内存阻塞,这是 OOM 前兆;io.pressure 能提前发现存储瓶颈。云上的自动扩缩容如果只看 CPU 使用率,会漏掉内存与 IO 压力型故障。eBPF 允许在内核中安全运行沙箱化程序,无需写内核模块、无需重启。它同时是观测工具(perf 级采样、系统调用追踪)和数据面引擎(Cilium 用它替代 iptables/iptables 做网络策略与负载均衡)。
1# 一行看谁在频繁触发 OOM kill 前的内存回收
2sudo bpftrace -e 'tracepoint:mm_vmscan:mm_vmscan_direct_reclaim_begin { @reclaim = count(); }
3 interval:s:5 { print(@reclaim); }'
4
5# 追踪某进程的系统调用耗时分布(微秒)
6sudo bpftrace -e 'tracepoint:syscalls:sys_enter_read /pid == 1234/ { @start[tid] = nsecs; }
7 tracepoint:syscalls:sys_exit_read /@start[tid]/ {
8 @us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }'
9
10# 统计 TCP 连接建立(用于判断连接风暴)
11sudo bpftrace -e 'kprobe:tcp_connect { @connects = count(); }
12 interval:s:10 { print(@connects); }'为什么它对云很重要:
代价也要说清:eBPF 程序本身有 bug 可能拖垮内核( verifier 只能保证基本安全,不能保证逻辑正确);调试门槛高;不同内核版本特性差异大(CO-RE 缓解了部分问题)。
1// 极简 seccomp 白名单片段:只允许必要系统调用
2{
3 "defaultAction": "SCMP_ACT_ERRNO",
4 "architectures": ["SCMP_ARCH_X86_64"],
5 "syscalls": [
6 { "names": ["read","write","exit","exit_group","futex","mmap","munmap","brk","rt_sigreturn"],
7 "action": "SCMP_ACT_ALLOW" }
8 ]
9}生产实践:容器运行时默认启用 runtime 内置 seccomp profile(屏蔽 ptrace、mount、reboot、kexec_load 等高危调用);配合 AppArmor/SELinux 做强制访问控制;再配合 user namespace 与 rootless 容器,构成纵深防御。任何一层单独都不够。
方案 | 隔离强度 | 启动速度 | 密度 | 典型场景 |
|---|---|---|---|---|
KVM/QEMU 全虚机 | 强(硬件辅助虚拟化) | 秒~十秒级 | 中 | 多租户强隔离、需跑异构 OS、合规要求 |
Firecracker / Cloud Hypervisor 微虚机 | 强(最小设备模型) | 百毫秒级 | 高 | Serverless、多租户函数、容器逃逸兜底 |
Kata Containers | 强(容器语义 + 虚机隔离) | 亚秒~秒 | 中 | 需要容器生态又要虚机隔离 |
runc / containerd 容器 | 中(共享内核) | 几十~百毫秒 | 很高 | 微服务、CI、绝大多数云原生负载 |
gVisor | 中强(用户态内核拦截 syscall) | 快 | 高 | 不可信代码、在线代码执行 |
几个工程要点:
/、/proc、docker socket)、特权容器、capabilities 过宽、共享宿主 PID/网络命名空间。默认配置 + 最小权限 + 定期内核升级能挡掉绝大多数。1# 检查一个容器是否被过度授权(常见危险信号)
2docker inspect <cid> --format '{{.HostConfig.Privileged}} {{.HostConfig.CapAdd}} {{json .HostConfig.Binds}}'
3# 期望:false / 空 / 不含 docker.sock、/、/proc、/sys1# 查看 conntrack 表使用与是否溢出
2sudo conntrack -S | head
3cat /proc/sys/net/netfilter/nf_conntrack_max
4sudo dmesg -T | grep -i "conntrack: table full"
5
6# 调优(示例,需按并发量评估)
7sudo sysctl -w net.netfilter.nf_conntrack_max=1048576
8sudo sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=900conntrack 表满是高并发服务偶发丢包的经典原因,且只在压力下出现,测试环境很难复现。eBPF 数据面(如 Cilium 的 --disable-conntrack 对部分流量)可以绕开,但要注意无状态转发对某些协议的影响。
Kubernetes 的 NetworkPolicy 是白名单语义:一旦某 Pod 被任意一条策略选中,未被显式放行的流量即被拒绝。
1apiVersion: networking.k8s.io/v1
2kind: NetworkPolicy
3metadata:
4 name: api-only-from-frontend
5spec:
6 podSelector:
7 matchLabels: { app: api }
8 policyTypes: ["Ingress"]
9 ingress:
10 - from:
11 - podSelector:
12 matchLabels: { app: frontend }
13 ports:
14 - protocol: TCP
15 port: 8080常见事故:只写了 Ingress 策略,忘了 Pod 需要访问外部(DNS、对象存储),导致解析失败或调用超时;或者 CNI 不支持策略,YAML 生效但实际不拦截——必须实测验证,不能只看 apply 成功。
1# 验证策略是否真的生效(从非 frontend Pod 访问)
2kubectl run probe --rm -it --image=curlimages/curl --restart=Never -- \
3 curl -sv --max-time 5 http://api-svc:8080/healthz1# 随机读 IOPS(4K,QD 32,模拟 OLTP)
2fio --name=randread --ioengine=libaio --direct=1 --rw=randread \
3 --bs=4k --iodepth=32 --numjobs=4 --size=4G --runtime=60 \
4 --group_reporting --filename=/mnt/data/testfile
5
6# 顺序写带宽(模拟日志/备份)
7fio --name=seqwrite --ioengine=libaio --direct=1 --rw=write \
8 --bs=1M --iodepth=16 --numjobs=2 --size=8G --runtime=60 --group_reporting
9
10# 关注:IOPS、带宽、p99/p999 延迟(不只是平均延迟!)关键提醒:看 p99/p999 而不是平均延迟。云盘在多租户环境下存在"邻居噪音",平均值正常但尾延迟抖动,会直接放大上层服务的超时与重试风暴。
1apiVersion: storage.k8s.io/v1 2kind: StorageClass 3metadata: 4 name: ssd-sc 5provisioner: ebs.csi.aws.com # 换成你的 CSI 驱动 6parameters: 7 type: gp3 8 volumeSizeBytes: "107374182400" 9reclaimPolicy: Delete 10volumeBindingMode: WaitForFirstConsumer # 重要:避免跨可用区绑定 11allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer 几乎是必选项:否则 PVC 会在 Pod 调度前就绑定到某个可用区的盘,Pod 被调度到别的可用区时直接挂不上(跨 AZ 云盘不可挂载)。
其他高频坑:
ReadWriteOnce + 副本时,需要正确的拓扑与反亲和,否则副本挤在同一节点。理解 K8s 只需要抓住一个模式:期望状态(Spec)+ 实际状态(Status)+ 调谐循环(Reconcile Loop)。
1// 极简 Reconcile 骨架(controller-runtime 语义)
2func (r *MyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
3 var obj myv1.Widget
4 if err := r.Get(ctx, req.NamespacedName, &obj); err != nil {
5 return ctrl.Result{}, client.IgnoreNotFound(err) // 已删除,无需处理
6 }
7
8 // 1. 读取实际状态
9 actual, err := r.observe(ctx, &obj)
10 if err != nil {
11 return ctrl.Result{RequeueAfter: 10 * time.Second}, err // 可重试错误:退避重试
12 }
13
14 // 2. 计算差异并收敛(幂等!重复执行结果必须一致)
15 if diff := plan(obj.Spec, actual); len(diff) > 0 {
16 if err := r.apply(ctx, &obj, diff); err != nil {
17 return ctrl.Result{}, err
18 }
19 }
20
21 // 3. 回写状态,供上层与用户观测
22 obj.Status.Ready = actual.Ready
23 obj.Status.ObservedGeneration = obj.Generation
24 return ctrl.Result{}, r.Status().Update(ctx, &obj)
25}三条工程铁律:
生产调度需要考虑:
requests 决定调度与容量规划,limits 决定隔离与限流。只设 limits 不设 requests 会导致调度器误判容量,节点超卖后集体抖动。topologySpreadConstraints)。cpuManagerPolicy: static + 整数核 requests,避免被 CFS 调度和跨 NUMA 迁移影响。1resources:
2 requests: { cpu: "4", memory: 8Gi } # 整数核,配合 static policy
3 limits: { cpu: "4", memory: 8Gi } # Guaranteed QoS1apiVersion: autoscaling/v2
2kind: HorizontalPodAutoscaler
3metadata: { name: api-hpa }
4spec:
5 scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: api }
6 minReplicas: 3
7 maxReplicas: 30
8 metrics:
9 - type: Resource
10 resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
11 behavior:
12 scaleDown:
13 stabilizationWindowSeconds: 300 # 防止抖动
14 policies: [{ type: Percent, value: 25, periodSeconds: 60 }]失效原因清单:
<unknown>,静默不扩容。requests → 利用率无法计算。1应用逻辑 → 运行时(GC/线程池) → 系统调用/IO → 内核调度 → 硬件(CPU/内存/网卡/盘)每一步都要有数据支撑,不要凭感觉调 vm.swappiness。
1# 1. 全局快照:先看是 CPU、内存还是 IO 瓶颈
2vmstat 1 5 # r 列(运行队列)、bi/bo、si/so、wa
3mpstat -P ALL 1 3 # 各核是否均衡,%iowait / %soft
4iostat -xz 1 3 # %util、await、r/s w/s(注意 %util 对 SSD 无意义)
5pidstat -d 1 3 # 定位到进程
6
7# 2. 内存压力与回收
8cat /proc/pressure/memory
9cat /proc/meminfo | grep -E "MemAvailable|SwapTotal|SwapFree|Dirty"
10sar -B 1 3 # pgscan/pgsteal 高说明在回收,可能引发延迟尖刺
11
12# 3. 网络
13ss -s # 连接总数、TIME_WAIT
14ss -ti # 重传、RTT
15ethtool -S eth0 | grep -i -E "drop|error|miss"
16cat /proc/interrupts | head -20 # 中断是否集中在单核
17
18# 4. 内核级定位(有 eBPF 时优先用它)
19sudo perf top # CPU 热点
20sudo offcputime-bpfcc 30 # 阻塞在哪(on-CPU 正常但慢时特别有用)调整 | 适用条件 | 风险 |
|---|---|---|
CPU 亲和绑定 + 关闭 NUMA 自动迁移 | 延迟敏感、整数核分配 | 降低整体利用率弹性 |
透明大页(THP)设为 madvise 或关闭 | 数据库、低延迟服务(THP 整理会导致延迟尖刺) | 大内存应用可能损失吞吐 |
vm.swappiness 调低 + 启用 zswap | 内存紧张但希望避免直接 OOM | 过度调低可能提前触发 OOM killer |
关闭 swap 的容器场景改用 PSI 驱动的驱逐 | K8s 节点 | 需配好 eviction 阈值 |
中断亲和(RSS/RPS)+ 多队列网卡 | 高网络吞吐 | 配置错误反而更慢 |
noatime、合理 readahead | 大量小文件读 | 依赖具体负载 |
io_uring 替代 libaio/同步 IO | 高并发 IO 应用(需应用支持) | 内核版本与安全面考量 |
核心原则:任何调优都要有 before/after 的压测数据与回滚方案。没有基线的调优只是随机游走。
症状:服务周期性延迟尖刺,CPU 使用率不高,日志无异常。
排查路径:
cat /sys/fs/cgroup/<pod>/cpu.stat → 看 nr_throttled 是否持续增长 → CPU 限流(limits 太低或 burst 不足)。cat /sys/fs/cgroup/<pod>/memory.pressure 的 full → 内存回收阻塞。iostat + io.stat 的 await 尖刺 → 存储尾延迟。dmesg 中的 OOM kill / 内核 soft lockup。结论:这类问题的根因 90% 在资源限额设置与真实需求不匹配,而不是内核参数。
一个原则:告警要基于用户可感知的症状(SLO 错误率、延迟分位),而不是基于机器指标。"CPU 80%"不是告警,"p99 延迟超过 500ms 持续 5 分钟且影响 1% 请求"才是。
1# SLO 驱动的告警示例(Prometheus 语义)
2- alert: ApiLatencySloBurn
3 expr: |
4 (
5 sum(rate(http_request_duration_seconds_bucket{le="0.5",job="api"}[5m]))
6 / sum(rate(http_request_duration_seconds_count{job="api"}[5m]))
7 ) < 0.99
8 for: 5m
9 labels: { severity: page }
10 annotations:
11 summary: "5 分钟内 p99 延迟 SLO 达成率低于 99%"多租户/大规模下的额外要求:全链路 trace ID 贯穿网关→服务→数据库;每个租户/服务有独立看板;容量与成本按标签归因。
分层防御清单:
latest 标签。云 IAM 是最常被低估的攻击面:一个过宽的实例角色权限,可能让一次容器逃逸升级为整个账号沦陷。原则是按最小权限拆分角色 + 定期权限审计 + 关键操作二次确认。
度量方式:建立单位业务成本(每千次请求成本、每用户成本),而不是只看账单总额——账单下降可能只是业务量下降。
11. 止血优先:先恢复服务(回滚变更 / 扩容 / 切流量 / 降级),再查根因
22. 界定范围:影响哪些服务/租户/地域?从什么时候开始?最近有什么变更?
33. 分层定位:
4 - 客户端/网关:DNS、TLS、超时、限流
5 - 应用层:错误率、依赖调用、GC、连接池
6 - 编排层:Pod 状态、事件(kubectl describe / get events)、探针失败、驱逐
7 - 节点层:资源压力、磁盘满、内核日志、kubelet 日志
8 - 网络层:Service/Endpoint 是否就绪、策略是否拦截、conntrack、丢包
9 - 存储层:挂载状态、IO 延迟、配额
104. 保留证据:core dump、日志快照、指标截图(在清理前)
115. 复盘:时间线 + 根因 + 检测为什么慢 + 如何防止复发(要落到代码/配置/流程)1# 一组高频有用的 K8s 排查命令
2kubectl get pods -A --field-selector=status.phase!=Running
3kubectl describe pod <pod> -n <ns> # 看 Events:调度失败、镜像拉取、探针
4kubectl get events -n <ns> --sort-by=.lastTimestamp | tail -30
5kubectl top pod -n <ns> --containers # 需要 metrics-server
6kubectl logs <pod> -c <container> --previous # 上一次崩溃的日志
7kubectl debug node/<node> -it --image=busybox # 进节点排障(受限环境)
8journalctl -u kubelet --since "10 min ago"原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。