docker 搭建zookper集群,快照虚拟机多机模拟

网上有很多zk集群搭建的,发现踩了很多坑,记录一下自己的搭建:

虚拟机配置

快照克隆:


关闭防火墙。

zk集群正式搭建

查询虚拟机ip地址:

bash 复制代码
ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1

挂载文件地址:

复制代码
mkdir -p /mydata/zookeeper/data # 数据挂载目录
mkdir -p /mydata/zookeeper/conf # 配置挂载目录
mkdir -p /mydata/zookeeper/logs # 日志挂载目录

关键点,修改配置:

复制代码
echo 1 > /mydata/zookeeper/conf/myid 

这里是指定zk id,选举需要使用,单机不需要

复制代码
vim /mydata/zookeeper/conf/zoo.cfg

zoo.cfg创建zk配置,配置如下:

复制代码
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data
dataLogDir=/logs
clientPort=2181
server.1=172.30.123.67:2888:3888
server.2=172.30.123.60:2888:3888
server.3=172.30.115.33:2888:3888

网上很多都是hostname:sudo hostnamectl set-hostname zk2

或者修改/etc/hosts这个文件,通过名称映射ip,这个我也失败了,解析不了。


docker 执行命令:

复制代码
docker run -d --name zk \
  --network host \
  --restart=unless-stopped \
  -v /mydata/zookeeper/data:/data \
  -v /mydata/zookeeper/logs:/logs \
  -v /mydata/zookeeper/conf:/conf \
  -e ZOO_MY_ID=$(cat /mydata/zookeeper/data/myid) \
  zookeeper:3.5.7

这个有点坑,我试了其他博主的博客,大多都是直接-p去映射,但是我这边尝试一直链接不是,采用 --network host。

--network host 让容器直接使用宿主机网络,端口 2181/2888/3888 不用再 -p 映射。

集群验证:

复制代码
docker exec zk zkServer.sh status

显示:

复制代码
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: follower

follower就是选举角色,到这里就成功了,其他的虚拟机上还有leader。

简单使用java连接集群

pom.xml:

添加依赖

复制代码
<dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>5.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>5.9.0</version>
        </dependency>

生产客户端bean:

复制代码
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ZookeeperConfig {

    @Value("${curator.connectString}")
    private String connectString;

    @Value("${curator.sessionTimeoutMs}")
    private int sessionTimeoutMs;

    @Value("${curator.connectionTimeoutMs}")
    private int connectionTimeoutMs;

    @Value("${curator.retryCount}")
    private int retryCount;

    @Value("${curator.elapsedTimeMs}")
    private int elapsedTimeMs;

    @Bean(initMethod = "start", destroyMethod = "close")
    public CuratorFramework curatorFramework() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(elapsedTimeMs, retryCount);
        return CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .sessionTimeoutMs(sessionTimeoutMs)
                .connectionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(retryPolicy)
                .build();
    }
}

注册服务bean:

复制代码
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.nodes.PersistentNode;
import org.apache.zookeeper.CreateMode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ZookeeperServiceRegistry {

    @Autowired
    private CuratorFramework curatorFramework;

    /**
     * 注册服务节点
     * @param serviceName 服务名
     * @param serviceAddress 实例地址,如 127.0.0.1:8080
     * @return PersistentNode 句柄,方便后续关闭
     */
    public PersistentNode registerService(String serviceName, String serviceAddress) throws Exception {
        // 1. 先保证父节点存在
        String parent = "/services/" + serviceName;
        Stat stat = curatorFramework.checkExists().forPath(parent);
        if (stat == null) {
            curatorFramework.create()
                    .creatingParentContainersIfNeeded()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath(parent);
        }

        // 2. 子节点路径,使用 EPHEMERAL 即可,不需要 SEQUENTIAL
        String childPath = parent + "/" + serviceAddress;

        // 3. 创建临时节点
        PersistentNode node = new PersistentNode(
                curatorFramework,
                CreateMode.EPHEMERAL,   // 会话断后自动删除
                false,                  // false 表示不监听子节点
                childPath,
                serviceAddress.getBytes());

        node.start();
        if (!node.waitForInitialCreate(10, TimeUnit.SECONDS)) {
            throw new IllegalStateException("Failed to create node at " + childPath);
        }
        return node;
    }

    /**
     * 注销服务节点(若仍持有 PersistentNode,先关闭再删除)
     */
    public void unregisterService(String serviceName, String serviceAddress) throws Exception {
        String path = "/services/" + serviceName + "/" + serviceAddress;
        // 如果之前保存了 PersistentNode,先关闭
        // node.close();
        curatorFramework.delete().forPath(path);
    }
}

使用spring CommandLineRunner 钩子,主动注册

复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class ServiceRegistrationRunner implements CommandLineRunner {

    @Autowired
    private ZookeeperServiceRegistry serviceRegistry;

    @Override
    public void run(String... args) throws Exception {
        serviceRegistry.registerService("my-service", "127.0.0.1:8080");
        System.out.println("Service registered successfully.");
    }
}
相关推荐
草履虫建模6 分钟前
若依微服务一键部署(RuoYi-Cloud):Nacos/Redis/MySQL + Gateway + Robot 接入(踩坑与修复全记录)
redis·mysql·docker·微服务·云原生·nacos·持续部署
半梦半醒*28 分钟前
playbook剧本
linux·运维·服务器·ssh·ansible·运维开发
大喵桑丶1 小时前
Nginx配置学习及多应用场景配置示例
运维·学习·nginx
wanhengidc1 小时前
七夕 云手机:浪漫时光里的科技陪伴
运维·科技·安全·游戏·智能手机
草莓田田圈~2 小时前
kubernetes-ubuntu24.04操作系统部署k8s集群
云原生·容器·kubernetes
Brilliantee4042 小时前
K8s 二次开发漫游录
云原生·容器·kubernetes·operator·k8s二次开发
阿鹿.3 小时前
docker-相关笔记
java·笔记·docker
007php0074 小时前
Go 语言常用命令使用与总结
java·linux·服务器·前端·数据库·docker·容器
鹧鸪云光伏4 小时前
鹧鸪云软件如何重塑光伏电站管理与降本增效
大数据·运维·光伏·光伏设计