在 kind 集群里给 CRD 写 x-kubernetes-validations:跨字段规则 self.min <= self.max 用 fieldPath 把错误挂到 .max,messageExpression 拼出提示,两条违反时一次列出;用 oldSelf 写迁移规则实现 owner 创建后不可改、tier 不能从 prod 降级,新增字段时不执行;没有 maxItems / maxLength 的数组加嵌套遍历规则会让 CRD 创建就被拒(成本超预算 100 倍),连 messageExpression 里的 string(整数) 也会被判超预算。
用 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 请求。
用 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 精确延迟。
在 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。
在 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。
在 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 秒内出示新证书。
读 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 秒。
在 kind 里实测 imagePullPolicy:不写时 API Server 按镜像引用补默认值(无 tag / latest → Always,其他 tag 和 digest → IfNotPresent);镜像在本地而仓库连不上时,IfNotPresent 与 Never 能跑,Always 报 ErrImagePull → ImagePullBackOff;本地没有的镜像,IfNotPresent 尝试拉取失败而 Never 直接 ErrImageNeverPull;同一个 tag 在节点上被改指向别的镜像后,IfNotPresent 的两个 Pod 跑着不同的镜像。
用一个假的 HTTP 镜像仓库让五个 Pod 各撞上一种拉取失败:连接被拒绝、404 not found、401 Unauthorized、域名解析失败、镜像名格式错误(InvalidImageName),ImagePullBackOff 状态的 message 带着 ErrImagePull 的真正原因;观察 330 秒的重试节奏,ErrImagePull 出现在 1、24、48、103、194 秒,相邻间隔 23、24、55、91 秒,越来越长。
用一个要求 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 都会失败。
用 6 个 ConfigMap 实测标签选择器:!= 与 notin 会选中没有该键的对象,逗号是 AND;Deployment 的 selector 必须匹配模板标签、不能为空、创建后不可改,空选择器在 Service(不选)与 NetworkPolicy(全选)里含义相反;标签值最长 63 字符、键前缀必须是小写 DNS 子域名;把 Pod 的 app 标签改掉,Service 的 endpoint 0.1 秒内从 3 变 2,Deployment 补一个新 Pod,被改标签的 Pod 脱离管理但继续运行。
在 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 成功。