6-2-2-k8s实际应用-zookeeper集群部署(二)
1. 任务实现思路分析
搬出 AI 时代运维三板斧中的前两板 , 看看是否能解决问题。
注 : 由于只用了两板斧就搞定了 , 所以就没用到第三板。
1.1 AI 助手
提示词 : 我要在 K8s 上部署 zookeerper。分别给我一个单节点和集群模式的部署方案 , 注意需要使用存储类 glusterfs、需要有 SVC、需要有 zoo.cfg 的 ConfigMap
单节点部署配置文件(
zookeeper-single.yaml)apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zookeeper-data spec: accessModes: - ReadWriteOnce storageClassName: glusterfs resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: zookeeper spec: selector: app: zookeeper ports: - protocol: TCP port: 2181 targetPort: 2181 --- apiVersion: v1 kind: ConfigMap metadata: name: zookeeper-config data: zoo.cfg: | tickTime=2000 dataDir=/data clientPort=2181 --- apiVersion: apps/v1 kind: Deployment metadata: name: zookeeper spec: replicas: 1 selector: matchLabels: app: zookeeper template: metadata: labels: app: zookeeper spec: containers: - name: zookeeper image: zookeeper:3.7.0 resources: requests: cpu: 100m memory: 1Gi ports: - containerPort: 2181 volumeMounts: - name: zookeeper-data mountPath: /data env: - name: ZOOKEEPER_CONFIG_FILE value: /opt/zookeeper-3.7.0/conf/zoo.cfg - name: ZOO_SERVERS value: "server.1=zookeeper-0.zookeeper.default.svc.cluster.local:2888:3888;2181" volumes: - name: zookeeper-data persistentVolumeClaim: claimName: zookeeper-data - name: zookeeper-config configMap: name: zookeeper-config集群模式部署配置文件(
zookeeper-cluster.yaml)apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zookeeper-data spec: accessModes: - ReadWriteOnce storageClassName: glusterfs resources: requests: storage: 10Gi --- apiVersion: v1 kind: Service metadata: name: zookeeper spec: selector: app: zookeeper ports: - protocol: TCP port: 2181 targetPort: 2181 --- apiVersion: v1 kind: ConfigMap metadata: name: zookeeper-config data: zoo.cfg: | tickTime=2000 dataDir=/data clientPort=2181 initLimit=5 syncLimit=2 server.1=zookeeper-0.zookeeper.default.svc.cluster.local:2888:3888 server.2=zookeeper-1.zookeeper.default.svc.cluster.local:2888:3888 server.3=zookeeper-2.zookeeper.default.svc.cluster.local:2888:3888 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: zookeeper spec: serviceName: zookeeper replicas: 3 selector: matchLabels: app: zookeeper template: metadata: labels: app: zookeeper spec: containers: - name: zookeeper image: zookeeper:3.7.0 resources: requests: cpu: 100m memory: 1Gi ports: - containerPort: 2181 volumeMounts: - name: zookeeper-data mountPath: /data env: - name: ZOOKEEPER_CONFIG_FILE value: /opt/zookeeper-3.7.0/conf/zoo.cfg volumes: - name: zookeeper-data persistentVolumeClaim: claimName: zookeeper-data - name: zookeeper-config configMap: name: zookeeper-config
分析完内容 , 我发现我好像懂了点 , 但是又没有完全懂 , 返回的结果中单节点和集群模式的配置文件看着差不太多 , 分析一下结果 , 顺便捋一下思路:
kind类型不同: 单节点是Deployment, 集群模式是StatefulSet, 这个目前看起来没毛病 , 思路是对的Deployment副本数为1,StatefulSet副本数为3集群模式没有使用
volumeClaimTemplates集群模式
zoo.cfg配置文件中多了几个server的配置项 , 但是好像没有实现myid的处理
1.2 搜索引擎
搜索引擎 , 在AI 助手出来以前在运维辅助中排名第一 , 现在暂居第二了 , 估计也没机会重回巅峰了(谨代表个人排名意见)。
看完了 AI 助手 的输出结果 , 觉得整体结构内容没问题 , 但是感觉细节上还是差那么点意思 , 尤其是集群模式的部署。我们会在本文第三小节验证。
同时 , 我还发现了一点 image: zookeeper:3.7.0 , 既然引用的 Image 是 DockerHub 官方的 , 那么 DockerHub 上一定有对应的 Image 及容器化部署的使用方法。
这也就带来一个新的灵感和一种新的学习方法 , 同时也是最简单直接的 Docker 部署转化为 Kubernetes 部署的方法 , 直接去看 Docker 的部署命令、启动命令、相关参数 , 然后直接搬到 K8s 上就可以。
直接转到 DokcerHub 官网 , 我们直接用关键词 zookeeper 搜索一下。
搜索结果截图:

简单的思考分析一下搜索结果:
排名最高的两个
zookeeper镜像 , 下载量都超过100M+, 分别是Docker官方和Bitnami出品的。上周下载量最多的是
Bitnami出品的zookeeper, 下载量高达1,140,215, 比DockerHub出品的zookeeper下载量681,115, 多了一倍还多。
为什么要做上面的分析?
当我们做开源技术选型的时候 , 主要的决定因素之一就是使用者数量 , 使用者太少说明产品还不成熟 , 代表着出了问题你都没地方寻求帮助。
我的技术选型几个原则:首选官方(
Apache官方没有 , 只能选DockerHub官方)、用户量大(100M+)、维护更新频繁(7 days ago)。除了
DockerHub出品的zookeeper镜像之外 ,Bitnami出品的镜像也是一个很好的选择 , 群众的眼睛是雪亮的 , 如果不好用也不可能这么多人推荐、下载。AI助手 给出的示例用的是DockerHub官方的镜像。
上面说了那么多 , 好像没有说到第二板斧的重点搜索引擎 , AI 助手 给出的结果中 , 单节点模式看着没什么问题 , 但是集群模式总感觉少点啥 , 重点的 myid 的处理方式我就没看到。因此 , 我又用关键词 StatefulSet 部署 Zookeeper 在搜索引擎中搜索了一番。
搜索结果中有两个方向的思路比较有参考价值:
基于 K8s 官方文档给出的
Zookeeper部署方案。K8s官网的一个教程案例 Running ZooKeeper, A Distributed System Coordinator , 这个例子看着比较复杂 , 而且引入了几个新的技术。基于
Bitnami制作的镜像提供的Zookeeper集群部署方案
梳理清楚已经获取的信息 , 为了快速完成领导交付的任务 , 今天的验证测试方案顺序如下:
AI助手 提供的单节点部署配置AI助手 提供的集群模式部署配置Bitnami提供的集群模式部署方案K8s官网Zookeeper部署案例
因为 , 单节点部署比较简单。所以 , 测试问题重点就在于 AI 助手和 Bitnami 提供的集群模式部署配置是否可行 , 如果方案可行就没官网案例什么事了 , 如果不行再去实验 K8s 官网 Zookeeper 部署案例 , 但是说实话我暂时还很不想碰 , 因为这个案例里有个技术点我压根儿就没听过 , 真要搞的话又会引入新的问题。
2. zookeeper单节点部署
我觉得 AI 助手 返回的单节点的部署方案和配置文件看着还可以没啥问题。但是 , 也不要直接复制、粘贴 , 拿来即用。一定要多参考 DockerHub 官网的 Zookeeper 相关示例 , 二者相结合 , 写出来的才是更靠谱的资源清单。
2.1 思路梳理
在 K8s 集群上部一套单节点的 Zookeeper 需要的资源清单如下:
PersistentVolumeClaimConfigMap:zoo.cfgDeploymentCluster ServiceExternal Service(可选)
知道了需要完成的任务目标 , 接下来结合 AI 助手给出的配置和官方配置参数 , 生成一套资源配置清单。
注意: 实践证明 , AI 助手 给出的也只是一个大概 , 细节还是有很多不足的地方 , 下面示例中的所有资源配置清单 , 都是参考官方配置参数和实际使用需求整理的。
简单说一下修改了哪些内容。
Zookeeper版本选择 , 使用了落后官方最新的稳定版3.9.0一个版本的3.8.2替换 AI 助手给出的配置方案中的3.7.0增加了
dataLog的配置完善了资源限制的配置
完善了
zoo.cfg的配置
2.2 资源配置清单
如无特殊说明 , 所有涉及 K8s 的操作都在 Master-0 节点上执行 , 配置文件根目录为 /srv/opsman/k8s-yaml。
创建资源清单文件夹
cd /srv/opsman/k8s-yaml mkdir -p zookeeper/single cd zookeeper/singlevi zookeeper-pvc.yaml--- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zookeeper-data spec: accessModes: - ReadWriteOnce storageClassName: glusterfs resources: requests: storage: 1Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zookeeper-datalog spec: accessModes: - ReadWriteOnce storageClassName: glusterfs resources: requests: storage: 2Gi说明: 后端存储类使用的 GlusterFS。
vi zookeeper-cm.yaml--- apiVersion: v1 kind: ConfigMap metadata: name: zookeeper-config data: zoo-cfg: | tickTime=2000 dataDir=/data dataLogDir=/datalog clientPort=2181 initLimit=10 syncLimit=5vi zookeeper-deploy.yaml--- apiVersion: apps/v1 kind: Deployment metadata: name: zookeeper spec: replicas: 1 selector: matchLabels: app: zookeeper template: metadata: labels: app: zookeeper spec: containers: - name: zookeeper image: zookeeper:3.8.2 resources: requests: cpu: 50m memory: 500Mi limits: cpu: '2' memory: 4000Mi ports: - name: zookeeper-2181 containerPort: 2181 protocol: TCP volumeMounts: - name: config mountPath: /conf - name: data mountPath: /data - name: datalog mountPath: /datalog volumes: - name: data persistentVolumeClaim: claimName: zookeeper-data - name: datalog persistentVolumeClaim: claimName: zookeeper-datalog - name: config configMap: name: zookeeper-config items: - key: zoo-cfg path: zoo.cfg --- apiVersion: v1 kind: Service metadata: name: zookeeper spec: ports: - name: zookeeper-2181 protocol: TCP port: 2181 targetPort: 2181 selector: app: zookeeper type: ClusterIPDeployment和Cluster Service放在了一个配置文件。vi zookeeper-external-svc.yaml--- apiVersion: v1 kind: Service metadata: name: zookeeper-external-svc labels: app: zookeeper-external-svc spec: ports: - name: tcp-zookeeper-external protocol: TCP port: 2181 targetPort: 2181 nodePort: 32181 selector: app: zookeeper type: NodePort注意:可选配置项 , 如果不需要被
K8s集群之外的服务访问 , 则不需要配置。
2.3 部署资源
验证
PersistentVolumeClaim[root@ks-master-0 single]# kubectl get pvc -o wide NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE zookeeper-data Bound pvc-371c9406-1757-451a-9c89-bed47ac71dd4 1Gi RWO glusterfs 12s Filesystem zookeeper-datalog Bound pvc-457a134c-0db2-4efc-902c-555daba2057e 2Gi RWO glusterfs 11s Filesystem验证
Deployment[root@ks-master-0 single]# kubectl get deploy -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR zookeeper 1/1 1 1 5m1s zookeeper zookeeper:3.8.2 app=zookeeper验证
Pod[root@ks-master-0 single]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES zookeeper-bcfc6cc5c-bh56m 1/1 Running 0 54s 10.233.120.8 ks-worker-1 <none> <none>验证 Service
[root@ks-master-0 single]# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR zookeeper ClusterIP 10.233.58.30 <none> 2181/TCP 59s app=zookeeper zookeeper-external-svc NodePort 10.233.40.37 <none> 2181:32181/TCP 59s app=zookeeper
2.4 Zookeeper 服务可用性验证
2.4.1 在 K8s 集群内部验证
在
K8s上创建一个Zookeeper Client Pod验证kubectl run zookeeper-client --image=zookeeper:3.8.2验证
Zookeeper Server连通性# 进入 Zookeeper Client 容器内部 kubectl exec -it zookeeper-client -- bash # 连接 Zookeeper Server bin/zkCli.sh -server 10.233.58.30:2181 # 成功结果如下 [root@ks-master-0 single]# kubectl exec -it zookeeper-client -- bash root@zookeeper-client:/apache-zookeeper-3.8.2-bin# bin/zkCli.sh -server 10.233.58.30:2181 Connecting to 10.233.58.30:2181 2023-08-07 07:44:16,110 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC 2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:host.name=zookeeper-client 2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.version=11.0.20 2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.vendor=Eclipse Adoptium 2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.home=/opt/java/openjdk 2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.class.path=/apache-zookeeper-3.8.2-bin/bin/......(此处有省略) 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.io.tmpdir=/tmp 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.compiler=<NA> 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.name=Linux 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.arch=amd64 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.version=5.10.0-153.12.0.92.oe2203sp2.x86_64 2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.name=root 2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.home=/root 2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.dir=/apache-zookeeper-3.8.2-bin 2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.free=42MB 2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.max=256MB 2023-08-07 07:44:16,120 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.total=48MB 2023-08-07 07:44:16,123 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=10.233.58.30:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@18bf3d14 2023-08-07 07:44:16,128 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation 2023-08-07 07:44:16,134 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes 2023-08-07 07:44:16,143 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false Welcome to ZooKeeper! 2023-08-07 07:44:16,171 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server zookeeper.default.svc.cluster.local/10.233.58.30:2181. 2023-08-07 07:44:16,173 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error) 2023-08-07 07:44:16,185 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /10.233.118.8:55022, server: zookeeper.default.svc.cluster.local/10.233.58.30:2181 JLine support is enabled 2023-08-07 07:44:16,251 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server zookeeper.default.svc.cluster.local/10.233.58.30:2181, session id = 0x1000178f5af0000, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: 10.233.58.30:2181(CONNECTED) 0]创建测试数据 , 验证服务可用性
# 创建测试数据 [zk: 10.233.58.30:2181(CONNECTED) 0] create /test test-data1 Created /test # 读取测试数据 [zk: 10.233.58.30:2181(CONNECTED) 1] get /test test-data1
2.4.2 在 K8s 集群外部验证
本文直接使用 K8s Master-0 节点安装 Zookeeper 客户端进行测试验证。
安装
openjdk, 仅限于测试验证。yum install java-11-openjdk安装
Zookeeper客户端 , 到Zookeeper官网找相应版本的软件包。本文选择3.8.2作为测试版本。# 下载并解压 Zookeeper ( 在国内源下载 ) wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz tar xvf apache-zookeeper-3.8.2-bin.tar.gz验证
Zookeeper Server连通性cd apache-zookeeper-3.8.2-bin/bin/ ./zkCli.sh -server 192.168.9.91:32181 # 成功结果如下 ( 结果有省略 ) [root@ks-master-0 bin]# ./zkCli.sh -server 192.168.9.91:32181 /usr/bin/java Connecting to 192.168.9.91:32181 2023-08-07 15:46:53,156 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC ...... WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: 192.168.9.91:32181(CONNECTED) 0]创建测试数据 , 验证服务可用性
# 创建测试数据 [zk: 192.168.9.91:32181(CONNECTED) 0] create /test2 test2-data1 Created /test2 # 读取测试数据 [zk: 192.168.9.91:32181(CONNECTED) 1] get /test2 test2-data1
至此 , Boss 交代的任务完成了一半 , 已经实现了单节点 Zookeeper 的部署 , 并在 K8s 集群内部和外部分别做了连通性、可用性测试。
但是 , 时间已超期 , 已经来到了第二天 , 所以说啊 , 对于一个未知的任务 , 实现起来 , 根本没有 Boss 想象的那么简单。
不过 , 由于完成了单节点的任务 , 先上交汇报给 Boss , 并说明一下实现思路、过程 , 部署过程中遇到的问题及解决方案 ( 切记不要直接跟 Boss 说这个很难 , 你预估的时间有问题 , 那么说纯属找抽 ) 。
按上面的套路汇报完 , 得到了 Boss 的理解和认可 ( Boss 其实还是很好说话的 , 只要你能以理说服他 ) , 让我先把单节点的 Zookeeper 环境交给测试使用 , 再去继续研究集群模式的部署方案。
这波操作不仅没有受到批评 , 还给自己争取了时间 , 完美!!!
3. 集群模式 Zookeeper 部署
单节点部署 Zookeeper 的任务完成以后 , 接下来开始研究集群模式的 Zookeeper 部署 , AI 助手给出的默认示例根本就不靠谱 , 我也懒得再调教他了。
为什么这么说?
因为我利用 AI 助手给的方案 , 利用 DockerHub 提供的 Zookeeper 去尝试在 K8s 集群上部署 Zookeeper 集群 , 耗时 2 天 ( 主要是犯病了 , 钻了牛角尖 , 就想搞定它 , 无奈能力又不够! )
接下来简单说一下 , 我被折磨疯了的两天都做了哪些尝试、遇到了哪些问题、有哪些心得体会 ( 逼得我都差点祭出第三板斧了 ) 。
集群模式的关键解决
myid和servers的配置servers的配置这个没有问题很好解决 , 可以在配置文件中直接写入或是用ENV的方式注入myid是重点 ,DockHub镜像仓库中提供的Zookeeper镜像 , 节点myid不能动态配置在实验中尝试了
initContainers、SidecarContainer、ConfigMap挂载启动脚本等方式 , 都没有起到效果不是说
DockHub镜像彻底不能用 , 只是需要进行启动脚本改造 , 甚至需要重新打Image, 太麻烦了 , 已经耗时 2 天了 , 不得不暂时放弃上面几种尝试以及最后的成品资源配置清单的编写 , 都是在
KubeSphere的图形化管理控制台下测试验证的 , 比命令行界面方便了太多心得: 通往成功的路有千万条 , 一条不通时可以尝试换条路 , 不要死磕到底。我们的目的是为了解决问题 , 能解决问题的办法就是好办法 , 钻牛角尖的精神也要分情况
最终只能另寻出路 , 好在之前的调研中 , 已经找到了另外两种可能的解决方案。
使用
Bitnami制作的镜像部署Zookeeper集群 ( 最终选择 ) 。Kubernetes官方文档示例中介绍的方案 , 该方案使用镜像registry.k8s.io/kubernetes-zookeeper:1.0-3.4.10, 使用PodDisruptionBudget确保服务可用性。
说一下最终的选型理由:
Pod Disruption Budget, 有点复杂不太适合我目前段位。
Pod Disruption Budget (Pod 干扰 预算) 简称 PDB , Kubernetes version >= 1.21 才可以使用 PodDisruptionBudget。PDB 的作用是将限制在同一时间因自愿干扰导致的多副本应用中发生宕机的 Pod 数量。
具体的知识点 , 本文不细说了 , 反正我目前也不打算用了 ( 唉!主要是说不明白难免误人子弟 ) , 有兴趣的可以参考官方文档的 PDB 介绍和 PDB 配置案例。
Bitnami制作的镜像部署Zookeeper集群 , 该方案网上的参考案例有很多 , 而且该方案采用Zookeeper原生部署方案 , 没有额外的K8S机制 , 减少了复杂度。这个也是选择的重点。
接下来 , 我就开始尝试使用 Bitnami 制作的 Zookeeper 镜像完成 Zookeeper 集群的部署。
3.1 思路梳理
在 K8s 集群上部一套 Zookeeper 集群需要的资源清单如下:
StatefulSetHeadless ServiceConfigMap:zoo.cfg( 没有使用 , 所有的配置都使用 ENV 的形式 )ConfigMap:setup.sh( 启动脚本 , 计划使用实际没有使用 , 最终采取了ENV和Command方式 )External Service( 可选 )
注意:由于本文配置方案没有考虑安全配置仅适用于开发、测试环境。不要把本文的示例直接拿到生产环境使用 , 必须参考官方配置文档增加相应的 ENV 配置 , 方可用于生产。
3.2 资源配置清单
如无特殊说明 , 所有涉及 K8s 的操作都在 Master-0 节点上执行 , 配置文件根目录为 /srv/opsman/k8s-yaml。
创建资源清单文件夹
cd /srv/opsman/k8s-yaml mkdir -p zookeeper/cluster cd zookeeper/clustervi zookeeper-svc.yaml--- # Headless Service , 用于 Zookeeper 集群之间相互通讯 apiVersion: v1 kind: Service metadata: name: zk-hs labels: app: zookeeper spec: ports: - name: tcp-client protocol: TCP port: 2181 targetPort: 2181 - name: tcp-follower port: 2888 targetPort: 2888 - name: tcp-election port: 3888 targetPort: 3888 selector: app: zookeeper clusterIP: None type: ClusterIP --- # Client Service , 用于 K8S 集群内的应用访问 Zookeeper apiVersion: v1 kind: Service metadata: name: zk-cs labels: app: zookeeper spec: ports: - name: tcp-client protocol: TCP port: 2181 targetPort: 2181 selector: app: zookeeper type: ClusterIPvi zookeeper-sts.yaml--- apiVersion: apps/v1 kind: StatefulSet metadata: name: zookeeper labels: app: zookeeper spec: replicas: 3 selector: matchLabels: app: zookeeper serviceName: zk-hs template: metadata: name: zookeeper labels: app: zookeeper spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: "app" operator: In values: - zookeeper topologyKey: "kubernetes.io/hostname" containers: - name: zookeeper image: bitnami/zookeeper:3.8.2 command: - bash - '-ec' - | HOSTNAME="$(hostname -s)" if [[ $HOSTNAME =~ (.*)-([0-9]+)$ ]]; then ORD=${BASH_REMATCH[2]} export ZOO_SERVER_ID="$((ORD + 1 ))" else echo "Failed to get index from hostname $HOST" exit 1 fi exec /entrypoint.sh /run.sh resources: limits: cpu: 1 memory: 2Gi requests: cpu: 50m memory: 500Mi env: - name: ZOO_ENABLE_AUTH value: "no" - name: ALLOW_ANONYMOUS_LOGIN value: "yes" - name: ZOO_SERVERS value: > zookeeper-0.zk-hs.default.svc.cluster.local:2888:3888 zookeeper-1.zk-hs.default.svc.cluster.local:2888:3888 zookeeper-2.zk-hs.ddefault.svc.cluster.local:2888:3888 ports: - name: client containerPort: 2181 - name: follower containerPort: 2888 - name: election containerPort: 3888 livenessProbe: tcpSocket: port: client failureThreshold: 6 initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 readinessProbe: tcpSocket: port: client failureThreshold: 6 initialDelaySeconds: 5 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 volumeMounts: - name: data mountPath: /bitnami/zookeeper volumeClaimTemplates: - metadata: name: data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "glusterfs" resources: requests: storage: 2Gi说明:
ENV的配置我只用了最基本的 , 重点就是ZOO_SERVERS, 更多参数的用法请参考Bitnami官方文档Command里直接写了启动命令 , 也可以做成ConfigMap挂载为脚本default.svc.cluster.local, 注意FQDN只能这么写 , 不要写成自定义的 , 哪怕我的集群域名是opsman.top( 这个是遗留问题 , 来不及细看了 , 回头再说 )
vi zookeeper-external-svc.yaml--- # External Client Service , 用于 K8S 集群外部访问 Zookeeper apiVersion: v1 kind: Service metadata: name: zookeeper-external-svc labels: app: zookeeper-external-svc spec: ports: - name: tcp-zookeeper-external protocol: TCP port: 2181 targetPort: 2181 nodePort: 32181 selector: app: zookeeper type: NodePort注意:可选配置项 , 如果不需要被 K8s 集群之外的服务访问 , 则不需要配置。
3.3 部署资源
部署
Cluster和Headless Servicekubectl apply -f zookeeper-svc.yaml部署
StatefulSetkubectl apply -f zookeeper-sts.yaml部署外部
Serviceskubectl apply -f zookeeper-external-svc.yaml
3.4 Zookeeper服务可用性验证
3.4.1 K8s 部署资源验证
验证
PersistentVolumeClaim[root@ks-master-0 cluster]# kubectl get pvc -o wide NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE data-zookeeper-0 Bound pvc-342c3869-17ca-40c7-9db0-755d5af0f85f 2Gi RWO glusterfs 2m7s Filesystem data-zookeeper-1 Bound pvc-6744813f-0f5b-4138-8ffc-387f63044af3 2Gi RWO glusterfs 47s Filesystem data-zookeeper-2 Bound pvc-731edc8d-189a-4601-aa64-a8d6754d93ec 2Gi RWO glusterfs 28s Filesystem验证
StatefulSet[root@ks-master-0 cluster]# kubectl get sts -o wide NAME READY AGE CONTAINERS IMAGES zookeeper 3/3 2m3s zookeeper bitnami/zookeeper:3.8.2验证
Pod[root@ks-master-0 cluster]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES zookeeper-0 1/1 Running 0 2m42s 10.233.118.45 ks-worker-2 <none> <none> zookeeper-1 1/1 Running 0 83s 10.233.120.17 ks-worker-1 <none> <none> zookeeper-2 1/1 Running 0 64s 10.233.115.99 ks-worker-0 <none> <none>验证
Service[root@ks-master-0 cluster]# kubectl get svc -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR zk-cs ClusterIP 10.233.43.229 <none> 2181/TCP 3m58s app=zookeeper zk-hs ClusterIP None <none> 2181/TCP,2888/TCP,3888/TCP 3m58s app=zookeeper zookeeper-external-svc NodePort 10.233.45.5 <none> 2181:32181/TCP 10s app=zookeeper
3.4.2 Zookeeper 集群状态验证
验证
StatefulSet创建的Pod配置的主机名[root@ks-master-0 cluster]# for i in 0 1 2; do kubectl exec zookeeper-$i -- hostname; done zookeeper-0 zookeeper-1 zookeeper-2验证
StatefulSet创建的Pod配置的完全限定域名(Fully Qualified Domain Name,FQDN)[root@ks-master-0 cluster]# for i in 0 1 2; do kubectl exec zookeeper-$i -- hostname -f; done zookeeper-0.zk-hs.default.svc.cluster.local zookeeper-1.zk-hs.default.svc.cluster.local zookeeper-2.zk-hs.default.svc.cluster.local验证每个
Zookeeper服务的myid文件内容[root@ks-master-0 cluster]# for i in 0 1 2; do echo "myid zookeeper-$i";kubectl exec zookeeper-$i -- cat /bitnami/zookeeper/data/myid; done myid zookeeper-0 1 myid zookeeper-1 2 myid zookeeper-2 3验证
Zookeeper生成的配置文件[root@ks-master-0 cluster]# kubectl exec -it zookeeper-0 -- cat /opt/bitnami/zookeeper/conf/zoo.cfg | grep -vE "^#|^$" tickTime=2000 initLimit=10 syncLimit=5 dataDir=/bitnami/zookeeper/data clientPort=2181 maxClientCnxns=60 autopurge.snapRetainCount=3 autopurge.purgeInterval=0 preAllocSize=65536 snapCount=100000 maxCnxns=0 reconfigEnabled=false quorumListenOnAllIPs=false 4lw.commands.whitelist=srvr, mntr maxSessionTimeout=40000 admin.serverPort=8080 admin.enableServer=true server.1=zookeeper-0.zk-hs.default.svc.cluster.local:2888:3888;2181 server.2=zookeeper-1.zk-hs.default.svc.cluster.local:2888:3888;2181 server.3=zookeeper-2.zk-hs.default.svc.cluster.local:2888:3888;2181验证集群状态
[root@ks-master-0 cluster]# for i in 0 1 2; do echo -e "# myid zookeeper-$i \n";kubectl exec zookeeper-$i -- /opt/bitnami/zookeeper/bin/zkServer.sh status;echo -e "\n"; done # myid zookeeper-0 /opt/bitnami/java/bin/java ZooKeeper JMX enabled by default Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: leader # myid zookeeper-1 /opt/bitnami/java/bin/java ZooKeeper JMX enabled by default Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: follower # myid zookeeper-2 /opt/bitnami/java/bin/java ZooKeeper JMX enabled by default Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: follower
3.4.3 Zookeeper 服务可用性验证
3.4.3.1 在 K8s 集群内部验证。
在
K8s上创建一个Zookeeper Client Pod验证 ( 单节点验证时创建过 , 不需要再创建了 )kubectl run zookeeper-client --image=zookeeper:3.8.2验证
Zookeeper Server连通性# 进入 Zookeeper Client 容器内部 kubectl exec -it zookeeper-client -- bash # 连接 Zookeeper Server ( 10.233.43.229 是 Cluster Service 的 IP ) bin/zkCli.sh -server 10.233.43.229:2181 # 成功结果如下(内容有省略) [root@ks-master-0 cluster]# kubectl exec -it zookeeper-client -- bash root@zookeeper-client:/apache-zookeeper-3.8.2-bin# bin/zkCli.sh -server 10.233.43.229:2181 Connecting to 10.233.43.229:2181 2023-08-08 10:08:40,864 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC ..... 2023-08-08 10:08:40,872 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=10.233.43.229:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@18bf3d14 2023-08-08 10:08:40,886 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation 2023-08-08 10:08:40,892 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes 2023-08-08 10:08:40,903 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false Welcome to ZooKeeper! 2023-08-08 10:08:40,920 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server zk-cs.default.svc.cluster.local/10.233.43.229:2181. 2023-08-08 10:08:40,923 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error) JLine support is enabled 2023-08-08 10:08:40,948 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /10.233.118.8:38050, server: zk-cs.default.svc.cluster.local/10.233.43.229:2181 2023-08-08 10:08:41,064 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server zk-cs.default.svc.cluster.local/10.233.43.229:2181, session id = 0x10007253d840000, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: 10.233.43.229:2181(CONNECTED) 0]创建测试数据 , 验证服务可用性
# 创建测试数据 [zk: 10.233.43.229:2181(CONNECTED) 0] create /test test-data1 Created /test # 读取测试数据 [zk: 10.233.43.229:2181(CONNECTED) 1] get /test test-data1
3.4.3.2 在 K8s 集群外部验证。
验证
Zookeeper Server连通性# 进入 Zookeeper 安装包的 bin 目录 cd apache-zookeeper-3.8.2-bin/bin/ # 连接 Zookeeper Server ( 192.168.9.91 是 K8S Master-0 节点的 IP , 32181 是 External Service 定义的 NodePort 端口号 ) ./zkCli.sh -server 192.168.9.91:32181 # 成功结果如下 ( 结果有省略 ) [root@ks-master-0 bin]# ./zkCli.sh -server 192.168.9.91:32181 /usr/bin/java Connecting to 192.168.9.91:32181 2023-08-08 18:13:52,650 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC ...... 2023-08-08 18:13:52,660 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=192.168.9.91:32181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@5c072e3f 2023-08-08 18:13:52,666 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation 2023-08-08 18:13:52,671 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes 2023-08-08 18:13:52,686 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false Welcome to ZooKeeper! 2023-08-08 18:13:52,708 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server ks-master-0/192.168.9.91:32181. 2023-08-08 18:13:52,709 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error) JLine support is enabled 2023-08-08 18:13:52,721 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /192.168.9.91:45004, server: ks-master-0/192.168.9.91:32181 2023-08-08 18:13:52,776 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server ks-master-0/192.168.9.91:32181, session id = 0x10007253d840001, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: 192.168.9.91:32181(CONNECTED) 0]创建测试数据 , 验证服务可用性
# 创建测试数据 [zk: 192.168.9.91:32181(CONNECTED) 0] create /test2 test2-data1 Created /test2 # 读取测试数据 ( 读取了 2次 测试数据 ) [zk: 192.168.9.91:32181(CONNECTED) 1] get /test test-data1 [zk: 192.168.9.91:32181(CONNECTED) 2] get /test2 test2-data1
至此 , 实现了 Zookeeper 集群模式部署 , 并在 K8S 集群内部和外部分别做了连通性、可用性测试。
###
参考链接
KubeSphere 部署 Zookeeper 实战教程 (qq.com)