美文网首页
配置Kubernates方式启动Zookeeper集群

配置Kubernates方式启动Zookeeper集群

作者: 大猪小猪在菜盘 | 来源:发表于2019-06-17 23:13 被阅读0次

    本文使用的ZooKeeper官方镜像版本为3.5,可以去Docker Hub查看此版本镜像的Dockerfile文件

    1. 单机启动一个简单的三点集群

    ZooKeeper 可以很方便的用docker-compose方式在单机启动一个三点以上的集群,样例编排脚本如下:

    version: '3.1'
    
    services:
      zoo1:
        image: zookeeper
        restart: always
        hostname: zoo1
        ports:
          - 2181:2181
        environment:
          ZOO_MY_ID: 1
          ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
    
      zoo2:
        image: zookeeper
        restart: always
        hostname: zoo2
        ports:
          - 2182:2181
        environment:
          ZOO_MY_ID: 2
          ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181
    
      zoo3:
        image: zookeeper
        restart: always
        hostname: zoo3
        ports:
          - 2183:2181
        environment:
          ZOO_MY_ID: 3
          ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181
    

    核心配置部分即为配置ZooKeeper地址的ZOO_SERVERS和配置ZooKeeper的服务ID即ZOO_MY_ID。

    ZooKeeper一共需要用到三个端口,端口的功能如下:

    1、2181:对cline端提供服务
    2、3888:选举leader使用
    3、2888:集群内机器通讯使用(Leader监听此端口)
    

    调试的时候使用docker-compose启动一个单机的集群是非常合适的,到了测试环境和生产环境,集群化的部署和高可用已经使必然。我们接下来就过渡到K8S集群环境中部署ZooKeeper

    2. K8S部署思路

    网上有大牛们的类似搭建文章例如k8s部署zookeeper/kakfa集群,看了之后发现虽然能满足功能但是启动了三个Deployment再用Service去对外暴露统一域名这种方式。而ZooKeeper是一个有状态的集群,StatefulSet+Headless Service方式来创建工作负载更加合适。另外推荐用一个StatefulSet的原因是相比与多个Deployment,StatefulSet更加容易通过脚本和环境变量扩展。

    StatefulSet+HeadlessService方式下,每个ZooKeeper节点都有类似如下的域名:

    zookeeper-service-0.zookeeper-service.namespace.svc.cluster.local:2888:3888;2181 
    zookeeper-service-1.zookeeper-service.namespace.svc.cluster.local:2888:3888;2181 
    zookeeper-service-2.zookeeper-service.namespace.svc.cluster.local:2888:3888;2181 
    ...
    zookeeper-service-N.zookeeper-service.namespace.svc.cluster.local:2888:3888;2181 
    

    联想到官方镜像提供的一个docker-compose编排脚本中的ZOO_SERVERS环境变量格式,我们很容易联想到,在StatefulSet的环境变量配置中,将ZOO_SERVERS设置成为

    zookeeper-service-N.zookeeper-service.namespace.svc.cluster.local:2888:3888;2181
    

    问题来了,没法对单个POD设置这个地址,如果在StatefulSet中设置这个地址,所有的POD又将共享同一地址,没法启动集群。因此我们需要做改造

    3. 适用于K8S的镜像改造

    最容易想到的还是设法修改启动脚本,让每个POD在启动时候,拥有不同的参数来创建这个ZOO_SERVERS和ZOO_MY_ID。我们可以编写如下的脚本:

    #!/bin/bash
    
    #MINE_MIDWARE_NAMESPACE=ns-mine-midware
    #MINE_ZOOKEEPER_SERVICE=mine-zookeeper-service
    #MINE_ZOOKEEPER_REPLICAS=3
    #MINE_ZOOKEEPER_POD=mine-zookeeper-service
    
    echo ${MINE_MIDWARE_NAMESPACE}   #namespace
    echo ${MINE_ZOOKEEPER_SERVICE}   #service
    echo ${MINE_ZOOKEEPER_REPLICAS}  #replica count
    echo ${MINE_ZOOKEEPER_POD}       #podname
    
    ZK_HOSTNAME=$(hostname)
    
    # 解析格式如下:"mine-zookeeper-service-2"
    ZK_ID=$( echo ${T_HOSTNAME} | cut -d "-" -f4 | cut -d "-" -f3 )
    ZK_HOST_POSTFIX="$MINE_ZOOKEEPER_SERVICE.$MINE_MIDWARE_NAMESPACE.svc.cluster.local"
    
    if [[ -n "${MINE_ZOOKEEPER_REPLICAS-}" ]]
    then
      i=0
      while [[ ${i} -lt ${MINE_ZOOKEEPER_REPLICAS} ]]; do
        tmp=""
        idx=$(($i+1))
        if [[ ${i} -eq ${T_ID} ]]; then
          tmp="server.$idx=0.0.0.0:2888:3888;2181 "
        else
          tmp="server.$idx=$MINE_ZOOKEEPER_POD-$i.$ZK_HOST_POSTFIX:2888:3888;2181 "
        fi
        ZOOKEEPER_SERVERS="$ZOOKEEPER_SERVERS$tmp"
        i=$(( i + 1 ))
      done
    fi
    
    ZOOKEEPER_SERVERS=${ZOOKEEPER_SERVERS%?}
    
    export ZOO_MY_ID=$(($T_ID+1))
    export ZOO_SERVERS=${ZOOKEEPER_SERVERS}
    
    echo ${ZOO_MY_ID}
    echo ${ZOO_SERVERS}
    

    以上的脚本通过四个输入的环境变量

    MINE_MIDWARE_NAMESPACE
    MINE_ZOOKEEPER_SERVICE
    MINE_ZOOKEEPER_REPLICAS
    MINE_ZOOKEEPER_POD
    

    来创建ZOO_SERVERS和ZOO_MY_ID。这四个环境变量可以配置在StatefulSet中。创建了这个脚本之后,我们再扩展一下官方的Dockerfile:

    FROM zookeeper:3.5
    MAINTAINER simon.zhu.chn@hotmail.com
    
    ADD zk-config.sh /
    
    ENTRYPOINT ["/bin/bash", "-c", "source zk-config.sh && /docker-entrypoint.sh"]
    

    这样子我们就能再启动docker-entrypoint之前优先将环境变量输出提供给官方镜像使用。

    4. 微该官方镜像

    构建完镜像之后在K8S中启动集群,发现无法正常启动。
    具体原因是因为官方镜像脚本的docker-entrypoint.sh最后一行中引用了CMD中的启动参数。因为我们已经修改了ENTRYPIONT,所以,官方镜像的启动配置的docker-entrypoint.sh也需要做修改。

    首先我们去git上拉取官方的镜像源码,然后修改docker-entrypoint.sh脚本

    #!/bin/bash
    
    set -e
    
    # Allow the container to be started with `--user`
    if [[ "$1" = 'zkServer.sh' && "$(id -u)" = '0' ]]; then
        chown -R zookeeper "$ZOO_DATA_DIR" "$ZOO_DATA_LOG_DIR" "$ZOO_LOG_DIR" "$ZOO_CONF_DIR"
        exec gosu zookeeper "$0" "$@"
    fi
    
    # Generate the config only if it doesn't exist
    if [[ ! -f "$ZOO_CONF_DIR/zoo.cfg" ]]; then
        CONFIG="$ZOO_CONF_DIR/zoo.cfg"
    
        echo "clientPort=2181" >> "$CONFIG"
        echo "dataDir=$ZOO_DATA_DIR" >> "$CONFIG"
        echo "dataLogDir=$ZOO_DATA_LOG_DIR" >> "$CONFIG"
    
        echo "tickTime=$ZOO_TICK_TIME" >> "$CONFIG"
        echo "initLimit=$ZOO_INIT_LIMIT" >> "$CONFIG"
        echo "syncLimit=$ZOO_SYNC_LIMIT" >> "$CONFIG"
    
        echo "autopurge.snapRetainCount=$ZOO_AUTOPURGE_SNAPRETAINCOUNT" >> "$CONFIG"
        echo "autopurge.purgeInterval=$ZOO_AUTOPURGE_PURGEINTERVAL" >> "$CONFIG"
        echo "maxClientCnxns=$ZOO_MAX_CLIENT_CNXNS" >> "$CONFIG"
    
        echo $ZOO_SERVERS
    
        for server in $ZOO_SERVERS; do
            echo ${server}
            echo "$server" >> "$CONFIG"
        done
    fi
    
    # Write myid only if it doesn't exist
    if [[ ! -f "$ZOO_DATA_DIR/myid" ]]; then
        echo "${ZOO_MY_ID:-1}" > "$ZOO_DATA_DIR/myid"
    fi
    
    #注释掉了下面的这行,因为CMD方式启动出错
    #exec "$@" 
    #检查配置写入情况
    cat $CONFIG
    #添加这一行,直接使用脚本
    zkServer.sh start-foreground
    

    修改完之后,我们重新构建官方镜像:

    docker build -t szzookeeper:3.5 .
    

    构建完毕之后再次修改我们自定义构建镜像的文件,将引用镜像设置为我们刚构建好的小改官方镜像:

    FROM szzookeeper:3.5
    MAINTAINER simon.zhu.chn@hotmail.com
    
    ADD zk-config.sh /
    
    ENTRYPOINT ["/bin/bash", "-c", "source /zk-config.sh && /docker-entrypoint.sh"]
    

    构建,提交至docker hub.

    5. K8S启动ZooKeeper集群效果

    这里我用Rancher搭建了K8S的两台机器集群,可以看到POD分布在了不同的NODE上

    image.png

    进入任意一个POD,使用命令查看ZooKeeper集群状态:可以看到这是一个follower节点

    6. 待更新,挂载持久卷

    相关文章

      网友评论

          本文标题:配置Kubernates方式启动Zookeeper集群

          本文链接:https://www.haomeiwen.com/subject/iygzfctx.html