Springでdocker-composeで立ち上げたredis-clusterを操作する


#はじめに
今回は開発環境でdocker-composeで環境を整えることが多いことを考え、springでdocker-compose上のredis-clusterを使用する方法について書こうと思います。
redisをしっかり使えるようになっていきたいですね。

まずはどんな環境で、どんなコード書いているかなどを記載していきます。
実行手順に関しては最後に一気に行います。



#実行環境
redis v6.0.10
spring v5.0.0
docker v19.03.13

```php:tree
.
├── RedisPractice(springのプロジェクト)
│   
├── conf
│   ├── redis.conf
│   └── redis.sh
└── docker-compose.yml
```


#環境構築
##spring
以下の内容をpox.xmlに追加しておきます
特にここでJedisを入れおいてください。JedisはJavaでredisを使用するためのライブラリです。

```pom.xml
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
```



##docker-composeの内容
将来的に、複数サービスを管理したいので、docker-copmposeでredis-clusterを立ち上げます。
dockerのネットワークを立ち上げて、その中で管理する形にしたいと思います。

```docker-compose.yml
version: '3'

services:
  redis:
    image: "redis:latest"
    command: bash -c "/bin/bash /conf/redis.sh  && while true; do echo "up"; sleep 100; done"
    ports:
        - 7000:7000
        - 7001:7001
        - 7002:7002
        - 7003:7003
        - 7004:7004
        - 7005:7005
    volumes:
      - "./conf:/conf:"
    
    networks:
            app_net:
                ipv4_address: 172.16.239.10

networks:
    app_net:
        driver: bridge
        ipam:
            driver: default
            config:
                - subnet: 172.16.239.0/24
                  gateway: 172.16.239.1

```
docker networkをbridgeで接続し、その中にsubnet（172.16.239.0）を作成しています。
以下がイメージです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/32794aa4-247a-4442-9120-77083a61a0a4.png)
参考情報：https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9

以下の記事でbridgeの解説で使われている図を参考に作成しまています。
https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9
参考サイト：Docker network 概論


docker-compose up でdocker-composeを起動すると、redisコンテナ内でredis.shを実行する。
以下にredisコンテナにマウントした内容と、実行する内容を記載します。

## redis-clusterを起動させるファイルたち


redis-clusterに関しての内容は以下記事にわかりやすく解説されています。一読してみてください。とてもわかります。
https://qiita.com/keitatata/items/44678ad472e61a4606c5
参考サイト：[実演]Redis Clusterの仕組みを完全に理解する

以下にredisコンテナにマウントした内容と、実行する内容を記載します。以下のtreeの内容の**conf**の内容の説明になります。

```php:tree
.
├── RedisPractice(springのプロジェクト)
│   
├── conf(このディレクトリの説明)
│   ├── redis.conf
│   └── redis.sh
└── docker-compose.yml
```

docker-compose up でdocker-composeを起動すると、redisコンテナ内でredis.shを実行します。
簡単に説明すると、

>**redisサーバー** を　**各ポート** ごとに　**/conf/redis.conf**　の中身の設定で、**バックグラウンド**で起動する。
その際にクラスターの情報は　**/conf/nodes.700_ .conf**ファイルに書きこむ。
そのあとredisサーバごとの設定情報をの**/conf/r700_i.log**に書き込む。
最後にクラスターを構築し、1ノードにつき最低何個のレプリカを割り当てる。

です。


```redis.sh
redis-server /conf/redis.conf --port 7000 --cluster-config-file /conf/nodes.7000.conf --daemonize yes ;
redis-server /conf/redis.conf --port 7001 --cluster-config-file /conf/nodes.7001.conf --daemonize yes ;
redis-server /conf/redis.conf --port 7002 --cluster-config-file /conf/nodes.7002.conf --daemonize yes ;
redis-server /conf/redis.conf --port 7003 --cluster-config-file /conf/nodes.7003.conf --daemonize yes ;
redis-server /conf/redis.conf --port 7004 --cluster-config-file /conf/nodes.7004.conf --daemonize yes ;
redis-server /conf/redis.conf --port 7005 --cluster-config-file /conf/nodes.7005.conf --daemonize yes ;


redis-cli -p 7000 info 1> /conf/r7000i.log 2> /dev/null;
redis-cli -p 7001 info 1> /conf/r7001i.log 2> /dev/null;
redis-cli -p 7002 info 1> /conf/r7002i.log 2> /dev/null;
redis-cli -p 7003 info 1> /conf/r7003i.log 2> /dev/null;
redis-cli -p 7004 info 1> /conf/r7004i.log 2> /dev/null;
redis-cli -p 7005 info 1> /conf/r7005i.log 2> /dev/null;


yes "yes" | redis-cli --cluster create 172.16.239.10:7000 172.16.239.10:7001 172.16.239.10:7002 172.16.239.10:7003 172.16.239.10:7004 172.16.239.10:7005 --cluster-replicas 1;

```

redisサーバーの設定ファイルは以下です。
全て大事ですが、cluster-announce-ipを指定せずにハマった過去があります。以下の記事ですので、もし良ければ見てみてください。
https://qiita.com/hudebakononaka/items/bb6376818075b951d5b7

```redis.conf

cluster-enabled      yes
cluster-node-timeout 5000
bind 0.0.0.0

cluster-announce-ip  127.0.0.1

```

#Springでredisを操作する準備

以下のイメージで動かせるようにします。

![スクリーンショット 2021-02-20 16.04.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376115/53ce33c2-db2a-f146-dfbf-560c01e14364.png)

今回確認する動作は
**GETのパラメーターに値を乗せて、データを保存する。**
です。

以下にSpringのコードを乗せています。


Springからのredisの操作に関してはSpring Data Redisドキュメントがわかりやすいです。
https://spring.pleiades.io/spring-data/redis/docs/2.3.6.RELEASE/reference/html/#redis:template
参考サイト ： Spring ドキュメント


```RedisController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisController {

	@Autowired
	private StringRedisTemplate redisTemplate;

	@RequestMapping(value="/redis/{key}/{value}" ,method = RequestMethod.GET)
	public String registerRedisServer( @PathVariable("key")String redisKey , @PathVariable("value") String redisValue) {

		//文字列操作をする場合はrg.springframework.data.redis.core　のValueOperationsを使用する
		ValueOperations<String, String> stringOoperation  = redisTemplate.opsForValue();
		stringOoperation.set(redisKey, redisValue);


		return "{"+ redisKey +":"+ redisValue +"}";
	}

}

```
Configのファイルのコードは以下の記事を参考にさせていただいています。

https://ksby.hatenablog.com/entry/2018/11/30/065921
参考サイト : Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その１９ )( Docker で Redis の環境を構築する２（Redis Cluster 構成）)


```RedisConfig.java
import java.util.List;

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 lombok.Data;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class RedisConfig {

	 List<String> nodes;

	 @Bean
	 public RedisConnectionFactory connectionFactory() {
		 return new JedisConnectionFactory(new RedisClusterConfiguration(nodes));
	 }

}

```
```application.yml
spring:
  redis:
    cluster:
      nodes: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005
      max-redirects: 9

```

#実行手順


docker-compose.ymlがあるディレクトリ上で下記を実行してください。

```
$ docker-compose up -d
```

上記のコードを使用して、Spring を起動してください。
そのあとに、下記を実行してください。

```
curl localhost:8080/redis/yes/nonono　
```

上記内容を実行すると、redisサーバーの中に値が保存されているはずです。
以下で試してみましょう。

```
＄ docker exec -it redi_redis_1 bash
# redis-cli -p 7000
127.0.0.1:7000> get "yes"
(error) MOVED 15538 127.0.0.1:7002
127.0.0.1:7000> CTRL＋C
# redis-cli -p 7002
127.0.0.1:7002> get "yes"
"nonono"
```

このようにポート7002に　"yes":"nonono"のデータが保存されていました。


#今後試してみたいこと

今回は開発環境でdocker-composeで環境を整えることが多いことを考え、docker-composeでredis-clusterを使用する方法について書きました。次回はより本番環境に近いものを考え、redis-clusterをkubernetesで動かし可用性を高める試みでも記事にしようと思います。

#今回のコード
私のgithubにコードがありますので、使用したい方は使用してください。
https://github.com/Kota-Yamaguchi/redisPractice

#参考文献

https://spring.pleiades.io/spring-data/redis/docs/2.3.6.RELEASE/reference/html/#redis:template
参考サイト ： Spring ドキュメント

https://ksby.hatenablog.com/entry/2018/11/30/065921
参考サイト : Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その１９ )( Docker で Redis の環境を構築する２（Redis Cluster 構成）)

https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9
参考サイト：Docker network 概論

https://qiita.com/keitatata/items/44678ad472e61a4606c5
参考サイト：[実演]Redis Clusterの仕組みを完全に理解する