ZooKeeper 与 Kubernetes 控制面是什么关系?答案是:没有关系。但「没有」这个结论值得验证。这篇从 Kubernetes 的源码编译出真正的 kube-apiserver,让它连本机 etcd,看它往 etcd 里写什么、resourceVersion 与 etcd 的 revision 是什么关系;读存储工厂的源码确认只有 etcd3;最后试一下把它指向 ZooKeeper,看它怎么失败。
GET /readyz → ok,启动到就绪 2 s etcd 里 /registry 下共 57 个 key,第一级分类 14 种,前 14 种:['apiregistration.k8s.io', 'configmaps', 'endpointslices', 'flowschemas', 'ipaddresses', 'leases', 'masterleases', 'namespaces', 'peerserverleases', 'priorityclasses', 'prioritylevelconfigurations', 'ranges', 'servicecidrs', 'services']
POST /api/v1/namespaces → 201 POST /api/v1/namespaces/demo/configmaps → 201 (201 = 创建成功) etcd 里含 demo / cm1 的 key: ['/registry/configmaps/demo/cm1', '/registry/namespaces/demo'] 值的前 12 个字节:b'k8s\x00\n\x0f\n\x02v1\x12\t'(Kubernetes 的 protobuf 存储格式前缀 k8s\x00),总长 191 字节;值里可见的字符串:['k8s', 'ConfigMap', 'cm1', 'demo"', '*$43f2ce51-6679-4ec2-b27a-b00f448a9e202', 'Python-urllib']
只启动了 kube-apiserver 与 etcd,没有 controller-manager、scheduler、kubelet,所以只验证了「控制面的存储」这一层,不是完整集群。
resourceVersion = 73;etcd mod_revision = 73;相等:True PATCH 修改 data.a → c: 200 修改后 resourceVersion = 74;etcd mod_revision = 74;相等:True
下一篇(ZooKeeper 与 etcd 对比)会具体比较两者的 watch 与版本模型。
staging/src/k8s.io/apiserver/pkg/storage/storagebackend/factory/factory.go(kubernetes v1.37.1) func Create(c storagebackend.ConfigForResource, newFunc, newListFunc func() runtime.Object, resourcePrefix string) (storage.Interface, DestroyFunc, error) { switch c.Type { case storagebackend.StorageTypeETCD2: return nil, nil, fmt.Errorf("%s is no longer a supported storage backend", c.Type) case storagebackend.StorageTypeUnset, storagebackend.StorageTypeETCD3: return newETCD3Storage(c, newFunc, newListFunc, resourcePrefix) default: return nil, nil, fmt.Errorf("unknown storage type: %s", c.Type) }
另外在 v1.37.1 源码目录里统计:go.mod 里有 go.etcd.io/etcd/client/v3 v3.7.0,go.mod 与 vendor/modules.txt 中 zookeeper 出现 0 次(这两个数字是我用 grep 查的,没有写进实验输出文件)。
60 秒后 GET https://127.0.0.1:7652/readyz → 0 URLError <urlopen error [Errno 61] Connection refused>;apiserver 进程已退出,退出码 1
日志里的 E / W 行共 21 行,前 3 行与最后 1 行:
W1001 14:13:47.792242 83619 authentication.go:841] AnonymousAuth is not allowed with the AlwaysAllow authorizer. Resetting AnonymousAuth to false. You should use a different authorizer
E1001 14:13:47.975921 83619 options.go:205] The manifest file is empty, ignoring.
W1001 14:13:47.977747 83619 logging.go:55] [core] [Channel #2 SubChannel #4] grpc: addrConn.createTransport failed to connect to {Addr: "127.0.0.1:7300", ServerName: "127.0.0.1:7300", }. Err: connection error: desc = "error read
E1001 14:14:07.976197 83619 run.go:72] "command failed" err="error creating storage factory: etcd grpc connection not ready: context deadline exceeded"
日志里是否出现 "Serving securely"(开始对外服务): False