保持工作负载健康:命名空间、资源、配额与探针
通过 request、limit 和配额公平地共享集群,并让 Kubernetes 检测不健康的容器。
集群是一个共享的 CPU 和内存池。没有护栏时,一个贪婪的工作负载可能会饿死它的邻居,而挂起的应用可能会继续接收流量。本指南涵盖应对这两者的工具:用命名空间和配额来划分资源池,用 request 和 limit 来描述每个容器需要什么,以及用探针让 Kubernetes 能判断容器何时不健康。
用命名空间划分集群
命名空间把一个集群拆分为用于团队、应用或环境的独立区域:
kubectl create namespace demo
kubectl get pods -n demo
kubectl config set-context --current --namespace=demo
kubectl get pods -A
除非你另外指定,你的对象会进入 default,可以在命令上使用 -n NAME,或在清单中使用 metadata.namespace。集群自己的组件位于 kube-system。大多数对象是有命名空间的(Pod、Service、ConfigMap、Secret),而有些,如节点和 PersistentVolume,是集群范围的。命名空间是配额和访问规则附着的单位,但它们本身是一种组织边界,而不是强安全边界。一个常见的意外是某个 Pod 似乎消失了,实际上是你把它创建在了另一个命名空间中。请用 kubectl get pods -A 检查。
设置 request 与 limit
每个容器都可以声明它需要什么,以及它最多可以使用什么:
spec:
containers:
- name: web
image: nginx:1.25
resources:
requests:
cpu: 250m
memory: 64Mi
limits:
cpu: 500m
memory: 128Mi
- Request(请求) 是调度器预留的量。Pod 只会被放置在拥有那么多未被占用容量的节点上,并且容器至少能得到这么多。
- Limit(限制) 是硬上限。试图使用超过其 CPU limit 的容器会被限流。超过其内存 limit 的容器会被杀死(
OOMKilled)并重启。
CPU 以核为单位衡量,其中 1000m(毫核)是一整个核,所以 250m 是四分之一个核。limit 不能低于其 request。两者都是按容器设置的,而不是按 Pod。
用 metrics server 观察使用情况
kubectl top 报告实时使用情况,但它需要 metrics server,许多全新的集群缺少它。没有它你会看到 “Metrics API not available”。在 minikube 上:
minikube addons enable metrics-server
kubectl top nodes
kubectl top pods -A
在其他集群上,请从它的项目页面安装 metrics-server。这是找出哪些 Pod 使用资源最多的快速方法。
用 ResourceQuota 和 LimitRange 强制预算
ResourceQuota 为命名空间可以请求或使用的总量设置上限:
apiVersion: v1
kind: ResourceQuota
metadata:
name: demo-quota
namespace: demo
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
pods: "10"
kubectl describe resourcequota -n demo 显示每项限制下已使用的量。一旦总量将超出,新的 Pod 在创建时就会因 “exceeded quota” 错误被拒绝。当某个配额涵盖 CPU 或内存时,该命名空间中的每个 Pod 也必须声明这些 request 和 limit,否则会被拒绝。LimitRange 通过为没有设置自己值的容器提供默认值来避免这一点:
apiVersion: v1
kind: LimitRange
metadata:
name: container-defaults
namespace: demo
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 64Mi
default:
cpu: 250m
memory: 128Mi
添加就绪探针与存活探针
正在运行的容器不一定是能工作的容器。探针让 Kubernetes 可以检查:
- 就绪探针(readiness probe) 决定容器是否应当接收流量。当它失败时,Pod 会从其 Service 的端点中被移除,但不会被重启。用于启动缓慢或暂时过载的情况。
- 存活探针(liveness probe) 决定容器是否仍然存活。在连续失败足够多次之后,kubelet 会重启该容器。
- 启动探针(startup probe) 在慢启动的应用启动期间,让另外两个探针先不生效。
spec:
containers:
- name: web
image: nginx:1.25
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 5
timeoutSeconds: 1
failureThreshold: 3
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
时序字段对每种探针的作用相同。initialDelaySeconds 是容器启动后到第一次检查之前要等待多久,periodSeconds 是检查的频率,timeoutSeconds 是等待回应多久,failureThreshold 是连续多少次失败才算失败。除了 HTTP 请求,探针还可以打开 TCP 连接(tcpSocket)、在容器内运行命令(exec),或使用 gRPC。
保持存活检查简单,并且只关于进程本身。如果存活探针因为数据库宕机而失败,Kubernetes 就会白白重启健康的应用容器,并可能使故障更加严重。就绪探针才是反映依赖关系的合适位置。就绪状态也驱动滚动更新:新 Pod 只有在就绪后才算可用。
你可以在 kubectl describe pod 中看到探针结果,失败会出现在事件中,也可以在 kubectl get pods 中看到,就绪探针失败时会在 READY 列显示为 0/1。
热门指南
-
Kubernetes 是什么,以及它解决的问题 为什么仅靠容器无法继续扩展,以及 Kubernetes 如何把一组机器变成一个平台。 -
Kubernetes 集群如何工作:控制平面与节点 让集群运转的各个组件,以及从 kubectl apply 到运行中的容器之间发生了什么。 -
Deployment:扩缩、自愈与滚动更新 运行一个 Pod 的多个副本,无停机地更新它们,并在发布出问题时回滚。 -
Service:为短暂的 Pod 提供稳定的网络 给 Pod 一个稳定的地址,在集群内外暴露它们,并限制谁可以与谁通信。 -
调试失败的 Pod:describe、logs、exec 与 port-forward 一份可重复的清单,用来找出 Pod 为什么是 Pending、崩溃或没有响应。