ClickHouse Operator 的 ClickHouseKeeper 引用指南:通过 KeeperRef 在 CHI 中自动解析 Keeper 拓扑
【免费下载链接】clickhouse-operatorAltinity Kubernetes Operator for ClickHouse creates, configures and manages ClickHouse® clusters running on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/cl/clickhouse-operator
本指南讲解 Altinity ClickHouse Operator 中
spec.configuration.zookeeper.keeper(KeeperRef)的完整用法:如何在ClickHouseInstallation(CHI)中通过名称引用ClickHouseKeeperInstallation(CHK)资源,由 Operator 在协调(reconcile)期间自动解析出 ZooKeeper 节点地址。读完本文,你将掌握 KeeperRef 的字段语义、replicas与service两种端点发现模式、TLS 自动检测、就绪等待与超时配置、CHK 变更自动触发 CHI 协调,以及基于真实源码的故障排查方法。
为什么需要 Keeper 引用(KeeperRef)
在 ClickHouse 复制拓扑中,副本间的元数据同步依赖 ZooKeeper 兼容服务。传统写法是在spec.configuration.zookeeper.nodes中逐个显式写出host:port:
zookeeper: nodes: - host: zookeeper-0.zookeepers.zoo3ns.svc.cluster.local port: 2181 - host: zookeeper-1.zookeepers.zoo3ns.svc.cluster.local port: 2181 - host: zookeeper-2.zookeepers.zoo3ns.svc.cluster.local port: 2181这种方式要求运维人员预先知道 ZooKeeper/Keeper 的完整地址清单,且当 Keeper 扩缩容时必须手工同步维护 CHI 清单,极易出错。
KeeperRef 的引入正是为了解决这个问题:不再显式指定端点,而是通过名称引用一个ClickHouseKeeperInstallation(CHK)资源,由 Operator 在协调周期中自动解析出实际的 Keeper 节点地址并写入 ClickHouse 配置。从源码看,KeeperRef类型定义于 pkg/apis/clickhouse.altinity.com/v1/type_keeper_ref.go,它挂在ZookeeperConfig上(pkg/apis/clickhouse.altinity.com/v1/type_zookeeper.go),与显式Nodes是同一层级的两条可选路径。
基本用法
最简单的引用方式如下(完整可运行示例见 docs/chi-examples/04-replication-zookeeper-07-keeper-ref.yaml):
apiVersion: "clickhouse.altinity.com/v1" kind: "ClickHouseInstallation" metadata: name: my-chi spec: configuration: zookeeper: keeper: name: my-keeper clusters: - name: default layout: shardsCount: 1 replicasCount: 2当 CHI 提交后,Operator 会:
- 通过 CHK 名称与命名空间定位对应的
ClickHouseKeeperInstallation资源; - 发现该 CHK 暴露的所有 Keeper 副本服务(或 CR 级服务,取决于
serviceType); - 将解析出的节点地址按
<zookeeper><node><host>...</host><port>...</port></node>结构渲染进 ClickHouse 配置,使 ClickHouse 获得正确的 ZooKeeper 节点列表。
这条解析链路在源码中对应 pkg/controller/chi/controller-keeper-resolver.go 中的resolveKeeperNodes:它按serviceType分派到resolveKeeperByReplicas(按副本发现)或resolveKeeperByService(按 CR 级服务发现),最终返回一个api.ZookeeperNodes列表。值得注意的实现细节是:当副本发现失败或返回 0 个节点时,replicas模式会自动回退到 CR 级服务,提升了解析的健壮性。
KeeperRef 字段详解
下表完整列出KeeperRef支持的字段(与 type_keeper_ref.go 中的结构定义一一对应):
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name | string | (必填) | ClickHouseKeeperInstallation资源的名称 |
namespace | string | CHI 所在命名空间 | CHK 资源所在命名空间,跨命名空间引用时需显式指定 |
serviceType | string | replicas | 端点发现模式,见下文 |
在类型层面,KeeperRef提供了几个 nil 安全的访问器:HasName()判断引用是否有效、GetNamespace(defaultNamespace)在未指定时回落到 CHI 命名空间、GetServiceType()在未指定时默认返回replicas。这也解释了文档中"namespace 省略则默认同命名空间"、serviceType默认replicas的行为。
另外,ZookeeperConfig.IsEmpty()的语义值得注意:只有当nodes为空且没有keeper引用时,该配置才被视为空。也就是说,只要填了keeper,即使不写任何nodes,也能正常驱动解析逻辑。
ServiceType:两种端点发现模式
serviceType控制 Keeper 端点如何被发现(两种模式的常量定义见 type_keeper_ref.go):
replicas(默认):发现每个 Keeper 副本对应的 per-host 服务,为每个 Keeper 副本生成一个 ZooKeeper 节点。ClickHouse 能感知完整的 Keeper 拓扑,故障转移时具备全局视野,生产环境推荐使用。源码实现上,resolveKeeperByReplicas通过 CHK labeler 的LabelCRName与LabelServiceValueHost标签选择器列出所有 host 服务,按名称排序后逐一生成节点(见 controller-keeper-resolver.go)。service:将 CHK CR 级 headless 服务作为一个单一 ZooKeeper 节点条目。配置更简单,但 ClickHouse 看不到各个 Keeper 副本,拓扑感知能力较弱。源码实现resolveKeeperByService直接通过 CHK 命名器构造 CR 级服务名并查询该 Service 的端口信息(见 controller-keeper-resolver.go)。
与其他 ZooKeeper 设置的组合
keeper引用与zookeeper下的其他字段完全正交,可以同时使用。解析出的节点会与显式声明的nodes共存,最终统一渲染进 ClickHouse 的<zookeeper>配置:
zookeeper: keeper: name: my-keeper session_timeout_ms: 30000 operation_timeout_ms: 10000 root: "/clickhouse/my-cluster" identity: "user:password"各字段的 ClickHouse 侧语义(依据 type_zookeeper.go 的注释):
session_timeout_ms:ZooKeeper 会话超时(毫秒),渲染为<session_timeout_ms>;operation_timeout_ms:单次 ZooKeeper 操作超时(毫秒),渲染为<operation_timeout_ms>;root:ClickHouse 所有 znode 的可选根路径前缀,渲染为<root>;identity:ZooKeeper digest 认证凭据,格式user:password,渲染为<identity>;use_compression:Keeper 协议客户端-服务端通信压缩开关,渲染为<use_compression>。
从合并逻辑看,ZookeeperConfig.MergeFrom(type_zookeeper.go)采用"节点去重追加、Keeper 引用仅在接收方为空时采纳、标量字段非零覆盖"的策略,模板与 CHI 合并时行为可预期。
集群级覆盖(Cluster-Level Override)
同一个 CHI 下可以部署多个集群,每个集群可以拥有自己的 Keeper 引用,从而覆盖顶层配置。覆盖规则很明确:只要某个集群带有自己的zookeeper配置(无论是自己的keeper引用还是自己的nodes),顶层配置对该集群就被整体忽略。
spec: configuration: zookeeper: keeper: name: default-keeper clusters: - name: cluster-a # 使用 default-keeper(继承自顶层配置) layout: shardsCount: 2 replicasCount: 2 - name: cluster-b # 使用自己专属的 keeper zookeeper: keeper: name: dedicated-keeper namespace: keeper-namespace layout: shardsCount: 1 replicasCount: 3真实的全字段示例(docs/chi-examples/99-clickhouseinstallation-max.yaml)中同样包含一个集群级覆盖:shards-only集群声明了自己的zookeeper.keeper(cluster-specific-keeper、serviceType: service),与顶层配置并存互不干扰。
TLS 自动检测
Operator 会自动探测 Keeper 是否启用了 TLS,探测依据是服务端口定义。相关常量与检测函数位于 pkg/apis/clickhouse.altinity.com/v1/type_host.go:
- 端口
2181或端口名为zk→ 不安全连接; - 端口
2281或端口名为zk-secure→ 安全连接(会在 ClickHouse 配置中设置<secure>1</secure>)。
检测函数ExtractZKPortInfo的优先级是:优先返回安全端口(若同时暴露了多个端口,只要存在zk-secure/2281就以安全模式解析),否则回落到非安全端口,最后兜底为默认的2181。因此,只要 Keeper 暴露了安全端口,解析出的 ZooKeeper 节点会自动带上secure: true,无需任何手工配置。完整的常量映射为:
zk/2181:Keeper 默认 ZooKeeper 客户端端口(不安全)zk-secure/2281:Keeper 安全(TLS)ZooKeeper 客户端端口raft/9444:Keeper 内部 Raft 端口(不用于客户端连接)
Keeper 就绪等待(Readiness)
在解析端点之前,Operator 会等待被引用的 CHK 的 Pod 进入Running阶段。这主要处理 CHK 与 CHI同时创建的场景——此时 Keeper Pod 可能尚未启动,直接解析会失败。
等待超时通过 Operator 配置ClickHouseOperatorConfiguration控制:
spec: reconcile: coordination: keeper: readyTimeout: 120 # 秒(默认:120)该行为在 pkg/controller/chi/worker-keeper-resolver.go 的waitKeeperReady中实现:它读取chop.Config().Reconcile.Coordination.Keeper.ReadyTimeout(单位秒),轮询 CHK 的所有 Pod,任一 Pod 未处于Running阶段就继续等待。
如果等待超时,CHI 协调将以ErrKeeperNotReady错误失败,并在 CHI 资源上发出 Kubernetes Event。该错误哨兵值定义于 controller-keeper-resolver.go,同类错误还包括ErrKeeperRefResolve(引用解析失败,如服务未找到)与ErrKeeperRefNoNodes(解析成功但得到 0 个节点)。
CHK 变更自动触发 CHI 协调(Auto-Reconcile)
Keeper 集群扩缩容后,ClickHouse 侧需要感知新的节点列表。Operator 提供了可选的 CHK 资源监听机制:
# ClickHouseOperatorConfiguration spec: reconcile: coordination: keeper: readyTimeout: 120 onKeeperResourceUpdate: reconcile # "none"(默认)或 "reconcile"当onKeeperResourceUpdate: reconcile时:
- Operator 在监听命名空间内 watch 所有 CHK 资源(pkg/controller/chi/controller-chk-watcher.go 中的
StartCHKWatcher通过动态 informer 实现,resync 周期 60 秒); - 仅当 CHK转换到
Completed状态时才触发依赖 CHI 的重新协调(onCHKUpdate只对"从非 Completed 变为 Completed"的转换响应,InProgress阶段不会触发,见 controller-chk-watcher.go); - 触发前会做一次端点差分:
shouldReconcileOnKeeperUpdate将当前 CHK 状态解析出的节点集合与 CHI 上次完成协调(NormalizedCRCompleted)消费的节点集合做集合相等比较(controller-chk-watcher.go)。只有当解析出的 ZooKeeper 端点列表确实发生变化时才入队协调——像磁盘扩容这类不影响端点列表的 CHK 变更会被跳过,并发出KeeperUpdateNoEndpointChange事件说明跳过原因。
这一差分机制保证了 ClickHouse 能及时跟上 Keeper 拓扑变化(如 Keeper 扩缩容),同时避免无意义的空转协调。
故障排查(Troubleshooting)
查看解析出的端点
解析后的 Keeper 节点会出现在 CHI 的归一化状态中:
kubectl get chi my-chi -o json | jq '.status.normalizedCompleted.spec.configuration.zookeeper.nodes'查看 Kubernetes Events
Keeper 引用解析失败会发出 Kubernetes Events:
kubectl get events --field-selector involvedObject.name=my-chi,reason=ReconcileFailed结合前文,还可以用reason=KeeperUpdateNoEndpointChange查看"CHK 完成但端点未变化、协调被跳过"的事件。
常见问题速查表
| 症状 | 原因 | 解决方法 |
|---|---|---|
| CHI 卡在 InProgress | CHK Pod 未运行 | 检查 CHK 状态:kubectl get chk |
| CHI 协调超时失败 | readyTimeout过短 | 在 Operator 配置中增大readyTimeout |
| ClickHouse 无法连接 Keeper | keeper 引用中的 namespace 错误 | 校验namespace字段,或省略以使用同命名空间 |
| 只解析出 1 个 ZK 节点 | 使用了serviceType: service | 切换为serviceType: replicas(默认) |
| Keeper 扩缩后 CHI 未更新 | Watcher 未启用 | 在 Operator 配置中设置onKeeperResourceUpdate: reconcile |
另外,源码层面还有两个可辅助诊断的错误语义:ErrKeeperRefNoNodes提示解析成功但 CHK 当前没有任何可用的 host 服务(例如 CHK 尚未生成服务或副本数为 0);而replicas模式在副本发现失败时自动回退到 CR 级服务,若最终仍失败才会返回ErrKeeperRefResolve。
完整配置示例
- Basic keeper reference:最简引用 +
session_timeout_ms/operation_timeout_ms组合; - All fields example:同时演示顶层
keeper引用(注释形式)与集群级zookeeper.keeper覆盖(shards-only集群)、以及显式nodes对照写法; - Operator config with coordination:完整
ClickHouseOperatorConfiguration,其中reconcile.coordination.keeper一节同时给出了readyTimeout: 120与onKeeperResourceUpdate: none(默认值)的完整上下文,可在此基础上按需修改。
总结
KeeperRef 将"ClickHouse ↔ ZooKeeper/Keeper 拓扑"的耦合点从手工维护的host:port清单,收敛为对 CHK 资源的声明式引用。配合replicas模式的完整拓扑感知、基于服务端口的 TLS 自动检测、CHK 就绪等待与readyTimeout超时保护,以及onKeeperResourceUpdate: reconcile下的端点差分触发协调,Operator 能够在不改动 CHI 的情况下自动跟随 Keeper 集群的演进,这是生产环境搭建复制集群(如 docs/chi-examples/04-replication-zookeeper-07-keeper-ref.yaml 演示的 1 分片 2 副本场景)时推荐的首选方式。
【免费下载链接】clickhouse-operatorAltinity Kubernetes Operator for ClickHouse creates, configures and manages ClickHouse® clusters running on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/cl/clickhouse-operator
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考