场景说明

某云提供商网络技术更新迭代,遗留下了基础网络和 VPC 网络两种网络架构,我们公司目前的服务器还大多都在基础网络中。我在新环境中搭建了 kubernetes 集群,并在上面部署了高可用的 zookeeper 集群。配置中心方案是一个全局方案,公司大大小小的项目陆陆续续都会上,为了便于维护与迁移,我们采用一套环境统一管理。此时,集群内的 zookeeper 已经由 helm 部署完成。

需求

  • 一台已经安装了 docker 和 docker-compose 的位于基础网络服务器(作为 zookeeper observer,为避免单点故障最好备两台及以上)
  • 已经安装好三个结点的 zookeeper 的 kubernetes 的集群

操作流程

1. 基础网络互通

这个步骤具体怎么做我就不提了,每个云服务商可能不同,但并不是什么难点。达到的效果就是将 kubernetes 集群所在的 VPC 和 observer 服务器可以互联互通

2. 向内网暴露 zk 集群相关服务

利用 statefulSet 会为每个 pod 生成的一个特殊的 label,为每一个 zookeeper 的 pod 建立内网 LB 类型的 Service。
这里有一个创建其中一个 svc 的例子:

apiVersion: v1
kind: Service
metadata:
  annotations: # 这里边是与云服务商强相关的一些配置,不具备通用性但仍然具有参考价值,这里需要配置不然默认是公网 LB
    service.kubernetes.io/qcloud-loadbalancer-clusterid: cls-xxxxxx # 确定 tke 集群
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxxx # 确定子网
  name: zk0
  namespace: kube-public # zk 所在的 ns
spec:
  ports:
  - name: tcp-2888-2888 # 数据同步端口
    port: 2888
    protocol: TCP
    targetPort: 2888
  - name: tcp-3888-3888 # 选举端口
    port: 3888
    protocol: TCP
    targetPort: 3888
  selector:
    app: zookeeper
    component: server
    release: xxx
    statefulset.kubernetes.io/pod-name: xxx-zookeeper-0 # 有了这个其实其它 label 可以省略
  type: LoadBalancer # service 类型

创建完成后,可以通过命令查看 LB 的 ip 地址:

[root@VM_64_11_centos zookeeper]# kubectl -n kube-public get svc
NAME                      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                         AGE
zk0                       LoadBalancer   172.16.255.8     10.1.0.12     2888:30734/TCP,3888:30513/TCP   2d15h
zk1                       LoadBalancer   172.16.255.66    10.1.0.13     2888:32569/TCP,3888:32718/TCP   2d14h
zk2                       LoadBalancer   172.16.255.105   10.1.0.6      2888:32189/TCP,3888:30692/TCP   2d14h

EXTERNAL-IP 即为 LB 的 ip 地址,我们可以通过这个地址访问到对应的 pod 在 2888 和 3888 两个端口上提供的服务。记录下这三个 IP 地址,在配置 observer 的时候会用到。

3. 创建 observer 所需环境

根据上一步得到的 ip,创建配置文件。

mkdir -p /data/zookeeper/
cd /data/zookeeper/
cat > zoo.cfg << EOF
clientPort=2181
dataDir=/var/lib/zookeeper/data
dataLogDir=/var/lib/zookeeper/log
tickTime=2000
initLimit=5
syncLimit=10
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
autopurge.snapRetainCount=3
autopurge.purgeInteval=0
peerType=observer
4lw.commands.whitelist=*
server.1=10.1.0.12:2888:3888
server.2=10.1.0.13:2888:3888
server.3=10.1.0.6:2888:3888
server.4=localhost:2888:3888:observer
EOF

创建存储

docker volume create zookeeper_data
mkdir -p /var/lib/docker/volumes/zookeeper_data/_data/data/version-2/ /var/lib/docker/volumes/zookeeper_data/_data/log/version-2/
echo 4 > /var/lib/docker/volumes/zookeeper_data/_data/data/myid
chown 1000:1000 /var/lib/docker/volumes/zookeeper_data/_data/data/version-2/ /var/lib/docker/volumes/zookeeper_data/_data/log/version-2/

创建 docker-compose.yaml

cat > docker-compose.yaml << EOF
version: "3"
services:
  zookeeper:
    image: zookeeper
    ports:
    - "2181:2181"
    volumes:
      - "./zoo.cfg:/conf/zoo.cfg"
      - "data:/var/lib/zookeeper"
  exporter:
    depends_on:
    - zookeeper
    image: josdotso/zookeeper-exporter:v1.1.2
    ports:
    - "9141:9141"
    command:
    - -bind-addr=:9141
    - -metrics-path=/metrics
    - -zookeeper=zookeeper:2181
    - -log-level=info
    - -reset-on-scrape=true

volumes:
  data:
EOF

4. 启动 observer

docker-compose up -d

至此 zookeeper observer 已经启动

5. 为 observer 配置监控

思路:将集群外的 observer 以无 selector 的 service 的形式挂到 kubernetes 集群中,打好 label 供 serviceMonitor 匹配即可

创建文件 zk-ob-external.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    app: zookeeper
    release: xxx
    position: external
  name: xxx-zookeeper-external
spec:
  ports:
  - name: zookeeperxp
    port: 9141
    protocol: TCP
    targetPort: zookeeperxp
---
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    app: zookeeper
    release: xxx
    position: external
  name: xxx-zookeeper-external
subsets:
- addresses:
  - ip: 10.104.170.174
  - ip: 10.104.42.205
  ports:
  - name: zookeeperxp
    port: 9141
    protocol: TCP

注意 label 要与对应 serviceMonitor 中 selector.matchLabels 匹配,端口名要一致

其它

超级管理员

在给 zookeeper 配置权限时,由于需要加密的缘故,很多新手都容易配错,配错后对应的结点就无法删除了。在 zookeeper 中并没有什么超管可以无视 ACL 删除结点,所以我遍寻 zookeeper 的超级管理权限不得法。想要无视 ACL 对 Zookeeper 数据进行操作,只需找一个 zk 服务在配置文件中加入skipACL=yes并重启服务即可,操作完成后记得注释掉这个配置并重启服务,因为没有 ACL 的 zk 很不安全。为了降低重启服务所带来的风险,建议在 observer 上进行该操作。