1. 引言
Kubernetes 运维中,故障排查与资源管理是日常工作的核心。当 Pod 启动失败、服务无法访问或集群资源分配不合理时,掌握正确的调试手段与资源治理策略至关重要。本文基于实际运维场景,系统讲解临时容器、端口转发、审计日志、HPA 弹性伸缩、Pod QoS 等级、LimitRange 与 ResourceQuota 等核心运维技能,帮助你快速定位问题并规范集群资源使用。
2. 临时容器:进入故障现场的最佳工具
2.1 什么是临时容器
临时容器(Ephemeral Container)是 Kubernetes 提供的一种特殊容器,它可以在现有 Pod 中临时运行,用于完成用户发起的操作,例如故障排查。它的核心价值在于:当应用容器因最小化封装而缺少调试工具时,你可以临时注入一个携带工具的容器,与目标容器共享网络命名空间,从而在 localhost 层面直接访问服务。
特性状态:Kubernetes v1.25 起正式稳定(stable)。
2.2 临时容器的关键特性
临时容器与其他容器的不同之处在于:它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。具体限制如下:
- 无端口配置:ports、livenessProbe、readinessProbe 等字段不允许设置。
- 无资源分配:Pod 资源分配不可变,resources 配置不允许设置。
- 独立创建入口:临时容器通过 API 中的 ephemeralcontainers 处理器创建,不能直接添加到 pod.spec,因此无法使用 kubectl edit 添加。
- 不可变更:临时容器添加到 Pod 后,不能更改或删除。
2.3 临时容器进行服务调试
2.3.1 增加一个临时容器
为了演示这个功能,我们先清理不需要的资源对象,然后创建一个测试 Pod:
bash
# 清理旧资源
kubectl delete pod --all
kubectl delete svc web
kubectl delete netpol --all
创建测试 Pod
kubectl run demo --image=hb.reg.com/library/myapp:1.0 --restart=Never
kubectl get pod
当 Pod 内部的应用出现问题时,正常的排查思路是:首先通过 describe 命令查看事件,确认创建过程是否有明显错误;如果没有,再确认容器运行时是否抛错,即查看镜像前台输出日志;如果日志也无法确认,可能需要检查镜像构建历史,或进入容器测试网络连通性。
但很多应用容器采用最小化封装,删除了 curl、wget 等调试工具。此时临时容器就派上用场了------我们可以注入一个带工具的容器到当前 Pod 内部,与目标容器共享网络命名空间,通过 localhost 直接访问服务:
bash
# 注入临时容器,--target 指定共享进程命名空间的目标容器
kubectl debug -it demo --image=hb.reg.com/library/busybox:1.31.1 --target=demo
进入后查看进程
/ # ps aux
测试网络访问(busybox 无 curl,可用 wget)
/ # wget localhost/index.html
如果指定 -i 或 --interactive 参数,kubectl 会自动挂接到临时容器的控制台。--target 参数指定另一个容器的进程命名空间,这个操作是必需的。
2.3.2 通过 Pod 副本调试
假设线上 Pod 出现问题,但里面有很多重要数据,不敢直接操作。此时可以克隆一个副本,在副本内部进行调试,并在副本上增加调试容器。这与传统 IaaS 体系中克隆虚拟机进行排错、破解密码的思路一致------先在克隆机上验证,成功后再应用到真实机器,避免在原机上操作带来的风险。
bash
# 创建测试 Pod
kubectl run myapp --image=hb.reg.com/library/busybox:1.31.1 --restart=Never -- sleep 1d
克隆副本并注入调试容器
kubectl debug myapp -it --image=hb.reg.com/library/ubuntu:22.04 --share-processes --copy-to=myapp-debug
在副本内查看进程与系统信息
root@myapp-debug:/# ps aux
root@myapp-debug:/# cat /etc/lsb-release
关键参数说明:--copy-to 指定克隆副本名称;--share-processes 允许查看 Pod 中其他容器的进程;--container 可指定新容器名,不指定时 kubectl debug 会自动生成;--attach=false 可防止自动附加。
2.3.3 在改变 Pod 命令时创建 Pod 副本
当容器因命令错误而崩溃时(例如 busybox 镜像执行不存在的 false 命令,导致无前台进程而退出),可以通过克隆副本并修改启动命令来排查原因:
bash
# 创建崩溃的 Pod
kubectl run myapp --image=hb.reg.com/library/busybox:1.31.1 -- false
kubectl get pod
# 状态显示 CrashLoopBackOff,因为没有前台进程
克隆副本并进入调试
kubectl debug myapp -it --copy-to=myapp-debug --container=myapp -- sh
/ # ps aux
这个实验保留了应用的镜像,但修改了默认命令,从而可以在副本中观察进程状态,定位崩溃原因。
2.3.4 在更改容器镜像时拷贝 Pod
当应用升级后出现兼容性问题时,可以通过克隆副本并替换镜像来对比验证。例如从 1.26 升级到 1.27 后发现异常,可以克隆副本并改回 1.26 镜像测试,判断是数据损坏还是新版本兼容性问题:
bash
# 创建测试 Pod
kubectl run myapp --image=hb.reg.com/library/busybox:1.31.1 --restart=Never -- sleep 1d
克隆副本并替换所有容器镜像为 ubuntu
kubectl debug myapp --copy-to=myapp-debug --set-image=*=hb.reg.com/library/ubuntu:22.04
查看副本并进入
kubectl get pod
kubectl exec -it myapp-debug -- /bin/bash
root@myapp-debug:/# ps aux
--set-image=*=ubuntu 中的星号代表所有容器,ubuntu 表示将所有容器镜像替换为 ubuntu。副本保留了默认命令和参数,仅修改镜像,便于对比测试。
2.3.5 在同一个节点上创建 Pod 进行调试
当网络插件或网络策略导致跨节点通信异常时,可以在目标 Pod 所在节点上创建调试 Pod,作为客户端发起测试。如果同节点访问正常而跨节点失败,则基本可以定位为节点间通信问题:
bash
# 查看 Pod 所在节点
kubectl get pod -o wide
在目标节点上创建调试 Pod
kubectl debug node/k8s-node02 -it --image=hb.reg.com/library/ubuntu:22.04 --profile=general
进入后查看节点文件系统(挂载在 /host)
root@k8s-node02:/# cd /host
root@k8s-node02:/host# ls
kubectl debug 会基于节点名自动生成新 Pod 名。节点的根文件系统会被挂载在 /host,调试容器运行在主机 IPC、网络和 PID 命名空间内。Pod 没有特权,因此读取某些进程信息可能失败,chroot /host 也会失败;如果需要特权 Pod,需要手动创建。
3. 端口转发:轻量级服务访问方案
3.1 为什么需要端口转发
集群外部访问服务通常需要借助 Service 或 Ingress,但如果只是临时调试,创建这些对象过于繁琐。此时可以使用 kubectl port-forward 将 Pod 端口映射到本地,快速验证服务可用性。
3.2 基本要求与命令格式
Kubernetes 服务器版本必须不低于 v1.10。命令格式如下:
bash
# 转发 Pod(默认类型)
kubectl port-forward <pod_name> <forward_port> --namespace <namespace> --address <IP 默认:127.0.0.1>
转发 Deployment / ReplicaSet / Service
kubectl port-forward deployment/myapp 28015:80
kubectl port-forward replicaset/myapp-75f59d57f4 28015:80
kubectl port-forward service/myapp 28015:80
不指定物理机端口时,自动寻找未被使用的本地端口
kubectl port-forward deployment/myapp :80
修改监听地址为 0.0.0.0,开启远程访问
kubectl port-forward deployment/myapp :80 --address 0.0.0.0
3.3 实战演示
首先创建测试 Pod 并查看其 IP:
bash
kubectl run myapp --image=hb.reg.com/library/myapp:1.0 --restart=Never
kubectl get pod -o wide
然后执行端口转发。如果报错提示 socat not found,需要先在所有节点安装 socat 并重启 kubelet:
bash
# 安装 socat
dnf install socat -y
# 重启 kubelet
systemctl restart kubelet
转发 Pod 端口到本地 30310
kubectl port-forward myapp 30310:80
默认情况下,端口监听在回环接口(127.0.0.1 和 ::1),只能在当前机器通过 curl 访问:
bash
curl localhost:30310
如果需要在集群外部访问,需要指定 --address 0.0.0.0 绑定所有地址:
bash
kubectl port-forward myapp 30310:80 --address 0.0.0.0
此时在浏览器中访问 http://192.168.10.11:30310 即可。对于 Deployment 控制器管理的多副本应用,同样可以整体转发:
bash
kubectl create deployment myapp --image=hb.reg.com/library/myapp:1.0 --replicas=4
kubectl port-forward deployment/myapp 30310:80 --address 0.0.0.0
curl localhost:30310
3.4 特别说明
kubectl port-forward 目前仅支持 TCP 协议,UDP 协议的支持在 issue 47862 中跟踪。
4. 审计:记录集群操作历史
4.1 为什么需要审计
企业级平台通常需要审计功能,以便在事后确认操作人和错误原因,避免类似事件再次发生。Kubernetes 提供了审计日志(Audit Logs)功能,可以记录对集群资源的操作历史,包括 Deployment、Pod、Service 等资源的创建、更新、删除等操作。审计日志可以配置为输出到文件、发送到远程日志服务器,或集成到安全信息和事件管理(SIEM)系统。
官方文档:https://kubernetes.io/zh-cn/docs/tasks/debug/debug-cluster/audit/
5. HPA 弹性伸缩:应对流量波动的自动扩缩容
5.1 什么是 HPA
HPA(HorizontalPodAutoscaler)是 Kubernetes 的横向 Pod 自动扩缩容组件。它根据 CPU 利用率等指标自动调整 Deployment 的副本数量,帮助集群应对流量波动。hpa 是 horizontalpodautoscaler 的缩写。
5.2 创建 HPA 对象
首先准备一个 Deployment 资源清单,为容器设置 CPU 请求:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: my-container
image: hb.reg.com/library/hpa-example
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 200m
创建 Deployment 后,通过 autoscale 命令创建 HPA 对象:
bash
kubectl autoscale deployment my-deployment --cpu-percent=50 --min=2 --max=10
kubectl get hpa
输出中可以看到:HPA 名称、管理的 Deployment 对象、当前 targets 值(初始为未知)、阈值 50%、Pod 最小个数 2、最大个数 10、当前副本数量 3。
5.3 压力测试演示自动扩缩容
创建 Service 并运行测试 Pod,通过无限循环发起访问来制造压力:
bash
# 查看标签
kubectl get pod --show-labels
创建 Service
kubectl create svc clusterip myapp --tcp=80:80
kubectl get svc
验证访问
curl 10.5.184.5
运行测试 Pod(建议多开两个会话)
kubectl run -i --tty work --image=hb.reg.com/library/busybox:1.0 /bin/sh
无限循环发起访问
/ # while true; do wget -q -O- http://myapp.default.svc.cluster.local; done
持续观察 HPA 状态,可以看到 CPU 利用率不断提升,副本数量随之增加,直到达到上限 10 个:
bash
kubectl get hpa
停止压力测试后,副本数量会逐渐回收。需要注意的是:扩展速度很快,但回收很慢,这是为了应对网络请求的波动,避免频繁扩缩容。
6. Pod QoS 等级:资源压力下的驱逐优先级
6.1 QoS 等级概述
Kubernetes 根据 Pod 中容器的资源请求(requests)和限制(limits)为每个 Pod 分配服务质量(Quality of Service,QoS)等级。当节点资源耗尽时,kubelet 会优先驱逐低等级 Pod。可选的 QoS 等级从低到高依次为:BestEffort、Burstable、Guaranteed。
官方文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-qos/
6.2 BestEffort:无资源保障
BestEffort 等级的 Pod 可以使用未专门分配给其他 QoS 等级 Pod 的节点资源。例如节点有 16 核 CPU 可供 kubelet 使用,其中 4 核分配给 Guaranteed Pod,那么 BestEffort Pod 可以尝试使用剩余的 12 核。
判定条件:Pod 中没有任何容器设置 requests 和 limits。最坏情况下它们可能分配不到任何资源,在需要为其他 Pod 释放资源时会被第一批杀死。
6.3 Burstable:有下限无上限
Burstable 等级的 Pod 有一些基于 request 的资源下限保证,但不需要特定的 limit。如果未指定 limit,则默认其 limit 等于节点容量,允许 Pod 在资源可用时灵活增加资源。只有在所有 BestEffort Pod 被驱逐后,这些 Pod 才会被驱逐。
判定条件:Pod 不满足 Guaranteed 的判据,且至少一个容器设置了内存或 CPU 的 request 或 limit。只要不归属于 BestEffort 和 Guaranteed,均归于此等级。
6.4 Guaranteed:最严格的资源保障
Guaranteed 等级的 Pod 具有最严格的资源限制,最不容易被驱逐。在超过自身限制或没有可抢占的低优先级 Pod 之前,这些 Pod 保证不会被杀死。它们不能获得超出指定 limit 的资源,也可以使用 staticCPU 管理策略独占 CPU。
判定条件:Pod 中每个容器都必须设置内存 limit 和 request,且两者相等;每个容器都必须设置 CPU limit 和 request,且两者相等。
6.5 等级对比与判定规则
单容器 Pod 的判定规则如下:
- CPU 和内存都未设置资源限制时,QoS 等级为 BestEffort。
- CPU 和内存都设置资源限制且相等时,QoS 等级为 Guaranteed。
- 其他情况 QoS 等级均为 Burstable。
多容器 Pod 需要将每个容器的等级合并运算:
- 所有容器等级都是 BestEffort 时,Pod 才为 BestEffort。
- 所有容器等级都是 Guaranteed 时,Pod 才为 Guaranteed。
- 其余情况下 Pod 均为 Burstable。
举例说明:假设 4 个 Pod 同属一个节点,需要释放资源时,驱逐顺序如下------Pod 1 的 Requests 和 Limits 相同,为 Guaranteed;Pod 2 的 Limits 大于 Requests,为 Burstable;Pod 3 未设置资源,为 BestEffort;Pod 4 的 Limits 大于 Requests,为 Burstable。因此最先杀死 Pod 3,然后从两个 Burstable 中选择使用量更高的 Pod 2,其次是 Pod 4,最后才是 Pod 1。
7. LimitRange:命名空间内的资源默认值与范围限制
7.1 为什么需要 LimitRange
通过创建 LimitRange 资源,可以避免为每个容器单独配置资源限制。LimitRange 允许为命名空间指定容器可配置的每种资源的最小和最大限额,并在未显式指定资源 request 时为容器设置默认值。
官方文档:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/resize-container-resources/
7.2 LimitRange 配置示例
yaml
apiVersion: v1
kind: LimitRange
metadata:
name: example-limit-range
spec:
limits:
- type: Pod
max:
cpu: "1"
memory: 1Gi
min:
cpu: "200m"
memory: 100Mi
- type: Container
max:
cpu: "500m"
memory: 512Mi
min:
cpu: "100m"
memory: 64Mi
defaultRequest:
cpu: "200m"
memory: 128Mi
default:
cpu: "300m"
memory: 200Mi
maxLimitRequestRatio:
cpu: "2"
memory: "4"
关键字段说明:defaultRequest 定义默认请求值;default 定义默认最大限制值;maxLimitRequestRatio 定义 limit 和 request 的比值上限。例如 CPU 比值设为 2,若 request 为 200m(20%),则 limit 最大允许 400m(40%),设置为 60% 就会报错。内存比值设为 4,若 request 为 1GB,则 limit 最大为 4GB,设置为 8GB 则不允许。
7.3 实战演示
创建 LimitRange 后,再创建一个未指定资源限制的 Pod,它会自动应用默认值:
bash
kubectl apply -f 1.lr.yaml
kubectl apply -f 2.pod.yaml
kubectl describe pod resource-limited-default-pod
在 describe 输出中可以看到 Pod 自动获得了 Limits(cpu 300m、memory 200Mi)和 Requests(cpu 200m、memory 128Mi)。LimitRange 既可以定义默认资源使用量,也可以限制用户定义资源使用量的范围区间。
8. ResourceQuota:限制命名空间的资源总量
8.1 为什么需要 ResourceQuota
LimitRange 只应用于单个 Pod,而集群需要一种手段限制命名空间中的可用资源总量,这就是 ResourceQuota(资源配额)。ResourceQuota 限制了一个命名空间中 Pod 和 PVC 存储最多可使用的资源总量,同时限制用户在该命名空间中可创建的 Pod、PVC 及其他 API 对象数量。
官方文档:https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/
8.2 ResourceQuota 配置示例
yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: test-resources-rq
namespace: test
spec:
hard:
requests.cpu: "20"
requests.memory: 100Gi
limits.cpu: "40"
limits.memory: 200Gi
pods: "1"
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
当特定资源配置了配额后,Pod 中必须为这些资源指定 request 和 limits,否则 API Server 不会接受创建 Pod 的请求。
8.3 实战演示
创建 ResourceQuota 后,在 test 命名空间创建 Deployment 并尝试扩容:
bash
kubectl apply -f 5.rq.yaml
kubectl create -f 6.deploy.yaml
kubectl get pod
kubectl get resourcequota -n test
尝试扩容到 5 个副本
kubectl scale deployment myapp --replicas=5 -n test
扩容命令虽然提示成功,但由于 pods 配额限制为 1,实际副本数不会超过限制。查看 resourcequota 可以看到当前使用量,例如 pods: 1/1、requests.cpu: 200m/20 等。最后删除资源释放配额:
bash
kubectl delete -f 4/
kubectl delete -f 5.rq.yaml
9. 总结
本文系统梳理了 Kubernetes 运维中的核心技能:临时容器为故障排查提供了进入运行中 Pod 的轻量通道;端口转发简化了临时服务访问;审计日志保障了集群操作的可追溯性;HPA 实现了基于负载的自动扩缩容;Pod QoS 等级决定了资源压力下的驱逐优先级;LimitRange 与 ResourceQuota 分别从单 Pod 和命名空间维度规范了资源使用。掌握这些工具,能够显著提升集群的运维效率与稳定性。