LabHub
学习 学习路径 课程

CKAD — Kubernetes 应用开发者

securityContext、资源、配额、QoS

在 LabHub 中继续学习

目标

能够通过清单规定 Pod 在节点上可以做什么(securityContext、ServiceAccount)以及可以使用多少资源(resources、LimitRange、ResourceQuota),并确认由此如何决定 QoS 类别。

为什么重要

容器默认以 root 身份运行,这是由镜像的构建方式决定的。只要存在一个容器逃逸漏洞,该 root 就可能进一步成为节点上的 root。runAsNonRoot: true 会直接阻止试图以 UID 0 启动的容器,capabilities.drop: ["ALL"] 则会移除内核授予的全部特权。如果 Web 服务器必须监听 80 端口,只需重新添加 NET_BIND_SERVICE。这就是最小权限原则的具体实现。

资源方面应分两层理解。requests 是调度器的语言。只有节点剩余可分配量大于 requests 总和时,Pod 才能调度到该节点,这与实际使用量无关。limits 是节点的语言。CPU 会通过 cgroup 配额节流,内存一旦超出就会 OOMKilled。因此,如果内存 limits 低于实际峰值,Pod 会悄无声息地反复重启。

LimitRange 和 ResourceQuota 必须配套理解。在设置了配额的命名空间中,创建没有 requests/limits 的 Pod 时,创建操作本身会被拒绝。如果只给团队命名空间设置配额,可能导致任何应用都无法启动,因此使用 LimitRange 填充默认值实际上必不可少。

步骤

  1. 创建命名空间 ckad-secure,并在其中创建 ServiceAccount app-sa
  2. 创建 Pod sa-pod。镜像 nginx:1.27serviceAccountName: app-saautomountServiceAccountToken: false
  3. 创建 Pod nonroot。镜像 nginx:1.27,在 Pod 层级 securityContext 中设置 runAsNonRoot: truerunAsUser: 1000fsGroup: 2000
  4. 创建 Pod hardened。镜像 nginx:1.27,容器名称 app;在容器层级 securityContext 中设置 allowPrivilegeEscalation: falsereadOnlyRootFilesystem: truecapabilities.drop: ["ALL"]capabilities.add: ["NET_BIND_SERVICE"]
  5. 创建 Deployment api。副本数 2,标签 app=api,镜像 nginx:1.27;容器的 resources.requestscpu: 100m / memory: 128Miresources.limitscpu: 500m / memory: 512Mi
  6. 创建 LimitRange defaultstype: Containerdefault(limits)为 cpu: 200m / memory: 256MidefaultRequestcpu: 100m / memory: 128Mimaxcpu: "1" / memory: 1Gimincpu: 50m / memory: 64Mi
  7. 创建 ResourceQuota team-quotarequests.cpu: "2"requests.memory: 4Gilimits.cpu: "4"limits.memory: 8Gipods: "10"
  8. 再创建两个 Pod。qos-guaranteed 的 requests 与 limits 均必须为 cpu: 250m / memory: 256Miqos-burstable 只设置 requests,值为 cpu: 100m / memory: 128Mi。两者均使用镜像 nginx:1.27

参考

命名空间与 ServiceAccount

创建命名空间 ckad-secure,并在其中创建 ServiceAccount app-sa

使用 kubectl create serviceaccount 创建。先创建命名空间,再在其中创建 ServiceAccount。

为 Pod 指定 ServiceAccount 并关闭令牌自动挂载

创建 Pod sa-pod。镜像 nginx:1.27serviceAccountName: app-saautomountServiceAccountToken: false

字段名称是 spec.serviceAccountNameserviceAccount 是旧别名)。关闭令牌自动挂载的布尔字段也位于 Pod 规范顶层。

Pod 层级 securityContext

创建 Pod nonroot。镜像 nginx:1.27,在 Pod 层级 securityContext 中设置 runAsNonRoot: truerunAsUser: 1000fsGroup: 2000

spec.securityContext 中的值会应用于整个 Pod。指定卷所有者组的字段只存在于 Pod 层级。

容器层级 securityContext 与 capabilities

创建 Pod hardened。镜像 nginx:1.27,容器名称 app;在容器层级 securityContext 中设置 allowPrivilegeEscalation: falsereadOnlyRootFilesystem: truecapabilities.drop: ["ALL"]capabilities.add: ["NET_BIND_SERVICE"]

capabilities 只存在于容器层级。先全部移除,再仅添加所需能力,就是最小权限原则。dropadd 均为字符串数组。

为 Deployment 指定 requests 与 limits

创建 Deployment api。副本数 2,标签 app=api,镜像 nginx:1.27;容器的 resources.requestscpu: 100m / memory: 128Miresources.limitscpu: 500m / memory: 512Mi

resources 位于容器下。requests 是调度器使用的值,limits 是运行时强制执行的值。CPU 单位 m 表示 1/1000 核。

使用 LimitRange 设置默认值及上下限

创建 LimitRange defaultstype: Containerdefault(limits)为 cpu: 200m / memory: 256MidefaultRequestcpu: 100m / memory: 128Mimaxcpu: "1" / memory: 1Gimincpu: 50m / memory: 64Mi

spec.limits 是数组,每个元素都含有 type。默认 limits 和默认 requests 使用不同的键名,请用 kubectl explain limitrange.spec.limits 确认。

使用 ResourceQuota 限制命名空间总量

创建 ResourceQuota team-quotarequests.cpu: "2"requests.memory: 4Gilimits.cpu: "4"limits.memory: 8Gipods: "10"

spec.hard 是映射,键名包含点,例如 requests.cpulimits.memory。数量限制应像 pods 一样使用字符串值。

综合:按预期创建 QoS 类别

再创建两个 Pod。qos-guaranteed 的 requests 与 limits 均必须为 cpu: 250m / memory: 256Miqos-burstable 只设置 requests,值为 cpu: 100m / memory: 128Mi。两者均使用镜像 nginx:1.27

QoS 不是可直接指定的字段,而是由 requests/limits 组合决定的结果。所有容器的 CPU 和内存 requests 与 limits 都必须相等,才能获得最高等级。使用 kubectl get pod -o jsonpath='{.status.qosClass}' 检查。