Altinity ClickHouse Operator 前置准备指南:为 Kubernetes 上的 ClickHouse 集群配置持久化存储与 ZooKeeper 复制协调
发布时间:2026/9/18 23:40:34 锦皓数字建站

Altinity ClickHouse Operator 前置准备指南为 Kubernetes 上的 ClickHouse 集群配置持久化存储与 ZooKeeper 复制协调【免费下载链接】clickhouse-operatorAltinity Kubernetes Operator for ClickHouse creates, configures and manages ClickHouse® clusters running on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/cl/clickhouse-operator在 Kubernetes 上运行 ClickHouse 之前需要先回答两个关键问题数据落在哪里、副本之间如何协调。本指南以 docs/introduction.md 为骨架完整讲解 Altinity ClickHouse Operator 部署集群的两大前置条件——Persistent Volumes持久化卷与 ZooKeeper并结合 docs/storage.md、docs/zookeeper_setup.md 与 docs/keeper_reference.md 及仓库中的真实示例与源码说明 PV/PVC/StorageClass 的工作原理、ZooKeeper 的快速与高级部署方式以及使用 ClickHouseKeeper 引用替代手写 ZK 地址的现代做法。读完本文你将能够为 ClickHouse 集群准备可用的持久化存储并独立部署或引用一套复制协调服务。前置条件总览在 Kubernetes 中创建一个可供使用的 ClickHouse 安装需要先具备以下两项基础设施Persistent Volumes持久化卷——ClickHouse 需要磁盘空间保存数据Kubernetes 通过 PersistentVolume 提供这一能力。ZooKeeper或 ClickHouseKeeper——如果要启用 ClickHouse 的数据复制Replication需要一个 ClickHouse 可访问的 ZooKeeper 实例。下文分别展开说明这两项前置条件为何必要以及如何准备。持久化存储PV、PVC 与 StorageClassClickHouse 为什么必须依赖持久化卷ClickHouse 是典型的存算耦合的数据库数据直接落盘。官方文档对 PersistentVolume 的定义是A PersistentVolume (PV) is a piece of storage in the cluster that has been provisioned by an administrator.这意味着必须事先做好功课为 ClickHouse 安装准备可用的持久化卷而不是依赖 Pod 内临时文件系统。在 Kubernetes 的存储体系中PV 可以由以下两种方式提供系统管理员手动准备由负责 k8s 安装的管理员预先准备足量的 PV 对象动态供应Dynamic Provisioning在 k8s 安装中配置 Persistent Volume Provisioner按需动态供应卷。当 ClickHouse 需要磁盘存储时会通过 Persistent Volume ClaimPVC 声明存储需求其中会指定期望的存储类Storage Class与容量大小。每个 PV 都有绑定的类class与已供应的容量。因此连接软件与待供应磁盘之间的核心纽带是 Storage Class。两种 PV 供应方式的对比在 docs/storage.md 中这一流程被进一步拆解为手动卷供应集群管理员直接向存储云供应商发起调用预置新的存储卷再创建PersistentVolume对象代表这些卷用户随后通过PersistentVolumeClaim认领这些卷。动态卷供应无需管理员手动预置存储存储资源由名为 provisioner 的软件模块动态供应该模块由StorageClass对象指定。StorageClass抽象了底层存储供应商及其全部参数如磁盘类型、位置等并通过针对特定存储平台或云供应商的 provisioner 让 Kubernetes 访问物理介质。StorageClass 是什么、怎么用应用程序用户在PersistentVolumeClaim中通过storageClassName参数按名字引用StorageClass。一个典型的 PVC 如下apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc namespace: mytestns spec: storageClassName: my-storage-class accessModes: - ReadWriteOnce resources: requests: storage: 100Gi示例中的存储类名my-storage-class对每个 k8s 安装都是特定的通常需要由集群管理员告知应用程序。但这并不总是方便——有时只想用任何可用的存储而不关心当前 k8s 安装中到底有哪些存储类。为此集群管理员可以指定一个默认StorageClass当默认存储类存在时用户可以创建不带storageClassName的PersistentVolumeClaim从而简化流程、降低对底层存储供应商的了解要求。关于PersistentVolumeClaim的三个重要行为如果未指定storageClassName将使用默认StorageClass必须由集群管理员指定进行供应如果storageClassName被设置为空字符串则不使用任何StorageClass即对该 PVC 而言动态供应被显式禁用只有未指定storageClassName的可用 PV 才会被纳入绑定考虑如果storageClassName被设置则匹配的StorageClass将被用于供应。AWS 场景用 kubectl 查看 StorageClass以 kops 创建的集群为例可以用kubectl查看当前可用的StorageClasskubectl get storageclasses.storage.k8s.ioNAME PROVISIONER AGE default kubernetes.io/aws-ebs 1d gp2 (default) kubernetes.io/aws-ebs 1d这里可以看到两个存储类名为default的存储类名为gp2的存储类——它同时是默认StorageClass名字后面标注了(default)。查看它们的内部定义kubectl get storageclasses.storage.k8s.io default -o yaml kubectl get storageclasses.storage.k8s.io gp2 -o yaml实际上这两个StorageClass是等价的metadata: labels: k8s-addon: storage-aws.addons.k8s.io name: gp2 provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Delete volumeBindingMode: Immediatemetadata: labels: k8s-addon: storage-aws.addons.k8s.io name: default provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Delete volumeBindingMode: Immediate这意味着我们的PersistentVolumeClaim可以有两种等价写法省略storageClassName字段——此时会使用名为gp2的存储类因为它是默认的显式指定storageClassName: default此时会使用名为default的存储类效果与使用gp2即系统中的默认StorageClass完全相同。从 PVC 到 Podvolume 与 volumeMountsPod 将PersistentVolumeClaim作为volume使用。关键约束是PVC 必须与使用它的 Pod 位于同一命名空间。k8s 会检查PersistentVolumeClaim以找到合适的PersistentVolume并通过volumeMounts将该 PV 挂载到 Pod 的文件系统中。Pod或 Pod Template中通过volumeMounts引用volumes里的名字# Pod 或 Pod Template 清单节选 containers: - name: myclickhouse image: clickhouse volumeMounts: - mountPath: /var/lib/clickhouse name: my-volume其中volume的定义可以是不同类型的最终对象描述例如emptyDir类型volumes: - name: my-volume emptyDir: {}hostPath类型StatefulSet 清单节选volumes: - name: my-volume hostPath: path: /local/path/或者引用PersistentVolumeClaimvolumes: - name: my-volume persistentVolumeClaim: claimName: my-claim其中最小化的PersistentVolumeClaim可以写成apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi注意这里没有指定storageClassName——意味着该 PVC 将认领显式指定的默认StorageClass的PersistentVolume。将这个名为my-pvc的 PVC 用于 Pod 的完整示例apiVersion: v1 kind: Pod metadata: name: nginx spec: volumes: - name: www persistentVolumeClaim: claimName: my-pvc containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/htmlStatefulSet从 volumeMounts 直达 volumeClaimTemplatesStatefulSet对上述流程做了捷径处理直接由volumeMounts跳到volumeClaimTemplates跳过中间的volume定义。一个典型的 StatefulSet 示例apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: nginx replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ ReadWriteOnce ] resources: requests: storage: 1Gi注意.spec.template.spec.containers.volumeMounts中的name: www直接对应volumeClaimTemplates中的name: www——两者通过名字建立绑定这是 ClickHouse Operator 在生成 StatefulSet 时同样遵循的机制。在 CHI 资源中声明持久化卷在 ClickHouse Operator 中不需要手写 Kubernetes 的 PVC/PV 对象而是通过ClickHouseInstallationCHI资源里的templates.volumeClaimTemplates声明卷模板Operator 会自动为每个 Pod 生成并管理 PVC。最小化的默认卷示例见 docs/chi-examples/03-persistent-volume-01-default-volume.yamlapiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: pv-simple spec: defaults: templates: dataVolumeClaimTemplate:>apiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: pv-log spec: configuration: clusters: - name: deployment-pv templates: podTemplate: pod-template-with-volumes layout: shardsCount: 2 replicasCount: 2 templates: podTemplates: - name: pod-template-with-volumes spec: containers: - name: clickhouse image: clickhouse/clickhouse-server:24.8 volumeMounts: - name:>apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gp2-encrypted provisioner: kubernetes.io/aws-ebs parameters: encrypted: true fsType: ext4 type: gp2 reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer allowVolumeExpansion: true然后在volumeClaimTemplates中通过storageClassName引用它apiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: pv-enc spec: defaults: templates: dataVolumeClaimTemplate:>kubectl create namespace zoo1ns然后将 ZooKeeper 部署进该命名空间以zookeeper-1-node.yaml为例kubectl apply -f zookeeper-1-node.yaml -n zoo1ns之后 ZooKeeper 就应该启动运行了可以进入下面的验证集群环节。重要提醒快速开始的 ZooKeeper 安装主要用于测试。需要精细调优的 ZooKeeper 请参考高级安装方案。高级安装Advanced Setup高级安装的文件位于 deploy/zookeeper/zookeeper-manually/advanced 目录所有资源被拆分到不同文件中便于逐个修改和配置所需选项。高级安装同样分为带持久化卷与带 emptyDir 卷两种每种都提供了对应的create与delete脚本如zookeeper-persistent-volume-create.sh/zookeeper-persistent-volume-delete.sh、zookeeper-volume-emptyDir-create.sh/zookeeper-volume-emptyDir-delete.sh。逐步说明如下1. 创建命名空间kubectl create namespace zoons2. 创建客户端访问 Service该 Service 为所有 ZooKeeper 节点提供客户端访问的 DNS 名称kubectl apply -f 01-service-client-access.yaml -n zoons预期输出service/zookeeper created3. 创建 Headless Service该无头 Service 为所有 ZooKeeper 节点提供各自的 DNS 名称kubectl apply -f 02-headless-service.yaml -n zoons预期输出service/zookeeper-nodes created4. 创建 Pod Disruption BudgetDisruption Budget 告知 k8s 任意时刻允许有多少个 ZooKeeper 节点离线kubectl apply -f 03-pod-disruption-budget.yaml -n zoons预期输出poddisruptionbudget.policy/zookeeper-pod-distribution-budget created5. 决定存储类Storage Class这一步不是那么直接可能需要与 k8s 实例管理员沟通。首先需要决定 ZooKeeper 使用Persistent Volume存储还是更简单的Volume文档中使用emptyDir类型若选择emptyDir使用emptyDir StatefulSet 配置05-stateful-set-volume-emptyDir.yaml若选择 Persistent Volume使用Persistent Volume StatefulSet 配置05-stateful-set-persistent-volume.yaml。简要来说StorageClass 将 Persistent Volumes 绑定在一起——这些 PV 由 k8s 管理员手动创建或由 Provisioner 自动创建无论哪种方式PV 都是外部提供给要部署到 k8s 的应用的。因此应用必须知道Storage Class Name才能在 Persistent Volume Claim 中向 k8s 请求新的持久化卷。这个Storage Class Name应向 k8s 管理员询问并写入 StatefulSet 配置中的.spec.volumeClaimTemplates.storageClassName参数。6. 编辑 StatefulSet 并按需选择卷类型在 05-stateful-set-volume-emptyDir.yaml 和/或 05-stateful-set-persistent-volume.yaml 中按存储偏好进行编辑。若使用emptyDir卷确保.spec.template.spec.containers.volumes就位且形如下面并注释掉.spec.volumeClaimTemplatesvolumes: - name: datadir-volume emptyDir: medium: # 可接受值空字符串表示节点的默认介质或 Memory sizeLimit: 1Gi若使用 Persistent Volume确保.spec.template.spec.containers.volumes被注释掉并取消.spec.volumeClaimTemplates的注释volumeClaimTemplates: - metadata: name: datadir-volume spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi ## storageClassName 需要与 k8s 管理员协调且必须存在 kind: StorageClass 资源 storageClassName: storageclass-zookeeper并确保storageClassName示例为storageclass-zookeeper按上文存储类一节描述正确指定。YAML 文件就绪后用kubectl应用kubectl apply -f 05-stateful-set.yaml -n zoons预期输出statefulset.apps/zookeeper-node created注仓库advanced目录中实际提供的是两份 StatefulSet 清单——05-stateful-set-persistent-volume.yaml 与 05-stateful-set-volume-emptyDir.yaml应用时请选择与你的存储决策一致的那份。验证 ZooKeeper 集群部署完成后可以按以下方式检查 ZooKeeper 集群。DNS 名称期望在zoons命名空间内有一个由 3 个 Pod 组成的 ZooKeeper 集群名称形如zookeeper-0 zookeeper-1 zookeeper-2这些 Pod 的短 DNS 名形如zookeeper-0.zookeepers.zoons zookeeper-1.zookeepers.zoons zookeeper-2.zookeepers.zoons其中zookeepers是 ZooKeeper headless service 的名称zoons是 ZooKeeper 命名空间的名称。完整 DNS 名FQDN形如zookeeper-0.zookeepers.zoons.svc.cluster.local zookeeper-1.zookeepers.zoons.svc.cluster.local zookeeper-2.zookeepers.zoons.svc.cluster.local检查资源列出 ZooKeeper 命名空间中的 Podkubectl get pod -n zoons预期输出NAME READY STATUS RESTARTS AGE zookeeper-0 1/1 Running 0 9m2s zookeeper-1 1/1 Running 0 9m2s zookeeper-2 1/1 Running 0 9m2s列出 Servicekubectl get service -n zoons预期输出NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE zookeeper ClusterIP 10.108.36.44 none 2181/TCP 168m zookeepers ClusterIP None none 2888/TCP,3888/TCP 31m列出 StatefulSetkubectl get statefulset -n zoons预期输出NAME READY AGE zookeepers 3/3 10m一切正常即表示 ZooKeeper 集群已成功运行。在 CHI 中接入 ZooKeeper手写节点与 keeper 引用当 ZooKeeper 就绪后传统方式是在ClickHouseInstallation的spec.configuration.zookeeper.nodes中显式填写host:port。仓库中的最小化 AWS 示例见 docs/chi-examples/04-replication-zookeeper-03-minimal-AWS-persistent-volume.yamlapiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: repl-03 spec: configuration: zookeeper: nodes: - host: zookeeper.zoo1ns port: 2181 clusters: - name: replcluster templates: podTemplate: clickhouse-with-volume-template layout: shardsCount: 1 replicasCount: 2 templates: podTemplates: - name: clickhouse-with-volume-template spec: containers: - name: clickhouse-pod image: clickhouse/clickhouse-server:24.8 volumeMounts: - name: clickhouse-storage-template mountPath: /var/lib/clickhouse volumeClaimTemplates: - name: clickhouse-storage-template spec: # 未指定 storageClassName —— 表示使用默认 storageClassName #storageClassName: default accessModes: - ReadWriteOnce resources: requests: storage: 50Gi注意该示例同时演示了复制的两个前置条件的组合使用PVvolumeClaimTemplatesvolumeMounts指向/var/lib/clickhouse与 ZKzookeeper.nodes。而更现代的做法是引用ClickHouseKeeperInstallationCHK资源详见 docs/keeper_reference.md不再手写host:port而是按名字引用 CHK由 Operator 在 reconcile 过程中自动解析 keeper 端点。基本用法见 docs/chi-examples/04-replication-zookeeper-07-keeper-ref.yamlapiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: repl-keeper-ref spec: configuration: zookeeper: keeper: name: my-keeper # namespace: my-namespace # 可选默认使用 CHI 所在命名空间 # serviceType: replicas # 可选默认值为 replicas session_timeout_ms: 30000 operation_timeout_ms: 10000 clusters: - name: default layout: shardsCount: 1 replicasCount: 2keeper引用支持以下字段字段类型默认值说明namestring必填ClickHouseKeeperInstallation资源的名称namespacestringCHI 的命名空间CHK 资源所在命名空间serviceTypestringreplicas端点发现模式见下文serviceType的两种模式replicas默认——发现每个 host 的 keeper 服务为每个 keeper 副本创建一个 ZooKeeper 节点。生产环境推荐ClickHouse 可获知完整的 keeper 拓扑便于故障转移service——使用 CHK CR 级别的 headless service 作为单个 ZooKeeper 节点入口。更简单但 ClickHouse 看不到各个 keeper 副本。keeper引用还可以与其他zookeeper字段session_timeout_ms、operation_timeout_ms、root、identity等组合使用。此外集群级也可以定义自己的keeper引用并覆盖顶层配置一旦某集群带有任何自己的zookeeper配置自己的keeper引用或自己的nodes该集群将完全忽略顶层配置。Operator 还会通过检查 service 端口规范自动探测 keeper 是否配置了 TLS端口2181或名为zk的端口表示非安全连接端口2281或名为zk-secure的端口表示安全连接会在 ClickHouse 配置中设置secure1/secure无需手动配置。源码视角keeper 引用如何被解析从源码结构看keeper 引用的解析与协调逻辑分布在 pkg/controller/chi/controller-keeper-resolver.go、pkg/controller/chi/worker-keeper-resolver.go 与 pkg/controller/chi/worker-reconciler-chi.go 中。在解析端点之前Operator 会等待被引用的 CHK 的 Pod 进入Running阶段——这解决了 CHK 与 CHI 同时创建的情况。等待超时可通过 Operator 配置调整config/config.yaml 中reconcile.coordination.keeper段# ClickHouseOperatorConfiguration spec: reconcile: coordination: keeper: readyTimeout: 120 # 秒默认 120 # onKeeperResourceUpdate: reconcile # none默认或 reconcile如果 keeper Pod 在超时内未就绪CHI 的 reconcile 会以ErrKeeperNotReady错误失败并在 CHI 资源上发出 Kubernetes Event。当设置onKeeperResourceUpdate: reconcile时Operator 会监视被监管命名空间中的所有 CHK 资源一旦 CHK 转入Completed状态所有依赖它的 CHI 都会触发重新 reconcile从而保证 ClickHouse 能及时感知 keeper 拓扑变化如扩缩容。相关实现见 pkg/controller/chi/controller-chk-watcher.go。从前置准备到第一个 ClickHouse 集群完成上述两大前置准备后即可创建第一个集群。最小的Hello, world式示例无持久化存储、1 分片 1 副本见 docs/chi-examples/01-simple-layout-01-1shard-1repl.yamlapiVersion: clickhouse.altinity.com/v1 kind: ClickHouseInstallation metadata: name: simple-01 spec: configuration: users: # printf test_password | sha256sum test_user/password_sha256_hex: 10a6e6cc8311a3e2bcc09bf6c199adecd5dd59408c343e926b129c4914f3cb01 test_user/password: test_password # 允许从 kubernetes 外部访问 test_user/networks/ip: - 0.0.0.0/0 clusters: - name: simple该示例仅用于演示不要用于任何生产用途——它没有持久化存储。更完整的组合可参考 docs/chi-examples/04-replication-zookeeper-04-medium-AWS-persistent-volume.yaml带复制与持久化卷的中型 AWS 部署以及 docs/chi-examples/99-clickhouseinstallation-max.yaml各字段全覆盖的完整示例。延伸阅读存储详解PV、PVC、StorageClass 与卷挂载ZooKeeper 安装指南快速开始与高级安装从 CHI 引用 ClickHouseKeeperkeeper 引用快速开始安装 Operator 并运行首个示例CHI 持久化卷示例docs/chi-examples/03-persistent-volume-01-default-volume.yaml、docs/chi-examples/03-persistent-volume-02-pod-template.yaml、docs/chi-examples/03-persistent-volume-04-encrypted-volume.yamlZooKeeper 部署文件deploy/zookeeper/zookeeper-manually/quick-start-persistent-volume、deploy/zookeeper/zookeeper-manually/quick-start-volume-emptyDir、deploy/zookeeper/zookeeper-manually/advanced【免费下载链接】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),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。