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

相关推荐
yyuuuzz1 小时前
中小企业出海上云:一次服务器选型踩坑记录
运维·服务器
奇特認1 小时前
kubernetes 微服务
微服务·容器·kubernetes
脚踏实地,坚持不懈!1 小时前
Android 上层卡顿在内核中的反应(基于 Linux v7.2.2)
android·linux·运维
灵晔君1 小时前
【Linux】基础IO(一)——文件、上层C库文件操作、底层linux原生IO
linux·运维·c语言
小五传输2 小时前
聚焦卫健数字化建设 文件传输服务器守护跨机构敏感医疗数据交换
大数据·运维·安全
专注仿真2 小时前
Go操作Kubernetes API
贪心算法·golang·kubernetes
机器人梦想家2 小时前
Debian 12/13 关闭开机图形界面(仅保留命令行)
运维·debian
UseLessQQ2 小时前
云原生 kubernetes 中的service
云原生·容器·kubernetes
大大大大晴天️2 小时前
把湖仓一体放进 K8s:Iceberg、Hudi、Paimon 如何重塑云原生大数据架构
大数据·云原生·kubernetes