これは、なにをしたくて書いたもの?
Redisでたまにクラスタを作るのですが、ふだん素のDockerでやっていて面倒だなーと思うようになり。
Docker Composeで構成しようと思うのですが、Redis Clusterを作る時はコマンドを実行する必要もあり。
このあたり、どうしようかな?と試行してみた結果です。
環境
今回の環境は、こちらです。
$ docker-compose -v docker-compose version 1.25.5, build 8a1c60f6 $ docker version Client: Docker Engine - Community Version: 19.03.8 API version: 1.40 Go version: go1.12.17 Git commit: afacb8b7f0 Built: Wed Mar 11 01:25:46 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.8 API version: 1.40 (minimum version 1.12) Go version: go1.12.17 Git commit: afacb8b7f0 Built: Wed Mar 11 01:24:19 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
RedisnのDockerイメージは、DockerHubにあるオフィシャルイメージをベースにします。
今回使うのは、Redis 5.0.8とします。
Docker Composeの用意する
まずは、Docker Compose用のディレクトリを作成。
$ mkdir redis-cluster $ cd redis-cluster
docker-compose.ymlを作成します。RedisのDockerイメージをそのままRedis Clusterには使えないので、ビルドも行うことにします。
docker-compose.yml
version: "3.8" services: redis: build: . image: kazuhira/redis-cluster:5.0.8 networks: - redis_network networks: redis_network:
用意したDockerfile。RedisのオフィシャルDockerイメージをベースに、カスタマイズ。
Dockerfile
FROM redis:5.0.8 COPY redis.conf /usr/local/etc/redis/redis.conf RUN chown -R redis.redis /usr/local/etc/redis CMD ["redis-server", "/usr/local/etc/redis/redis.conf"]
もともとENTRYPOINTが設定されているので、こちらの流れに乗ります。
https://github.com/docker-library/redis/blob/master/5.0/Dockerfile#L98-L102
COPYで追加している、Redisの設定ファイル。Redis Clusterを構成するためのミニマムです。
redis.conf
cluster-enabled yes cluster-config-file /usr/local/etc/redis/nodes.conf cluster-node-timeout 5000 appendonly yes
では、コンテナを起動。
$ docker-compose up --scale redis=6
6つ、コンテナが起動しました。
$ docker-compose ps Name Command State Ports ------------------------------------------------------------------------- redis-cluster_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp redis-cluster_redis_2 docker-entrypoint.sh redis ... Up 6379/tcp redis-cluster_redis_3 docker-entrypoint.sh redis ... Up 6379/tcp redis-cluster_redis_4 docker-entrypoint.sh redis ... Up 6379/tcp redis-cluster_redis_5 docker-entrypoint.sh redis ... Up 6379/tcp redis-cluster_redis_6 docker-entrypoint.sh redis ... Up 6379/tcp
ただ、まだ単独でRedisが浮いているだけです。
Redis Clusterを構成する
ここから、Redis Clusterを構成します。
起動したRedisを、一気にクラスタに含めたいと思うので、シェルスクリプトを書きましょう。
create-cluster.sh
#!/bin/bash REDIS_NETWORK=redis-cluster_redis_network REDIS_SERVICE_NAME=redis REDIS_PORT=6379 CLUSTER_REPLICAS=1 NODES=`docker network inspect ${REDIS_NETWORK} | jq '.[0].Containers | .[].IPv4Address' | perl -wp -e 's!"(.+)/.+"\r?\n!$1:6379 !g'` docker-compose exec ${REDIS_SERVICE_NAME} bash -c "yes yes | redis-cli --cluster create ${NODES} --cluster-replicas ${CLUSTER_REPLICAS}"
これで、docker-compose.ymlで定義されたネットワーク内にいるRedisを、全部クラスタに参加させます。
レプリカ数はCLUSTER_REPLICASで1にしているので、最低6ノード必要です。レプリカ数を0にすれば、3ノードでOKですね。
実行権限を付与して
$ chmod a+x create-cluster.sh
実行。
$ ./create-cluster.sh
クラスタが構成されました。
>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 172.19.0.3:6379 to 172.19.0.5:6379 Adding replica 172.19.0.6:6379 to 172.19.0.2:6379 Adding replica 172.19.0.4:6379 to 172.19.0.7:6379 M: 85961312c8f48c18cce5ff1e15de7a72a52bad9a 172.19.0.5:6379 slots:[0-5460] (5461 slots) master M: ee7e91e81d29311080f27e39659cf090334b7cd7 172.19.0.2:6379 slots:[5461-10922] (5462 slots) master M: 0b2a286562de2583f42534c90d04ccd191147c75 172.19.0.7:6379 slots:[10923-16383] (5461 slots) master S: 91c6b115bd237f64462922bac0ba3ec78ac04a07 172.19.0.4:6379 replicates 0b2a286562de2583f42534c90d04ccd191147c75 S: dc8b13f9b5b1cbcbf5a25277fa68f721a4303a13 172.19.0.3:6379 replicates 85961312c8f48c18cce5ff1e15de7a72a52bad9a S: 467f1f8eb26d8de160589a3f86cc1e57f3295130 172.19.0.6:6379 replicates ee7e91e81d29311080f27e39659cf090334b7cd7 Can I set the above configuration? (type 'yes' to accept): >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join .. >>> Performing Cluster Check (using node 172.19.0.5:6379) M: 85961312c8f48c18cce5ff1e15de7a72a52bad9a 172.19.0.5:6379 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: 91c6b115bd237f64462922bac0ba3ec78ac04a07 172.19.0.4:6379 slots: (0 slots) slave replicates 0b2a286562de2583f42534c90d04ccd191147c75 M: ee7e91e81d29311080f27e39659cf090334b7cd7 172.19.0.2:6379 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: 0b2a286562de2583f42534c90d04ccd191147c75 172.19.0.7:6379 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: dc8b13f9b5b1cbcbf5a25277fa68f721a4303a13 172.19.0.3:6379 slots: (0 slots) slave replicates 85961312c8f48c18cce5ff1e15de7a72a52bad9a S: 467f1f8eb26d8de160589a3f86cc1e57f3295130 172.19.0.6:6379 slots: (0 slots) slave replicates ee7e91e81d29311080f27e39659cf090334b7cd7 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
「cluster nodes」で、クラスタの状態を見てみます。
$ docker-compose exec redis redis-cli cluster nodes ee7e91e81d29311080f27e39659cf090334b7cd7 172.19.0.2:6379@16379 master - 0 1587192311927 2 connected 5461-10922 0b2a286562de2583f42534c90d04ccd191147c75 172.19.0.7:6379@16379 master - 0 1587192311000 3 connected 10923-16383 85961312c8f48c18cce5ff1e15de7a72a52bad9a 172.19.0.5:6379@16379 master - 0 1587192311000 1 connected 0-5460 91c6b115bd237f64462922bac0ba3ec78ac04a07 172.19.0.4:6379@16379 myself,slave 0b2a286562de2583f42534c90d04ccd191147c75 0 1587192311000 4 connected 467f1f8eb26d8de160589a3f86cc1e57f3295130 172.19.0.6:6379@16379 slave ee7e91e81d29311080f27e39659cf090334b7cd7 0 1587192312000 6 connected dc8b13f9b5b1cbcbf5a25277fa68f721a4303a13 172.19.0.3:6379@16379 slave 85961312c8f48c18cce5ff1e15de7a72a52bad9a 0 1587192311000 1 connected
master、slaveがそれぞれ3ノードずつありますね。
シェルスクリプトで実行しているのは、「docker network inspect」の結果を利用しています。コンテナ名とIPアドレスを表示するには、
jqを使って以下のような感じで。
$ docker network inspect redis-cluster_redis_network | jq '.[0].Containers | .[] | {Name, IPv4Address}' { "Name": "redis-cluster_redis_4", "IPv4Address": "172.19.0.5/16" } { "Name": "redis-cluster_redis_6", "IPv4Address": "172.19.0.2/16" } { "Name": "redis-cluster_redis_5", "IPv4Address": "172.19.0.7/16" } { "Name": "redis-cluster_redis_1", "IPv4Address": "172.19.0.4/16" } { "Name": "redis-cluster_redis_3", "IPv4Address": "172.19.0.3/16" } { "Name": "redis-cluster_redis_2", "IPv4Address": "172.19.0.6/16" }
IPアドレスのみ。
$ docker network inspect redis-cluster_redis_network | jq '.[0].Containers | .[].IPv4Address' "172.19.0.5/16" "172.19.0.2/16" "172.19.0.7/16" "172.19.0.4/16" "172.19.0.3/16" "172.19.0.6/16"
コンテナのみ。
$ docker network inspect redis-cluster_redis_network | jq '.[0].Containers | .[].Name' "redis-cluster_redis_4" "redis-cluster_redis_6" "redis-cluster_redis_5" "redis-cluster_redis_1" "redis-cluster_redis_3" "redis-cluster_redis_2"
この後のノード追加、削除などは、「redis-cli --cluster」でDocker Compose越しに操作すると良いでしょう。
$ docker-compose exec redis redis-cli --cluster help Cluster Manager Commands: create host1:port1 ... hostN:portN --cluster-replicas <arg> check host:port --cluster-search-multiple-owners info host:port fix host:port --cluster-search-multiple-owners reshard host:port --cluster-from <arg> --cluster-to <arg> --cluster-slots <arg> --cluster-yes --cluster-timeout <arg> --cluster-pipeline <arg> --cluster-replace rebalance host:port --cluster-weight <node1=w1...nodeN=wN> --cluster-use-empty-masters --cluster-timeout <arg> --cluster-simulate --cluster-pipeline <arg> --cluster-threshold <arg> --cluster-replace add-node new_host:new_port existing_host:existing_port --cluster-slave --cluster-master-id <arg> del-node host:port node_id call host:port command arg arg .. arg set-timeout host:port milliseconds import host:port --cluster-from <arg> --cluster-copy --cluster-replace help For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
この時に、各コンテナのIPアドレスを使います。
たとえば、コンテナをスケールさせて
$ docker-compose scale redis=12
ノード追加。
$ docker-compose exec redis redis-cli --cluster add-node 172.19.0.8:6379 172.19.0.2:6379 $ docker-compose exec redis redis-cli --cluster add-node 172.19.0.9:6379 172.19.0.2:6379 $ docker-compose exec redis redis-cli --cluster add-node 172.19.0.10:6379 172.19.0.2:6379 ... ...
このあとは、reshardとrebalanceが必要ですね(ここまででやめた)。
とまあ、こんな感じで。
参考)
GitHub - Grokzen/redis-py-cluster: Python cluster client for the official redis cluster. Redis 3.0+.