随着云原生化流行的大趋势,我们的基础组件也需要逐渐上Kubernetes了。Apache Zookeeper作为目前最流行的分布式协调组件,在我们的微服务架构中负责扮演注册中心的角色。
在Kubernetes中运行Zookeeper集群是很有意义的,可以利用其原生的弹性扩缩容、高可用特性。
先说下使用的k8s的版本是1.25.0,对于PodDisruptionBudget的apiVersion会有影响,某些更老的k8s版本,apiVersion是policy/v1bata,1.25.0的k8s对应的apiVersion是policy/v1。
使用StatefulSet部署Zookeeper
官方提供了使用statefulSet的方式来部署 Zookeeper 运行 Zookeeper,它会创建一个headless service,一个cluster service,一个podDisruptionBudget,一个statefulSet。
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: zk-pv
- spec:
- capacity:
- storage: 512Mi
- accessModes:
- - ReadWriteOnce
- hostPath:
- path: /data
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: zk-hs
- labels:
- app: zk
- spec:
- ports:
- - port: 2888
- name: server
- - port: 3888
- name: leader-election
- clusterIP: None
- selector:
- app: zk
- ---
- apiVersion: v1
- kind: Service
- metadata:
- name: zk-cs
- labels:
- app: zk
- spec:
- ports:
- - port: 2181
- name: client
- selector:
- app: zk
- ---
- apiVersion: policy/v1
- kind: PodDisruptionBudget
- metadata:
- name: zk-pdb
- spec:
- selector:
- matchLabels:
- app: zk
- maxUnavailable: 1
- ---
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: zk
- spec:
- selector:
- matchLabels:
- app: zk
- serviceName: zk-hs
- replicas: 3
- updateStrategy:
- type: RollingUpdate
- podManagementPolicy: OrderedReady
- template:
- metadata:
- labels:
- app: zk
- spec:
- affinity:
- podAntiAffinity:
- requiredDuringSchedulingIgnoredDuringExecution:
- - labelSelector:
- matchExpressions:
- - key: "app"
- operator: In
- values:
- - zk
- topologyKey: "kubernetes.io/hostname"
- containers:
- - name: kubernetes-zookeeper
- imagePullPolicy: IfNotPresent
- image: "harbor.martin.cc/google_containers/kubernetes-zookeeper:1.0-3.4.10"
- resources:
- requests:
- memory: "0.5Gi"
- cpu: "0.5"
- ports:
- - containerPort: 2181
- name: client
- - containerPort: 2888
- name: server
- - containerPort: 3888
- name: leader-election
- command:
- - sh
- - -c
- - "start-zookeeper \
- --servers=3 \
- --data_dir=/var/lib/zookeeper/data \
- --data_log_dir=/var/lib/zookeeper/data/log \
- --conf_dir=/opt/zookeeper/conf \
- --client_port=2181 \
- --election_port=3888 \
- --server_port=2888 \
- --tick_time=2000 \
- --init_limit=10 \
- --sync_limit=5 \
- --heap=512M \
- --max_client_cnxns=60 \
- --snap_retain_count=3 \
- --purge_interval=12 \
- --max_session_timeout=40000 \
- --min_session_timeout=4000 \
- --log_level=INFO"
- readinessProbe:
- exec:
- command:
- - sh
- - -c
- - "zookeeper-ready 2181"
- initialDelaySeconds: 10
- timeoutSeconds: 5
- livenessProbe:
- exec:
- command:
- - sh
- - -c
- - "zookeeper-ready 2181"
- initialDelaySeconds: 10
- timeoutSeconds: 5
- volumeMounts:
- - name: datadir
- mountPath: /var/lib/zookeeper
- securityContext:
- runAsUser: 1000
- fsGroup: 1000
- volumeClaimTemplates:
- - metadata:
- name: datadir
- spec:
- accessModes: [ "ReadWriteOnce" ]
- resources:
- requests:
- storage: 512Mi
使用 kubectl apply应用这个配置文件,等待一会之后,发现pod和service都已创建成功。
kubectl get pod 查看到 zk-0 pod一直pending.
kubectl describe pod zk-0 看到事件原因是:
0/4 nodes are available: 4 pod has unbound immediate PersistentVolumeClaims. preemption: 0/4 nodes are available: 4 Preemption is not helpful for scheduling.
再使用:
kubectl logs -n kube-system kube-controller-manager-k8s-master01.example.local
查看controller-manager的pod日志:
I0513 08:13:08.710572 1 event.go:294] "Event occurred" object="default/datadir-zk-0" fieldPath="" kind="PersistentVolumeClaim" apiVersion="v1" type="Normal" reason="FailedBinding" message="no persistent volumes available for this claim and no storage class is set"
这么看,原来PV和 storage class 都没搞。这个网上的参考还是需要自己补充一下的,PV的API定义已经加到上面的资源清单了。
PV弄了个HostPath的。但是也不知道存在哪个节点上。
然后再执行kubectl apply -f zookeeper.yml创建,POD zk-0未启动成功,出来错误CrashLoopBackOff。通过kubectl logs zk-0查看POD日志:
#This file was autogenerated DO NOT EDIT clientPort=2181 dataDir=/var/lib/zookeeper/data dataLogDir=/var/lib/zookeeper/data/log tickTime=2000 initLimit=10 syncLimit=5 maxClientCnxns=60 minSessionTimeout=4000 maxSessionTimeout=40000 autopurge.snapRetainCount=3 autopurge.purgeInteval=12 server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888 server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888 server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888 Creating ZooKeeper log4j configuration mkdir: cannot create directory '/var/lib/zookeeper/data': Permission denied chown: cannot access '/var/lib/zookeeper/data': No such file or directory mkdir: cannot create directory '/var/lib/zookeeper/data': Permission denied chown: invalid group: 'zookeeper:USER' /usr/bin/start-zookeeper: line 176: /var/lib/zookeeper/data/myid: No such file or directory
有个疑问,这个日志是一直存着吗,还是POD没启动成功,我用kubectl delete -f zookeeper删除掉POD,再看下,还有没有这个日志。肯定没了:
kubectl logs zk-0
Error from server (NotFound): pods "zk-0" not found
原来是POD及容器对于卷的目录主机目录没有写与创建子目录的权限。把对应的目录POD部署节点的目录 /data/,权限修改成全部可以读写创建:
chmod 777 /data/
重启后,还是有问题:
发现pod zk-0启动成功了,但是到了zk-1启动失败,原来是每个pod要创建一个hostPath的PV。接下来创建两个zk-pv1,zk-pv2,在node2和node3上创建好对应的host文件夹/data/,并设置权限777。然后重启,三个pod都启动成功了。
恭喜自己,部署看起来是成功了,那么就真正测试一下部署好的zk集群吧。
要测试在 Kubernetes 上部署的 ZooKeeper 集群,可以执行以下步骤:
获取 ZooKeeper 的客户端工具,例如 ZooKeeper 命令行客户端 zkCli.sh
。可以在 ZooKeeper 的官方网站下载安装包,并解压获取相关工具。
进入 Kubernetes 集群中的任意一个 Pod,可以使用 kubectl exec
命令进入 Pod 的容器内部。
kubectl exec -it -- /bin/bash
在容器内部,使用 ZooKeeper 客户端工具连接到 ZooKeeper 集群。根据您的部署方式和服务发现配置,可以使用 Service 名称或 Pod IP 连接到 ZooKeeper。
./zkCli.sh -server :
或者
./zkCli.sh -server :
这里的
是您 ZooKeeper 服务的名称,
是服务的端口号。如果您使用的是 StatefulSet 部署方式,可以使用 zk-{index}.
的方式连接到每个 ZooKeeper Pod。
连接成功后,您可以执行各种 ZooKeeper 的命令和操作,例如创建节点、设置数据、监听事件等。可以通过命令 help
或 ?
获取更多可用的命令列表和用法。
- [zk:
:] help - [zk:
:] ?
例如,可以使用以下命令创建一个节点并设置数据:
[zk: :] create /test mydata
然后使用以下命令获取节点的数据:
[zk: :] get /test
通过执行各种命令和操作,可以验证 ZooKeeper 集群的功能和可用性。
请注意,上述命令中的
和
需要替换为实际的 ZooKeeper 服务名称和端口。具体的连接信息取决于您的部署方式和配置。
都是验证通过的,说明安装成功了,Oh Yeah!
附:安装的容器镜像描述信息:
The ZooKeeper package is installed into the /opt/zookeeper directory, all configuration is sym linked into the /usr/etc/zookeeper/, and all executables are sym linked into /usr/bin. The ZooKeeper data directories are contained in /var/lib/zookeeper. This is identical to the RPM distribution that users should be familiar with.
所以 /var/lib/zookeeper这个文件夹是放数据的,所以我们就明白为什么要把这个文件夹放到PV了。