Kubernetes Kubernetes

保持工作负载健康:命名空间、资源、配额与探针

通过 request、limit 和配额公平地共享集群,并让 Kubernetes 检测不健康的容器。

15 min 中级

集群是一个共享的 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。

热门指南