環境:6サーバーDockerスウォームクラスター(2マスターと4ワーカー)
要件:既存のDockerスウォームに動物園の飼育係クラスターをセットアップする必要があります。
ブロックオン:クラスターでzookeeperをセットアップするには、各サーバー構成ですべてのzkサーバーを提供し、myidファイルで一意のIDを提供する必要があります。
質問:docker swarmでzookeeperのレプリカを作成する場合、各レプリカに一意のIDを提供するにはどうすればよいですか。また、Zoo.cfg構成ファイルを各ZookeeperコンテナのIDで更新するにはどうすればよいですか。
これは現在、簡単な質問ではありません。完全にスケーラブルなステートフルアプリケーションクラスターは、各クラスターメンバーが一意のIDとストレージボリュームを必要とする場合に注意が必要です。
Docker Swarmでは、今日、作成ファイルで各クラスターメンバーを個別のサービスとして実行することをお勧めします( 1z4/zookeeper-docker を参照)。
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イメージを作成しました。 entrypoint.sh
は、各コンテナの起動時に残りのzookeeperノードを自動検出し、現在のノードを適切に構成するように変更されました。
画像は docker store および github にあります。
注:現在、障害の原因となるコンテナの再作成などのケースは処理していません。
最新のイメージは、次のような場合にzookeeperクラスターの再構成をサポートします。
DockerSwarmモードでZookeeperクラスターをデプロイしようとしています。
DockerSwarmネットワークに接続された3台のマシンを展開しました。私の要件は、アンサンブルを形成するこれらの各ノードで3つのZookeeperインスタンスを実行してみることです。このスレッドを通過し、DockerSwarmにZookeeperをデプロイする方法についていくつかの洞察を得ました。
@juniusが提案したように、私はdockercomposeファイルを作成しました。 docker swarmが制約を無視するため、制約を削除しました。参照 https://forums.docker.com/t/docker-swarm-constraints-being-ignored/31555
私のZookeeperdocker作成ファイルは次のようになります
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:
Dockerstackコマンドを使用してデプロイされます。
docker stack deploy -c Zoo3.ymlzkネットワークの作成zk_netサービスの作成zk_Zoo3サービスの作成zk_Zoo1サービスの作成zk_Zoo2
Zookeeperサービスは、各ノードで問題なく正常に起動します。
docker stack services zk ID NAME MODE REPLICAS IMAGE PORTS rn7t5f3tu0r4 zk_Zoo1レプリケート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複製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 zlbcocid57xzzk_Zoo3複製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
ここで説明したこの問題を再現しました。動物園の飼育係のスタックを停止して再開したときです。
docker stack rm zk docker stack deploy -c Zoo3.yml zk
今回は飼育係のクラスターは形成されません。 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)
よく観察すると、このスタックを初めてデプロイしたときに、ID:2のZooKeeperインスタンスがノード1で実行されていました。これにより、値2のmyidファイルが作成されました。
猫/ home/zk/data/myid 2
スタックを停止して再開すると、今回はID:3のZooKeeperインスタンスがノード1で実行されていることがわかりました。
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 566b68c11c8b zookeeper:3.4.12 "/ docker-entrypoin ..." 6分前アップ6分0.0.0.0:2181-> 2181/tcp、0.0.0.0:2888-> 2888 /tcp、0.0.0.0:3888->3888/tcp zk_Zoo3.1.7m0hq684pkmyrm09zmictc5bm
ただし、myidファイルの値は2のままです。これは、以前のインスタンスによって設定されたものです。
そのため、ログには[myid:2]が表示され、ID 1および3のインスタンスに接続しようとして、失敗します。
さらにデバッグすると、docker-entrypoint.shファイルに次のコードが含まれていることがわかりました
# 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をcomposeファイルにマウントしました。
この修正により、スタックを複数回停止および開始でき、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 "$@"
私のdockerは次のようにファイルを作成します
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モードを使用してzookeeperインスタンスをdockerで起動して実行することができます。ノードの1つがダウンした場合、サービスはswarm上の使用可能なノードで問題なく開始されます。
ありがとう