基于 Kubernetes 部署 Zookeeper(StatefulSet方式)

随着云原生化流行的大趋势,我们的基础组件也需要逐渐上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 集群,可以执行以下步骤:

  1. 获取 ZooKeeper 的客户端工具,例如 ZooKeeper 命令行客户端 zkCli.sh。可以在 ZooKeeper 的官方网站下载安装包,并解压获取相关工具。

  2. 进入 Kubernetes 集群中的任意一个 Pod,可以使用 kubectl exec 命令进入 Pod 的容器内部。

    kubectl exec -it  -- /bin/bash

  3. 在容器内部,使用 ZooKeeper 客户端工具连接到 ZooKeeper 集群。根据您的部署方式和服务发现配置,可以使用 Service 名称或 Pod IP 连接到 ZooKeeper。

    ./zkCli.sh -server :

    或者

    ./zkCli.sh -server :

    这里的 是您 ZooKeeper 服务的名称, 是服务的端口号。如果您使用的是 StatefulSet 部署方式,可以使用 zk-{index}. 的方式连接到每个 ZooKeeper Pod。

  4. 连接成功后,您可以执行各种 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了。

你可能感兴趣的:(#,kubernetes,java,docker)