Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その19 )( Docker で Redis の環境を構築する2(Redis Cluster 構成))
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- Docker で Redis Cluster 環境を構築します。
参照したサイト・書籍
Redis 5 – bootstrapping a Redis Cluster with Docker
https://simplydistributed.wordpress.com/2018/08/31/redis-5-bootstrapping-a-redis-cluster-with-docker/Redis cluster tutorial
https://redis.io/topics/cluster-tutorial#creating-the-clusterA Redis Cluster of any size using Docker Compose and Redis 4.0 port-forwarding
https://get-reddie.com/blog/redis4-cluster-docker-compose/プロダクションでRedis Clusterを3年間運用し続けた所感
https://qiita.com/maruloop/items/a67b62d2a6a239c8fb67Spring Data Redis - 7. Redis Cluster
https://docs.spring.io/spring-data/redis/docs/2.0.11.RELEASE/reference/html/#clusterEnvironment variables in Compose
https://docs.docker.com/compose/environment-variables/
目次
- 方針
- コマンドラインから docker コマンドで Redis Cluster 環境を構築する
- ksbysample-webapp-lending から接続する + redis-cli で確認する
- Docker Compose で Redis Cluster 環境を構築する
手順
方針
- Docker イメージは Docker Hub の
redis:5.0.1
を利用します。 - Docker コンテナで起動する Redis は、ポート番号を 6379、Cluster Bus ポート番号を 16379 にします(Redis Cluster ではポート番号 + 10000 のポート番号を Cluster Bus ポートとして使用します)。コンテナ側は 6379, 16379 固定です。
- ホスト側では 6379, 6380, 6381, 6382, 6383, 6384 と 16379, 16380, 16381, 16382, 16383, 16384 の 12個のポート番号を Docker コンテナの Redis に紐づけます。
- Docker コンテナで Redis を起動する時に以下のオプションを付けます。
--cluster-announce-ip 172.23.136.33
(172.23.136.33 はホストの IP アドレスです)--cluster-announce-port 6379
(6379 はコンテナ毎に 6379, 6380, 6381, 6382, 6383, 6384 に変更します)--cluster-announce-bus-port 16379
(16379 はコンテナ毎に 16379, 16380, 16381, 16382, 16383, 16384 に変更します)
コマンドラインから docker コマンドで Redis Cluster 環境を構築する
docker-compose down
コマンドを実行して起動している Docker コンテナを全て終了(削除)します。
以下のコマンドを実行して Docker コンテナで Redis サーバを起動します。
docker run -d --name redis-cluster-6379 -p 6379:6379 -p 16379:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6379 --cluster-announce-bus-port 16379
docker run -d --name redis-cluster-6380 -p 6380:6379 -p 16380:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6380 --cluster-announce-bus-port 16380
docker run -d --name redis-cluster-6381 -p 6381:6379 -p 16381:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6381 --cluster-announce-bus-port 16381
docker run -d --name redis-cluster-6382 -p 6382:6379 -p 16382:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6382 --cluster-announce-bus-port 16382
docker run -d --name redis-cluster-6383 -p 6383:6379 -p 16383:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6383 --cluster-announce-bus-port 16383
docker run -d --name redis-cluster-6384 -p 6384:6379 -p 16384:16379 redis:5.0.1 redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --cluster-announce-ip 172.23.136.33 --cluster-announce-port 6384 --cluster-announce-bus-port 16384
IntelliJ IDEA の Docker Plugin で Log を見ると以下のようになっています。
以下の redis-cli --cluster create
コマンドで Redis Cluster を構築します。
docker run -i --rm redis:5.0.1 redis-cli --cluster create 172.23.136.33:6379 172.23.136.33:6380 172.23.136.33:6381 172.23.136.33:6382 172.23.136.33:6383 172.23.136.33:6384 --cluster-replicas 1
IntelliJ IDEA の Docker Plugin で Log を見ると以下のようになっています。
動作確認します。docker exec -it redis-cluster-6379 redis-cli
コマンドで redis-cluster-6379 のコンテナで redis-cli を起動した後、cluster nodes
コマンドを実行すると master, slave の情報が表示されます。
redis-cli から set "test" "1234"
を実行すると (error) MOVED 6918 172.23.136.33:6380
とホストの IPアドレスとポート番号で MOVED の応答が返ってきます。
今度は docker exec -it redis-cluster-6380 redis-cli
コマンドで redis-cluster-6380 のコンテナで redis-cli を起動した後、set "test" "1234"
を実行するとデータがセットされます。
flushdb コマンドでセットしたデータをクリアした後、docker exec -it redis-cluster-6379 redis-cli -c
コマンドで redis-cluster-6379 のコンテナで redis-cli を起動した後 set "test" "1234"
を実行すると、自動的に redis-cluster-6380 のコンテナの redis に接続してセットします。
ksbysample-webapp-lending から接続する + redis-cli で確認する
Redis Cluster に接続する場合、設定ファイルだけでは対応できません。Spring Data Redis - 7. Redis Cluster を参考に実装します。設定ファイルだけ設定した場合でも最初は動作するのですが、master の redis を落とした時に slave へ切り替えてくれません。
build.gradle の以下の点を変更します。
dependencies { .......... implementation("io.micrometer:micrometer-registry-prometheus") implementation("redis.clients:jedis") testImplementation("org.springframework.boot:spring-boot-starter-test") ..........
- dependencies block に
implementation("redis.clients:jedis")
を追加します。
変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。
src/main/resources/application-develop.properties を以下のように変更します。
spring.redis.cluster.nodes[0]=172.23.136.33:6379 spring.redis.cluster.nodes[1]=172.23.136.33:6380 spring.redis.cluster.nodes[2]=172.23.136.33:6381 spring.redis.cluster.nodes[3]=172.23.136.33:6382 spring.redis.cluster.nodes[4]=172.23.136.33:6383 spring.redis.cluster.nodes[5]=172.23.136.33:6384
- 以下の設定を削除します。
- spring.redis.host=localhost
- spring.redis.port=6379
- 以下の設定を追加します。
- spring.redis.cluster.nodes[0]=172.23.136.33:6379
- spring.redis.cluster.nodes[1]=172.23.136.33:6380
- spring.redis.cluster.nodes[2]=172.23.136.33:6381
- spring.redis.cluster.nodes[3]=172.23.136.33:6382
- spring.redis.cluster.nodes[4]=172.23.136.33:6383
- spring.redis.cluster.nodes[5]=172.23.136.33:6384
src/main/java/ksbysample/webapp/lending/config/RedisClusterConfig.java を新規作成し、以下の内容を記述します。
package ksbysample.webapp.lending.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import java.util.List; /** * Redis Cluster 用 Configuration クラス */ @Data @Configuration @ConfigurationProperties(prefix = "spring.redis.cluster") public class RedisClusterConfig { List<String> nodes; /** * Redis Cluster に接続するための {@link JedisConnectionFactory} オブジェクトを生成する * * @return {@link JedisConnectionFactory} オブジェクト */ @Bean public RedisConnectionFactory connectionFactory() { return new JedisConnectionFactory(new RedisClusterConfiguration(nodes)); } }
Tomcat を起動します。Spring Actuator の health check を見ると redis が認識されています。Redis Cluster 構成の場合、単体 Redis の時と表示が異なります。
ブラウザから http://localhost:8080/ のログイン画面にアクセスしてログインを試みると、問題なくログインできました。
redis-cli でデータを確認すると、データは保存されていますがクラスタ内のサーバに分散されていました。
PRINCIPAL_NAME_INDEX_NAME:tanaka.taro@sample.com"
がセットされているコンテナ redis-cluster-6381 を停止します。
ログイン中の画面でメニューから「貸出希望書籍登録」を選択すると問題なく画面が切り替わります(slave への切り替えが出来ないとエラーになります)。
redis-cli でデータを確認すると、redis-cluster-6381 の slave になっていた redis-cluster-6383 に PRINCIPAL_NAME_INDEX_NAME:tanaka.taro@sample.com"
のデータがセットされていました。
一旦作成した redis-cluster-XXXX のコンテナを全て削除します。
Docker Compose で Redis Cluster 環境を構築する
ホストのIPアドレスを環境変数にセットして docker-compose.yml 内で利用できるようにするために、プロジェクトのルートディレクトリの下に .env というファイルを新規作成し、以下の内容を記述します。
HOST_IP_ADDRESS=172.23.136.33
redis-server 起動時のオプションでサーバ共通のものを定義するファイルを作成します。docker/redis の下に redis.conf というファイルを新規作成し、以下の内容を記述します。
port 6379 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes
Redis Cluster の各サーバを起動するための Docker Image を作成するための Dockerfile を作成します。docker/redis の下に Dockerfile というファイルを新規作成し、以下の内容を記述します。
FROM redis:5.0.1 RUN apt-get update -qq && apt-get install -y expect ADD redis.conf /etc/redis/
redis-cli --cluster create
コマンドで Redis Cluster を構築する時に yes の入力を求められるところがあるので、expect をインストールして自動入力できるようにします。- ただし、いきなり
apt-get install -y expect
コマンドを実行しても失敗するので、その前にapt-get update -qq
を実行します。 - docker/redis/redis.conf を /etc/redis の下にコピーします。
docker-compose.yml に Redis Cluster を構築するための設定を記述します。redis-cluster-6379 ~ redis-cluster-6384 は redis-server 起動用コンテナで、redis-cluster-make は Redis Cluster を作成するための redis-cli --cluster create
コマンド実行用コンテナです。また redis_exporter の REDIS_ADDR に redis://172.23.136.33:6379 ~ redis://172.23.136.33:6384 をカンマ区切りで列挙して全ての Redis Server のメトリックスを収集できるようにします。
# 起動したコンテナに /bin/sh でアクセスする場合には以下のコマンドを実行する # docker exec -it redis /bin/sh # # 起動したコンテナの redis に redis-cli でアクセスするには以下のコマンドを実行する # docker exec -it redis redis-cli # ############################################################################# # 単体 Redis サーバ # redis: # image: redis:5.0.1 # container_name: redis # ports: # - "6379:6379" # ############################################################################# # Redis Cluster redis-cluster-6379: build: ./docker/redis image: redis:5.0.1-custom container_name: redis-cluster-6379 ports: - "6379:6379" - "16379:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6379 \ --cluster-announce-bus-port 16379 redis-cluster-6380: image: redis:5.0.1-custom container_name: redis-cluster-6380 ports: - "6380:6379" - "16380:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6380 \ --cluster-announce-bus-port 16380 depends_on: - redis-cluster-6379 redis-cluster-6381: image: redis:5.0.1-custom container_name: redis-cluster-6381 ports: - "6381:6379" - "16381:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6381 \ --cluster-announce-bus-port 16381 depends_on: - redis-cluster-6379 redis-cluster-6382: image: redis:5.0.1-custom container_name: redis-cluster-6382 ports: - "6382:6379" - "16382:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6382 \ --cluster-announce-bus-port 16382 depends_on: - redis-cluster-6379 redis-cluster-6383: image: redis:5.0.1-custom container_name: redis-cluster-6383 ports: - "6383:6379" - "16383:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6383 \ --cluster-announce-bus-port 16383 depends_on: - redis-cluster-6379 redis-cluster-6384: image: redis:5.0.1-custom container_name: redis-cluster-6384 ports: - "6384:6379" - "16384:16379" command: - /bin/sh - -c - | redis-server /etc/redis/redis.conf \ --cluster-announce-ip ${HOST_IP_ADDRESS} \ --cluster-announce-port 6384 \ --cluster-announce-bus-port 16384 depends_on: - redis-cluster-6379 redis-cluster-make: image: redis:5.0.1-custom container_name: redis-cluster-make command: - /bin/sh - -c - | expect -c " spawn redis-cli --cluster create \ ${HOST_IP_ADDRESS}:6379 \ ${HOST_IP_ADDRESS}:6380 \ ${HOST_IP_ADDRESS}:6381 \ ${HOST_IP_ADDRESS}:6382 \ ${HOST_IP_ADDRESS}:6383 \ ${HOST_IP_ADDRESS}:6384 \ --cluster-replicas 1 expect \"Can I set the above configuration? (type 'yes' to accept): \" send \"yes\n\" expect eof " depends_on: - redis-cluster-6379 - redis-cluster-6380 - redis-cluster-6381 - redis-cluster-6382 - redis-cluster-6383 - redis-cluster-6384 redis_exporter: image: oliver006/redis_exporter:latest container_name: redis_exporter ports: - "9121:9121" environment: - REDIS_ADDR=redis://${HOST_IP_ADDRESS}:6379,redis://${HOST_IP_ADDRESS}:6380,redis://${HOST_IP_ADDRESS}:6381,redis://${HOST_IP_ADDRESS}:6382,redis://${HOST_IP_ADDRESS}:6383,redis://${HOST_IP_ADDRESS}:6384
これで全ての準備が整いましたので docker-compose up -d
コマンドを実行します。最初に redis:5.0.1-custom イメージを生成した後、各コンテナが生成されます。
(.....途中は長いので省略.....)
IntelliJ IDEA の docker plugin で見ると、各コンテナは起動しており redis-cluster-make や redis-cluster-6379 コンテナのログは以下のように出力されています(yes が自動入力されています)。
redis-cluster-6379 と redis-cluster-6384 コンテナで redis-cli コマンドを起動して cluster nodes
コマンドを実行すると Redis Cluster が構築されていることが分かります。
Tomcat を起動して Spring Actuator の health check を見ると先程と同様に redis が cluster と認識されて表示されて、
http://localhost:8080/ にアクセスしてログイン画面を表示してからログインした後、
各 redis コンテナで redis-cli を起動して keys *
コマンドを実行するとセッション情報が保存されていることが確認できます。
Grafana からも各 redis サーバのメトリックスが確認できます。
docker-compose down
コマンドを実行すると、全てのコンテナが停止・削除されます。
次から docker-compose up -d
コマンドで起動する時は、redis:5.0.1-custom イメージが生成されているので1回目より短い時間で起動できます。
これで簡単に Redis Cluster が起動できる環境が出来ました。
履歴
2018/11/30
初版発行。