环境:6台服务器docker swarm集群(2个主节点和4个工作节点)
要求:在现有的docker swarm上设置一个zookeeper集群。
阻碍:为了在集群中设置zookeeper,我们需要在每个服务器配置中提供所有zk服务器,并在myid文件中提供唯一的ID。
问题:当我们在docker swarm中创建zookeeper的副本时,如何为每个副本提供唯一的ID?另外,如何更新zoo.cfg配置文件以包含每个zookeeper容器的ID?
环境:6台服务器docker swarm集群(2个主节点和4个工作节点)
要求:在现有的docker swarm上设置一个zookeeper集群。
阻碍:为了在集群中设置zookeeper,我们需要在每个服务器配置中提供所有zk服务器,并在myid文件中提供唯一的ID。
问题:当我们在docker swarm中创建zookeeper的副本时,如何为每个副本提供唯一的ID?另外,如何更新zoo.cfg配置文件以包含每个zookeeper容器的ID?
version: '2'
services:
zoo1:
image: 31z4/zookeeper
restart: always
ports:
- 2181:2181
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
zoo2:
image: 31z4/zookeeper
restart: always
ports:
- 2182:2181
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
..
..
对于一种最先进(但仍在不断发展中)的解决方案,我建议查看 Kubernetes:
新的Statefulsets概念带来了很多前景。我预计Docker Swarm将在未来增加类似的功能,其中每个容器实例都被分配一个唯一且“粘性”的主机名,可以用作唯一标识的基础。我一直在尝试在Docker Swarm模式下部署Zookeeper集群。
我已经部署了3台机器连接到Docker Swarm网络。我的要求是,在这些节点的每个上运行3个Zookeeper实例,形成集合。
我阅读了这个帖子,在如何在Docker Swarm中部署Zookeeper方面得到了一些见解。
正如@junius建议的那样,我创建了Docker Compose文件。我已经删除了约束条件,因为Docker Swarm会忽略它。请参考https://forums.docker.com/t/docker-swarm-constraints-being-ignored/31555
我的Zookeeper Docker Compose文件如下:
version: '3.3'
services:
zoo1:
image: zookeeper:3.4.12
hostname: zoo1
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /etc/localtime:/etc/localtime:ro
zoo2:
image: zookeeper:3.4.12
hostname: zoo2
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /etc/localtime:/etc/localtime:ro
zoo3:
image: zookeeper:3.4.12
hostname: zoo3
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /etc/localtime:/etc/localtime:ro
networks:
net:
使用docker stack命令部署。
docker stack deploy -c zoo3.yml zk 创建网络zk_net 创建服务zk_zoo3 创建服务zk_zoo1 创建服务zk_zoo2
Zookeeper服务在每个节点上都很好地运行,没有任何问题。
docker stack services zk ID NAME MODE REPLICAS IMAGE PORTS rn7t5f3tu0r4 zk_zoo1 replicated 1/1 zookeeper:3.4.12 0.0.0.0:2181->2181/tcp, 0.0.0.0:2888->2888/tcp, 0.0.0.0:3888->3888/tcp u51r7bjwwm03 zk_zoo2 replicated 1/1 zookeeper:3.4.12 0.0.0.0:2181->2181/tcp, 0.0.0.0:2888->2888/tcp, 0.0.0.0:3888->3888/tcp zlbcocid57xz zk_zoo3 replicated 1/1 zookeeper:3.4.12 0.0.0.0:2181->2181/tcp, 0.0.0.0:2888->2888/tcp, 0.0.0.0:3888->3888/tcp我在这里复现了讨论的问题,当我停止并重新启动zookeeper堆栈时。
docker stack rm zk docker stack deploy -c zoo3.yml zk
这次zookeeper集群没有形成。Docker实例记录了以下内容:
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
2018-11-02 15:24:41,531 [myid:2] - WARN [WorkerSender[myid=2]:QuorumCnxManager@584] - Cannot open channel to 1 at election address zoo1/10.0.0.4:3888
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:558)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:534)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:454)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:435)
at java.lang.Thread.run(Thread.java:748)
2018-11-02 15:24:41,538 [myid:2] - WARN [WorkerSender[myid=2]:QuorumCnxManager@584] - Cannot open channel to 3 at election address zoo3/10.0.0.2:3888
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:558)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:534)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:454)
at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:435)
at java.lang.Thread.run(Thread.java:748)
2018-11-02 15:38:19,146 [myid:2] - WARN [QuorumPeer[myid=2]/0.0.0.0:2181:Learner@237] - Unexpected exception, tries=1, connecting to /0.0.0.0:2888
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.Learner.connectToLeader(Learner.java:229)
at org.apache.zookeeper.server.quorum.Follower.followLeader(Follower.java:72)
at org.apache.zookeeper.server.quorum.QuorumPeer.run(QuorumPeer.java:981)
2018-11-02 15:38:20,147 [myid:2] - WARN [QuorumPeer[myid=2]/0.0.0.0:2181:Learner@237] - Unexpected exception, tries=2, connecting to /0.0.0.0:2888
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:204)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.Learner.connectToLeader(Learner.java:229)
at org.apache.zookeeper.server.quorum.Follower.followLeader(Follower.java:72)
at org.apache.zookeeper.server.quorum.QuorumPeer.run(QuorumPeer.java:981)
# 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
这是导致问题的原因。我已经编辑了docker-entrypoint.sh文件,加入了以下内容:
if [[ -f "$ZOO_DATA_DIR/myid" ]]; then
rm "$ZOO_DATA_DIR/myid"
fi
echo "${ZOO_MY_ID:-1}" > "$ZOO_DATA_DIR/myid"
并在我的组合文件中挂载了docker-entrypoint.sh。
通过这个修复,我能够多次停止和启动我的堆栈,并且每次我的zookeeper集群都能够形成集合而不会遇到连接问题。
我的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 "$ZOO_USER" "$ZOO_DATA_DIR" "$ZOO_DATA_LOG_DIR"
exec su-exec "$ZOO_USER" "$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=$ZOO_PORT" >> "$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 "maxClientCnxns=$ZOO_MAX_CLIENT_CNXNS" >> "$CONFIG"
for server in $ZOO_SERVERS; do
echo "$server" >> "$CONFIG"
done
fi
if [[ -f "$ZOO_DATA_DIR/myid" ]]; then
rm "$ZOO_DATA_DIR/myid"
fi
echo "${ZOO_MY_ID:-1}" > "$ZOO_DATA_DIR/myid"
exec "$@"
version: '3.3'
services:
zoo1:
image: zookeeper:3.4.12
hostname: zoo1
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=0.0.0.0:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /home/zk/docker-entrypoint.sh:/docker-entrypoint.sh
- /etc/localtime:/etc/localtime:ro
zoo2:
image: zookeeper:3.4.12
hostname: zoo2
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=0.0.0.0:2888:3888 server.3=zoo3:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /home/zk/docker-entrypoint.sh:/docker-entrypoint.sh
- /etc/localtime:/etc/localtime:ro
zoo3:
image: zookeeper:3.4.12
hostname: zoo3
ports:
- target: 2181
published: 2181
protocol: tcp
mode: host
- target: 2888
published: 2888
protocol: tcp
mode: host
- target: 3888
published: 3888
protocol: tcp
mode: host
networks:
- net
deploy:
restart_policy:
condition: on-failure
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=0.0.0.0:2888:3888
volumes:
- /home/zk/data:/data
- /home/zk/datalog:/datalog
- /home/zk/docker-entrypoint.sh:/docker-entrypoint.sh
- /etc/localtime:/etc/localtime:ro
networks:
net:
通过这种方式,我能够在使用Swarm模式的Docker中启动并运行Zookeeper实例,而无需在compose文件中硬编码任何主机名。如果我的某个节点崩溃,服务将在Swarm上的任何可用节点上启动,而不会出现任何问题。
谢谢
ip route get ${NODE_IP} | grep -c "dev lo"
来检查自己的IP,这对我来说似乎更加健壮。)而且我也卡在了重新创建上。你有没有考虑过使用Zookeeper 3.5的新重配置功能? - Caesar