知其然,知其所以然
Kubernetes 2026-10-11

CRD 的 CEL 校验:x-kubernetes-validations

在 kind 集群里给 CRD 写 x-kubernetes-validations:跨字段规则 self.min <= self.max 用 fieldPath 把错误挂到 .max,messageExpression 拼出提示,两条违反时一次列出;用 oldSelf 写迁移规则实现 owner 创建后不可改、tier 不能从 prod 降级,新增字段时不执行;没有 maxItems / maxLength 的数组加嵌套遍历规则会让 CRD 创建就被拒(成本超预算 100 倍),连 messageExpression 里的 string(整数) 也会被判超预算。

Kubernetes CRD CEL x-kubernetes-validations 准入 校验 真实验证 动画演示
Kubernetes 2026-10-11

client-go informer:本地缓存和 resync

用 client-go v0.36.1 写一个 ConfigMap informer 并统计它发出的 HTTP 请求:启动用一次带 sendInitialEvents=true 的 WATCH 灌满缓存(LIST=0、WATCH=1);从 lister 读 1000 次只要 60µs 且不产生请求,而直接 GET 100 次要 18.5 秒(客户端限流);WATCH 推送 ADD / UPDATE / DELETE,回调拿到新旧 resourceVersion;resync 每 10 秒对每个缓存对象重放一次 UpdateFunc,新旧 rv 相同,不产生任何 API 请求。

Kubernetes client-go informer lister resync WatchList 真实验证 动画演示
Kubernetes 2026-10-11

workqueue:限速重试和去重

用 client-go v0.36.1 的 workqueue 包做小实验:对同一个 key Add 100 次队列长度只有 1,处理中再 Add 先记为 dirty、Done 之后才重新入队;4 个 worker 绝不会同时处理同一个 key,不同 key 最多并行 4 个;DefaultControllerRateLimiter 对同一个 key 的失败重试按 5ms 翻倍(12 次到 10.24s),Forget 后重置;AddRateLimited 的延迟 50 / 102 / 202ms,AddAfter 精确延迟。

Kubernetes client-go workqueue 限速 重试 控制器 真实验证 动画演示
Kubernetes 2026-10-11

etcd 的 compaction 与 defrag:空间怎么回收

在 kind 控制面的 etcd 上实测空间回收:写 200 个 100KB 的 key 后 dbSize 涨 20.3 MiB;同一批 key 覆盖写 3 遍后 dbSize 79.2 MiB 而有效数据只有约 19.1 MiB,旧版本还能用 --rev 读到;compact 之后旧版本读不到(required revision has been compacted),dbSizeInUse 降到 20.0 MiB 但 dbSize 不变;defrag 才把 dbSize 缩回 20.0 MiB。

Kubernetes etcd compaction defrag MVCC 存储 真实验证 动画演示
Kubernetes 2026-10-11

etcd 里的 key:对象在 etcd 中的路径与编码

在 kind 的 etcd 里直接读 Kubernetes 对象:key 是 /registry/<资源>/<命名空间>/<名字>,CRD 多一段 API 组,节点还在用历史遗留的 minions;内置资源的 value 是以 k8s\x00 开头的 protobuf(ConfigMap 202 字节),CRD 对象是 JSON;API 里的 resourceVersion 就是 etcd key 的 mod_revision;用 etcdctl watch 能看到 create / label 是 PUT、delete 是 DELETE。

Kubernetes etcd 存储 key protobuf resourceVersion 真实验证 动画演示
Kubernetes 2026-10-11

kubeadm 证书:控制平面的 PKI 与有效期

在 kind 控制面节点上读 kubeadm 的 PKI:3 套 CA 有效期 10 年、11 张叶子证书 1 年(364d);apiserver.crt 的 SAN 包含 kubernetes.default…、节点名、10.96.0.1、172.18.0.3、127.0.0.1;admin.conf 是 O=kubeadm:cluster-admins,super-admin.conf 是 O=system:masters;kubelet 客户端证书靠 rotateCertificates 自动轮转,serving 证书自签;kubeadm certs renew apiserver 之后不重启 apiserver 它就在 0.1 秒内出示新证书。

Kubernetes kubeadm 证书 PKI CA 证书续期 真实验证 动画演示
Kubernetes 2026-10-11

kube-apiserver 关键参数:每个参数改变了什么

读 kubeadm 为 kube-apiserver 生成的 28 个参数并按作用分类,再一次改三个:--service-node-port-range=31000-31010 让新 NodePort 分到 31010 而旧的 32326 不动、指定 30050 被拒;追加 AlwaysPullImages 准入后新 Pod 的 imagePullPolicy 从 IfNotPresent 变成 Always,旧 Pod 不变;--anonymous-auth=false 把匿名请求从 403 变成 401;改动需要重启 apiserver(约 42 秒),改回去又用了 75 秒。

Kubernetes kube-apiserver 启动参数 准入控制 NodePort anonymous-auth 真实验证 动画演示
Kubernetes 2026-10-11

imagePullPolicy:IfNotPresent 与 latest

在 kind 里实测 imagePullPolicy:不写时 API Server 按镜像引用补默认值(无 tag / latest → Always,其他 tag 和 digest → IfNotPresent);镜像在本地而仓库连不上时,IfNotPresent 与 Never 能跑,Always 报 ErrImagePull → ImagePullBackOff;本地没有的镜像,IfNotPresent 尝试拉取失败而 Never 直接 ErrImageNeverPull;同一个 tag 在节点上被改指向别的镜像后,IfNotPresent 的两个 Pod 跑着不同的镜像。

Kubernetes imagePullPolicy 镜像 IfNotPresent Always 真实验证 动画演示
Kubernetes 2026-10-11

ImagePullBackOff:原因分类与退避

用一个假的 HTTP 镜像仓库让五个 Pod 各撞上一种拉取失败:连接被拒绝、404 not found、401 Unauthorized、域名解析失败、镜像名格式错误(InvalidImageName),ImagePullBackOff 状态的 message 带着 ErrImagePull 的真正原因;观察 330 秒的重试节奏,ErrImagePull 出现在 1、24、48、103、194 秒,相邻间隔 23、24、55、91 秒,越来越长。

Kubernetes ImagePullBackOff ErrImagePull 镜像拉取 退避 真实验证 动画演示
Kubernetes 2026-10-11

imagePullSecrets:私有仓库认证怎么传给运行时

用一个要求 Basic 认证的假仓库实测 imagePullSecrets:kubernetes.io/dockerconfigjson 的 auths 里 auth 就是 base64(用户名:密码);没有 secret 时仓库只收到不带 Authorization 的请求并报 no basic auth credentials,有 secret 时运行时先探测、收到 401 再带上 puller:s3cret,报错变成 not found(认证通过);给 default ServiceAccount 配置后新 Pod 自动带上;auths 的服务器地址写错、密码错、跨命名空间引用 secret 都会失败。

Kubernetes imagePullSecrets 私有仓库 dockerconfigjson ServiceAccount 真实验证 动画演示
Kubernetes 2026-10-11

标签与选择器:集合式表达式

用 6 个 ConfigMap 实测标签选择器:!= 与 notin 会选中没有该键的对象,逗号是 AND;Deployment 的 selector 必须匹配模板标签、不能为空、创建后不可改,空选择器在 Service(不选)与 NetworkPolicy(全选)里含义相反;标签值最长 63 字符、键前缀必须是小写 DNS 子域名;把 Pod 的 app 标签改掉,Service 的 endpoint 0.1 秒内从 3 变 2,Deployment 补一个新 Pod,被改标签的 Pod 脱离管理但继续运行。

Kubernetes 标签 选择器 matchLabels matchExpressions label 真实验证 动画演示
Kubernetes 2026-10-11

注解与标签:大小限制和用途

在 kind 集群里对比注解与标签:注解总量上限 262144 字节(两个各 150000 的注解也超),标签值最多 63 字节;注解不能用 -l 或 --field-selector 选择;改 Deployment 自身的注解不触发滚动,改 Pod 模板里的注解就会新建 ReplicaSet(rollout restart 的原理);kubectl apply 会把整份配置抄进 last-applied-configuration 注解,约 300 KB 的 ConfigMap 用 client-side apply 因注解超限失败,create 和 server-side apply 成功。

Kubernetes 注解 标签 annotations last-applied-configuration 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号