在 kind 集群里给 CoreDNS 加 log 插件,逐条看 DNS 请求:ndots:5 时解析 example.com 先依次查 example.com.k64.svc.cluster.local、example.com.svc.cluster.local、example.com.cluster.local 三个 NXDOMAIN,最后才查 example.com,A 和 AAAA 共 8 条请求;名字末尾加点只要 2 条;ndots:1 让外部名字变成 2 条,但集群内 s1.k64 变慢;Service 不同写法的请求数从 2 到 8+ 不等。
在 kind 节点上读 iptables-save:一个 Service 在 nat 表里是 KUBE-SERVICES → KUBE-SVC → KUBE-SEP 三层链,后端靠 statistic random 概率(3 个副本 1/3、1/2、无条件)抽签后 DNAT 到 Pod;300 个新连接分到 99/105/96;scale 到 4 个后 1.5 秒规则更新;没有后端时 filter 表写 REJECT,访问立即 Connection refused;NodePort 经 KUBE-NODEPORTS,连接映射由 conntrack 记住。
分别用 networking.kubeProxyMode 起 ipvs 和 nftables 的 kind 集群读内核:ipvs 里 Service 是 /proc/net/ip_vs 的虚拟服务器,rr 轮询把 300 个连接分成 100/100/100,ClusterIP 挂在 dummy 网卡 kube-ipvs0 上;nftables 里是 kube-proxy 表的 map 加 numgen random;再建 300 个 Service,iptables 模式多出 4500 行规则,ipvs 的 iptables 不变,三种模式 m299 都在 14~15 秒后可访问。
在 kind 集群里实测 Service 会话保持:sessionAffinity: ClientIP 让同一个客户端 IP 的 30 个连接全落在一个后端,不同客户端各自固定;iptables 里是 -m recent --rcheck/--set 加每个后端一张内核 recent 表;timeoutSeconds=3 时 1 秒间隔的访问 12/12 粘住、4 秒间隔 8/12 换了后端,每次访问刷新计时器;固定的后端被删后客户端被重新分配并重新固定。
在 kind 集群里实测 externalTrafficPolicy:Cluster 下集群外的客户端(172.18.0.3)到 NodePort,后端看到的是 10.244.1.1 或 172.18.0.4 而不是真实 IP,没有后端的节点会转发一跳;Local 下后端看到真实 IP,但没有本地后端的节点把包 DROP,curl 3.1 秒超时;LoadBalancer + Local 分配 healthCheckNodePort,有后端的节点返回 200、没有的返回 503。
在 kind 集群(kindnet)里实测 NetworkPolicy:没有策略时全通;default-deny ingress 约 1.1 秒生效且被拒的连接是超时而不是拒绝;podSelector 单独只匹配本命名空间,同一个 from 条目里 namespaceSelector 加 podSelector 是“且”,拆成两个条目是“或”;多条策略取并集;egress default-deny 会把 DNS 一起拦掉,必须单独放行 kube-system 的 53 端口。
在 kind 节点上读 CNI 配置与现场:kindnet 用 ptp + host-local,每个节点一段 podCIDR(10.244.1.0/24 等);host-local 在 /run/cni-ipam-state 里一个 IP 一个文件并记下 last_reserved_ip,新 IP 总是往后分配;Pod 里的 eth0 和节点上的 vethXXXX 互为对端,节点上是一条 /32 主机路由;删除 Pod 后路由、veth 和 IP 记录约 2 秒后才被 CNI DEL 清掉。
在 kind 集群里实测跨节点 Pod 通信:没有隧道,每个节点路由表里有一条去往别的节点 podCIDR 的路由(下一跳是节点 IP);服务端看到的是客户端真实的 Pod IP,KIND-MASQ-AGENT 对目的在 10.244.0.0/16 的流量 RETURN,只有出集群才 MASQUERADE;跨节点 ping 比同节点平均多约 0.03 ms;手动删掉去往另一节点的路由后访问超时,kindnet 约 5~8 秒内补回。
在 kind 节点上用 crictl、ctr、ps 把一个两容器 Pod 对应到运行时:1 个沙箱 + 2 个容器,共用一个 containerd-shim-runc-v2;ctr -n k8s.io 的 10 个 container 正好等于 5 个容器 + 5 个沙箱;crictl inspect 里看到 runc.v2、overlayfs、64Mi 和 100m 被翻译成 cgroup 参数;日志是 CRI 格式的文件 /var/log/pods/…/0.log;crictl stop 后 kubelet 0.7 秒内重启容器。
在 kind 节点上直观看 CRI:kubelet 与 containerd 之间的 unix socket、Version 调用、RuntimeReady / NetworkReady 条件;用 crictl 按 RunPodSandbox → CreateContainer → StartContainer 手动起一个 Pod(0.13 / 0.06 / 0.09 秒),kubelet 在运行时会在 0.9 秒内把这个不认识的沙箱清掉,停掉 kubelet 才能留住;挪走 CNI 配置后 NetworkReady=false,8.6 秒后节点 NotReady,用 mv 放回不会触发重新加载。
在 kind 集群里实测静态 Pod:kubelet 的 staticPodPath 是 /etc/kubernetes/manifests,控制面 4 个组件就是该目录里的文件,在 API 里是 config.source=file 且 ownerReference 是 Node 的镜像 Pod;往 worker 放一个文件 0.6 秒就出现镜像 Pod;kubectl delete 镜像 Pod 约 90 秒后会被重建而容器一直在跑;改文件触发重建、删文件才真正删除;引用 ConfigMap 会被 kubelet 拒绝。
在 kind 集群里实测节点心跳:kube-node-lease 里每个节点一个 Lease,leaseDurationSeconds=40、renewTime 约每 10 秒更新(间隔 10.0~10.3 秒);同样 100 秒 Lease 更新 10 次而 Node 对象只更新 1 次,没变化时 Node status 约 5 分钟才刷新;停掉 kubelet 后约 48 秒 Ready 变 NodeStatusUnknown 并出现 unreachable 污点;删除 Lease 5.7 秒后被 kubelet 重建。