2.2. 资源管理与 API 群组
在 Kubernetes 里,「资源」不是抽象名词:每一个对象都对应一个带版本号的 HTTP 路径,每一类资源都属于某个 API 群组。理解这层映射,你看 YAML 的方式会从「背字段」变成「查接口」。
- 层级:
L2 · 核心
- 难度:
基础
- 预计:
55 分钟
- 前置:
架构与对象模型、kubectl 基本操作
2.2.1. 你将学到
API 群组、版本与资源发现命令
对象类资源的通用格式与身份字段
命名空间的作用边界
Node 对象的
capacity/allocatable/ Conditions标签选择器语法、
kubectl的两种管理方式与配额基础
2.2.2. API 群组与版本
Kubernetes 的 API 是一棵可发现的树:核心组在 /api/v1,其他组在 /apis/<group>/<version>。
路径 |
典型资源 |
|---|---|
|
Pod、Service、Namespace、Node |
|
Deployment、StatefulSet、DaemonSet |
|
Job、CronJob |
|
Ingress、NetworkPolicy |
版本号代表稳定性:v1alpha1 默认关闭、随时可能删除;v1beta1 默认开启但字段可能变化;v1 向后兼容。升级集群前先查废弃清单——extensions/v1beta1 Ingress 在 1.22 移除,batch/v1beta1 CronJob 与 policy/v1beta1 PDB 在 1.25 移除。
kubectl api-versions
kubectl api-resources --api-group=apps -o wide
kubectl get --raw /apis/apps/v1 | jq -r '.resources[].name'
kubectl explain deployment.spec.strategy --api-version=apps/v1
2.2.3. 对象的通用格式
所有对象类资源都遵循同一骨架:apiVersion + kind 决定类型与版本,metadata 描述身份,spec 是你写的期望状态,status 是控制器写的实际状态。
字段 |
谁写 |
说明 |
|---|---|---|
|
你 |
决定资源类型与版本,创建后不可修改 |
|
你 |
同命名空间内唯一;多数资源支持 |
|
API Server |
对象全生命周期唯一,删除重建会变 |
|
API Server |
乐观锁版本号, |
|
API Server |
|
2.2.4. 命名空间
命名空间是「名称作用域 + 授权边界 + 配额边界」的三合一,不是目录。集群自带 default、kube-system、kube-public、kube-node-lease 四个,最后一个是节点心跳租约,用来减少 Node 状态写入压力。它影响同名资源能否共存、RBAC 授权范围、ResourceQuota 作用域与 DNS 名称 svc.namespace.svc.cluster.local;跨命名空间引用对象必须写全名,NetworkPolicy 默认也只在本命名空间生效。
警告
删除命名空间是异步的
要等其中所有资源(包括 CRD 实例、聚合 API 资源)清理完。卡在 Terminating 时先用 kubectl api-resources --verbs=list --namespaced -o name 逐个确认残留对象,再查 finalizer;直接清空 spec.finalizers 会让残留资源变成孤儿。
2.2.5. 节点资源与 Node 对象
Node 是集群级资源,通常由 kubelet 通过 --register-node 自动注册,node controller 维护状态。spec 里有 podCIDR、taints、unschedulable(对应 kubectl cordon);status 里有 capacity、allocatable、conditions、addresses。capacity 是节点总资源,allocatable 是扣掉 kube-reserved、system-reserved、eviction-hard 后能分给 Pod 的量;调度器只看 allocatable,所以「节点还有内存但 Pod Pending」通常是预留导致的。
Condition |
含义 |
典型影响 |
|---|---|---|
|
kubelet 正常且能上报 |
|
|
内存不足 |
kubelet 驱逐 BestEffort Pod |
|
磁盘或 inode 不足 |
镜像回收、Pod 被驱逐 |
|
CNI 未就绪 |
Pod 网络不通 |
kubectl describe node k8s-node01
kubectl label node k8s-node01 disktype=ssd
节点标签是调度与拓扑的基础:kubernetes.io/hostname、kubernetes.io/os、kubernetes.io/arch、topology.kubernetes.io/zone 由系统维护,自定义标签配合 nodeSelector 与节点亲和使用。
2.2.6. 标签、选择器与注解
标签是「连接对象的线」,选择器是「读这根线的方式」:
kubectl get pods -l app=web,tier=frontend # 等值,多个条件是 AND
kubectl get pods -l 'env!=dev' # 没有该标签的对象也会命中
kubectl get pods -l 'env in (dev,staging)' # 集合
标签参与选择,注解不参与。注解会被工具读取,例如 Ingress 参数、证书签发、变更说明,总量受 256 KiB 限制。生产环境建议统一使用 app.kubernetes.io/name、instance、version、managed-by 这套标准标签,便于 Helm、监控与成本分摊识别。
2.2.7. 用 kubectl 管理资源
声明式:
apply/diff/delete -f,可版本化、可重复,生产推荐;命令式:
create/run/expose,适合临时验证与生成 YAML 草稿;局部修改:
label/annotate/patch/scale/set image,精确变更单个字段;交互修改:
edit,调试可以,但容易与 Git 中的 YAML 冲突。
kubectl create ns demo --dry-run=client -o yaml
kubectl apply --server-side --field-manager=handbook -f ns-with-labels.yaml
kubectl get pods -A --field-selector status.phase=Running -o name
2.2.8. 资源配额与限制范围
ResourceQuota 限制「命名空间总量」,LimitRange 限制「单个对象的默认值与上下限」:
apiVersion: v1
kind: ResourceQuota
metadata:
name: eshop-quota
namespace: eshop
spec:
hard:
requests.cpu: "2"
requests.memory: 2Gi
limits.memory: 4Gi
pods: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
name: eshop-limits
namespace: eshop
spec:
limits:
- type: Container
default: {cpu: 200m, memory: 256Mi}
defaultRequest: {cpu: 100m, memory: 128Mi}
max: {cpu: "1", memory: 1Gi}
配额里一旦出现
requests.cpu或limits.memory,该命名空间内所有 Pod 都必须设置对应字段,否则创建被拒;LimitRange 的
default/defaultRequest在准入阶段先补齐,再接受配额检查,所以两者通常一起用;配额按命名空间独立计算,不感知节点容量。
2.2.9. 动手实验
2.2.9.1. 实验一:命名空间、标签与配额
apiVersion: v1
kind: Namespace
metadata:
name: eshop
labels:
app: eshop
env: dev
kubectl apply -f ns-with-labels.yaml
kubectl get ns eshop --show-labels
kubectl label ns eshop env=staging --overwrite
kubectl apply -f quota-and-limits.yaml
kubectl run web -n eshop --image=nginx:1.27 --labels='app=web,tier=frontend'
kubectl describe quota eshop-quota -n eshop
再创建一个不写 resources 的 Pod,观察 LimitRange 补默认值、配额拒绝超额创建。
2.2.9.2. 实验二:观察 Node 对象
apiVersion: v1
kind: Node
metadata:
name: temp-node.ilinux.io
labels:
kubernetes.io/hostname: temp-node.ilinux.io
spec:
podCIDR: 10.244.6.0/24
kubectl apply -f node-demo.yaml
kubectl describe node temp-node.ilinux.io | sed -n '/Conditions/,/Addresses/p'
kubectl delete node temp-node.ilinux.io
警告
手工创建的 Node 不会带来 kubelet
它只用来理解结构与状态字段:没有 kubelet 注册,会一直 NotReady,node controller 还会给它加污点。实验后立即删除,不要在生产集群模仿。
2.2.10. 验证清单
能说出
apps/v1对应的完整请求路径kubectl explain deploy --api-version=apps/v1能查到字段命名空间标签变更后,
-l env=staging能筛选到它Node 的
allocatable小于capacity,能解释差额来源未写
resources的 Pod 被 LimitRange 补上默认值,超额创建被配额拒绝
2.2.11. 常见问题与排错
现象 |
可能原因 |
排查入口 |
|---|---|---|
|
|
|
|
RBAC 未授权该命名空间 |
|
命名空间一直 |
finalizer 或残留资源 |
|
|
配额已满或字段缺失 |
|
2.2.12. 进阶挑战
用
kubectl get --raw /openapi/v3找出apps/v1的 schema 路径,再用jq提取 Deployment 的必填字段。用
kubectl auth can-i --list -n eshop解释当前用户在该命名空间能做什么、不能做什么。给命名空间加一个
scopes: BestEffort的配额,观察普通 Pod 与 BestEffort Pod 的不同结果。用
--field-selector找出所有spec.nodeName为某节点的 Pod,并解释为什么字段选择器只支持有限字段。
2.2.13. 小结
每个对象都是某个 API 群组、某个版本下的 HTTP 资源,
apiVersion决定路径。对象通用结构是
apiVersion / kind / metadata / spec / status,uid、resourceVersion、generation各有用途;命名空间是名称、授权、配额的三重边界。Node 是集群级资源,调度只看
allocatable;标签负责选择,注解负责携带信息。