应用命名空间资源配额

KubernetesBeginner
立即练习

介绍

之前的实验重点介绍了单个 Pod 和 Deployment 内部的资源请求(requests)与限制(limits)。ResourceQuota 将这一概念提升到了命名空间(namespace)级别。它允许团队或平台所有者设置边界,例如在一个命名空间中可以存在多少个 Pod、可以请求多少 CPU,以及可以限制多少内存。

在本实验中,你将创建一个命名空间 ResourceQuota,检查其硬性限制,观察 Kubernetes 如何拒绝一个未声明所需资源的 Pod,然后运行合规的 Pod,直到命名空间达到其 Pod 数量配额。

准备配额练习命名空间

在此步骤中,你将准备一个干净的命名空间,用于进行 ResourceQuota 练习。

从 /home/labex/project 开始。你将在此目录中编写配额和 Pod 的清单文件。

mkdir -p /home/labex/project
cd /home/labex/project

检查 Kubernetes API 服务器是否可达。如果虚拟机刚启动且节点尚未就绪,请等待几秒钟后再运行该命令。

kubectl get nodes --request-timeout=5s

预期输出包括:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

在创建应用 Pod 之前,请等待集群网络 Pod 处于 Ready 状态。

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

预期输出:

pod/calico-node-... condition met

创建一个名为 ckad-prep-quotas 的命名空间:

kubectl create namespace ckad-prep-quotas

将此命名空间设置为当前上下文的命名空间:

kubectl config set-context --current --namespace=ckad-prep-quotas

确认当前命名空间:

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

预期输出:

ckad-prep-quotas

创建命名空间资源配额

在此步骤中,你将创建一个同时限制对象数量和总请求资源的 ResourceQuota。

pods 配额限制了命名空间中可以存在的 Pod 数量。requests.* 和 limits.* 配额用于跟踪所有匹配的 Pod 所声明的资源请求和限制的总和。当命名空间具有 CPU 和内存请求或限制的配额条目时,新的 Pod 必须声明这些字段,以便 Kubernetes 进行统计。

创建 app-resource-quota.yaml:

cat > app-resource-quota.yaml <<'EOF'
apiVersion: v1
kind: ResourceQuota
metadata:
  name: app-resource-quota
spec:
  hard:
    pods: "2"
    requests.cpu: "400m"
    requests.memory: 256Mi
    limits.cpu: "800m"
    limits.memory: 512Mi
EOF

应用该配额:

kubectl apply -f app-resource-quota.yaml

预期输出:

resourcequota/app-resource-quota created

检查配额。此时,命名空间中没有运行任何 Pod,因此已使用的值应为零。

kubectl describe resourcequota app-resource-quota

预期输出包括:

Name:            app-resource-quota
Resource         Used  Hard
limits.cpu       0     800m
limits.memory    0     512Mi
pods             0     2
requests.cpu     0     400m
requests.memory  0     256Mi

观察被配额拒绝的 Pod

在此步骤中,你将尝试创建一个没有资源请求和限制的 Pod。

这个 Pod 是故意不完整的。由于命名空间配额会跟踪 CPU 和内存的请求与限制,Kubernetes 无法接纳一个省略了这些字段的 Pod。在 CKAD 任务中,识别这种失败非常有用:清单文件本身可能是有效的 YAML,但由于命名空间策略,准入控制仍会拒绝它。

创建 no-resources-pod.yaml:

cat > no-resources-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: no-resources
  labels:
    app: no-resources
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: app
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'sleep 3600'
EOF

尝试应用该清单。末尾的 || true 允许你的 shell 在预期的错误发生后继续执行,以便你可以检查结果。

kubectl apply -f no-resources-pod.yaml || true

预期输出包括:

Error from server (Forbidden): error when creating "no-resources-pod.yaml": pods "no-resources" is forbidden: failed quota

确认 Pod 未被创建:

kubectl get pod no-resources

预期输出包括:

Error from server (NotFound): pods "no-resources" not found

检查配额,确认已使用的 Pod 数量仍为零:

kubectl get resourcequota app-resource-quota -o 'jsonpath={.status.used.pods}{"\n"}'

预期输出:

0

运行合规的 Pod 直到配额耗尽

在此步骤中,你将创建包含资源请求和限制的 Pod,然后观察 Pod 数量配额如何阻止第三个 Pod 的创建。

下面每个有效的 Pod 都请求 100m CPU 和 64Mi 内存,并将自身限制为 200m CPU 和 128Mi 内存。两个这样的 Pod 符合配额要求。第三个 Pod 虽然具有有效的资源字段,但由于命名空间只允许两个 Pod,因此它会被拒绝。

创建 quota-workers.yaml:

cat > quota-workers.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: quota-worker-a
  labels:
    app: quota-worker
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: app
    image: busybox:1.36
    command: ["/bin/sh", "-c", "echo worker-a-ready; sleep 3600"]
    resources:
      requests:
        cpu: 100m
        memory: 64Mi
      limits:
        cpu: 200m
        memory: 128Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: quota-worker-b
  labels:
    app: quota-worker
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: app
    image: busybox:1.36
    command: ["/bin/sh", "-c", "echo worker-b-ready; sleep 3600"]
    resources:
      requests:
        cpu: 100m
        memory: 64Mi
      limits:
        cpu: 200m
        memory: 128Mi
EOF

应用清单并等待两个 Pod 就绪:

kubectl apply -f quota-workers.yaml
kubectl wait --for=condition=Ready pod/quota-worker-a pod/quota-worker-b --timeout=120s

预期输出:

pod/quota-worker-a created
pod/quota-worker-b created
pod/quota-worker-a condition met
pod/quota-worker-b condition met

检查配额使用情况:

kubectl get resourcequota app-resource-quota -o 'jsonpath={.status.used.pods}{" "}{.status.used.requests\.cpu}{" "}{.status.used.requests\.memory}{" "}{.status.used.limits\.cpu}{" "}{.status.used.limits\.memory}{"\n"}'

预期输出:

2 200m 128Mi 400m 256Mi

创建一个具有有效资源的第三个 Pod:

cat > quota-worker-c.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: quota-worker-c
  labels:
    app: quota-worker
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: app
    image: busybox:1.36
    command: ["/bin/sh", "-c", "sleep 3600"]
    resources:
      requests:
        cpu: 100m
        memory: 64Mi
      limits:
        cpu: 200m
        memory: 128Mi
EOF
kubectl apply -f quota-worker-c.yaml || true

预期输出包括:

Error from server (Forbidden): error when creating "quota-worker-c.yaml": pods "quota-worker-c" is forbidden: exceeded quota

总结

你创建了一个命名空间 ResourceQuota,检查了其硬性限制,观察了 Kubernetes 如何拒绝一个省略了必要资源字段的 Pod,并运行了合规的 Pod 直到命名空间达到其 Pod 数量限制。这建立了单个容器资源设置与命名空间级资源治理之间的联系。