Kubernetes 运维实战:临时容器、端口转发与资源管理详解

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 和命名空间维度规范了资源使用。掌握这些工具,能够显著提升集群的运维效率与稳定性。

相关推荐
虎头金猫2 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
AI职业加油站2 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
此冬歌咏2 天前
K8s 节点故障实战:优雅驱逐 31 秒,硬故障 331 秒,以及那个永远 Pending 的 Pod
运维·k8s
-梅2 天前
linux(8) 软硬链接
linux·运维·服务器
赵文宇(温玉)2 天前
CoreDNS的hosts插件的缺行配置导致k8s集群异常
容器·kubernetes·rancher
guo_wen_qiang2 天前
上传本地镜像到harbor中
docker·容器·持续部署
张洛闻Eren2 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
布裘2 天前
【银河麒麟】V4桌面图标消失,右击鼠标没反应排查
运维·银河麒麟·桌面环境
懂软件的胡子个哥2 天前
微信机器人为什么需要“回复候选”而不是所有 AI 内容直接发送
运维·微信·自动化·wechatapi·个人微信号二次开发