CLOVER🍀

That was when it all began.

Ubuntu LinuxでRedis ClusterのDockerむメヌゞを䜜っお遊ぶ

Redis Clusterを䜿っおみたいのず、合わせおそのDockerむメヌゞを䜜ろうかなず思っおちょっず遊んでみたした。

Redis 3から、クラスタが組めるようになったそうですね。これを詊しおみたいず。

参考
オフィシャルサむトチュヌトリアル
Redis cluster tutorial

公式のDockerコンテナでRedis Clusterを構築する - Maverick Techlab
Redis cluster - おさかな日誌
http://tech.albert2005.co.jp/blog/2015/04/28/redis-cluster/
Redis Cluster のリシャーディングとorphaned masterの話 - CyberAgent エンジニア Advent Calendar 2014 2日目 · GitHub

これらを参考に、Redis Cluster環境を構築するためのDockerむメヌゞを䜜っおいっおみたす。

Redis Clusterっお

そもそも、Redis Clusterに぀いおですが、ざっくり蚀うず

  • Redisを耇数ノヌドで構成し、マルチマスタを組める
  • デヌタはノヌド間でシャヌディング
  • スレヌブを䜜っお耐障害性の向䞊が可胜

ずいった代物らしいです。

Dockerむメヌゞの䜜成

それでは、Dockerむメヌゞを自分で䜜っおみたす。

たず、オフィシャルのチュヌトリアルを読むず

Redis Cluster and Docker

Currently Redis Cluster does not support NATted environments and in general environments where IP addresses or TCP ports are remapped.

Docker uses a technique called port mapping: programs running inside Docker containers may be exposed with a different port compared to the one the program believes to be using. This is useful in order to run multiple containers using the same ports, at the same time, in the same server.

In order to make Docker compatible with Redis Cluster you need to use the host networking mode of Docker. Please check the --net=host option in the Docker documentation for more information.

http://redis.io/topics/cluster-tutorial

ずいう感じでNATはサポヌトしおないよ、--net=hostで䜿おうねず曞いおあるので、その前提で䜜りたす。

必芁なのは、

ずいったずころ。

Redisのむンストヌル先を/opt/redisずしお、䜜成したのがこちら。
Dockerfile

FROM ubuntu:latest

ENV REDIS_VERSION 3.0.6
ENV REDIS_HOME /opt/redis

WORKDIR ${REDIS_HOME}

RUN mkdir -p ${REDIS_HOME}

RUN apt-get update

RUN apt-get install -y apt-file && \
    apt-file update && \
    apt-file search add-apt-repository && \
    apt-get install -y software-properties-common

RUN apt-add-repository ppa:brightbox/ruby-ng && \
    apt-get update && \                      
    apt-get install -y ruby2.2

RUN gem install redis

RUN cd /opt && \
    apt-get install -y \
     wget \
     gcc \
     make \
     && \
    wget -q http://download.redis.io/releases/redis-${REDIS_VERSION}.tar.gz && \
    tar -zxvf redis-${REDIS_VERSION}.tar.gz && \
    mv redis-${REDIS_VERSION} redis-src && \
    cd redis-src && \
    make && \
    make PREFIX=${REDIS_HOME} install

EXPOSE 6379

RUN mkdir conf

ADD redis.conf.template conf/redis.conf.template
ADD start-redis.sh start-redis.sh

RUN chmod a+x start-redis.sh

ENTRYPOINT ["./start-redis.sh"]

ムダにRuby 2.2を䜿うように蚭定。

RUN apt-get install -y apt-file && \
    apt-file update && \
    apt-file search add-apt-repository && \
    apt-get install -y software-properties-common

RUN apt-add-repository ppa:brightbox/ruby-ng && \
    apt-get update && \                      
    apt-get install -y ruby2.2

gemでredisも必芁みたいです。

RUN gem install redis

たた、「--net=host」を䜿うのが前提なので、ポヌトをDocker起動時に匕数で受けずるような構成にしたした。

ずいうわけで、蚭定ファむルのテンプレヌトを甚意。
redis.conf.template

port %PORT%
cluster-enabled yes
cluster-config-file conf/nodes.conf
cluster-node-timeout 5000
appendonly yes

内容は、チュヌトリアルにある最小構成の蚭定です。

起動スクリプト。こちらをENTRYPOINTに蚭定。
start-redis.sh

#!/bin/bash

if [ "$1" != "" ]; then
    PORT=$1
else
    PORT=7000
fi

perl -wp -e "s!%PORT%!${PORT}!" conf/redis.conf.template > conf/redis.conf

bin/redis-server conf/redis.conf

匕数にポヌトを指定するず、その倀で蚭定ファむルを䜜っお起動したす、ず。

で、ビルド。

$ docker build -t kazuhira/redis-cluster:3.0.6 .

これで、準備完了。

Redisの各ノヌドの起動

それでは、Redisを起動したす。たずは3ノヌド。

## Node1
$ docker run -it --rm --net=host --name redis-server1 kazuhira/redis-cluster:3.0.6 7000

## Node2
$ docker run -it --rm --net=host --name redis-server2 kazuhira/redis-cluster:3.0.6 7001

## Node3
$ docker run -it --rm --net=host --name redis-server3 kazuhira/redis-cluster:3.0.6 7002

これだけだず、単に3぀ノヌドがあるだけです。

クラスタを構成する

では、この3ノヌドをクラスタずしお構成したす。

ひず぀、Dockerコンテナに入っお

$ docker exec -it redis-server1 bash

Redisの゜ヌスコヌドの䞭にある、「redis-trib.rb」ずいうスクリプトを䜿甚したす。
※「/opt/redis-src」ディレクトリは、この゚ントリでのRedis゜ヌスコヌドの展開先です

# /opt/redis-src/src/redis-trib.rb

盎接実行するず、ヘルプが出おきたす。

# /opt/redis-src/src/redis-trib.rb
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
Usage: redis-trib <command> <options> <arguments ...>

  create          host1:port1 ... hostN:portN
                  --replicas <arg>
  check           host:port
  info            host:port
  fix             host:port
                  --timeout <arg>
  reshard         host:port
                  --from <arg>
                  --to <arg>
                  --slots <arg>
                  --yes
                  --timeout <arg>
                  --pipeline <arg>
  rebalance       host:port
                  --weight <arg>
                  --auto-weights
                  --threshold <arg>
                  --use-empty-masters
                  --timeout <arg>
                  --simulate
                  --pipeline <arg>
  add-node        new_host:new_port existing_host:existing_port
                  --slave
                  --master-id <arg>
  del-node        host:port node_id
  set-timeout     host:port milliseconds
  call            host:port command arg arg .. arg
  import          host:port
                  --from <arg>
                  --copy
                  --replace
  help            (show this help)

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

このスクリプトを䜿甚しお、3぀のノヌドをクラスタに参加させたす。
※今回は、党郚マスタヌノヌドずしお䜜成したす

# /opt/redis-src/src/redis-trib.rb create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Creating cluster
>>> Performing hash slots allocation on 3 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> 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 127.0.0.1:7000)
M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

クラスタの状態を確認しおみたす。こちらは、redis-cliで可胜です。

# bin/redis-cli -p 7000 cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_sent:167
cluster_stats_messages_received:167

クラスタに参加しおいるノヌド。

# bin/redis-cli -p 7000 cluster nodes
3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001 master - 0 1452952573411 2 connected 5461-10922
4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002 master - 0 1452952572405 3 connected 10923-16383
73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460

で、ノヌドに接続しおsetしおみるず

# bin/redis-cli -p 7000
127.0.0.1:7000> set key1 value1
(error) MOVED 9189 127.0.0.1:7001

怒られたす。

ここは、「-c」を付けお起動するずリダむレクトしおくれるようです。

# bin/redis-cli -p 7000 -c
127.0.0.1:7000> set key1 value1
-> Redirected to slot [9189] located at 127.0.0.1:7001
OK

もう少し登録。

127.0.0.1:7001> set key2 value2
-> Redirected to slot [4998] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set key3 value3
OK

key3は、自分に割り圓おられおいるようです。

ちなみに、最初にちょっずハマったのが、ノヌドを曞く時に

127.0.0.1:7000

みたいにIPアドレスではなく、

localhost:7000

みたいにホスト名で曞くず、クラスタの構成に倱敗したす。

こんな゚ラヌを受け取っお。

call': ERR Invalid node address specified: localhost:7000 (Redis::CommandError)

どうやら、ホスト名は䜿甚䞍可で、IPアドレスで曞く必芁があるらしいです。

Redis-trib by using hostnames fails to join cluster · Issue #2071 · antirez/redis · GitHub

ノヌドを远加する

続いお、ノヌドを远加しおみたす。新しくRedisを起動。

$ docker run -it --rm --net=host --name redis-server4 kazuhira/redis-cluster:3.0.6 7003

圓然、ただクラスタには参加しおいたせん。

クラスタに远加するには、「redis-trib.rb add-node」を䜿甚したす。

# /opt/redis-src/src/redis-trib.rb add-node 127.0.0.1:7003 127.0.0.1:7000

「127.0.0.1:7003」は新しいノヌド、「127.0.0.1:7000」は既存のノヌドです。

実行。

# /opt/redis-src/src/redis-trib.rb add-node 127.0.0.1:7003 127.0.0.1:7000
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Adding node 127.0.0.1:7003 to cluster 127.0.0.1:7000
>>> Performing Cluster Check (using node 127.0.0.1:7000)
M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   0 additional replica(s)
M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 127.0.0.1:7003 to make it join the cluster.
[OK] New node added correctly.

クラスタに参加できたようです。

でも、この状態ではスロットず呌ばれるものが割り圓おられおいたせん。クラむアントからのリク゚ストには応じるこずができるみたいですが 。

この状態から進めるために、reshardしたす。

# /opt/redis-src/src/redis-trib.rb reshard 127.0.0.1:7003
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Performing Cluster Check (using node 127.0.0.1:7003)
M: 93af9513be1feb3f1088b003737c1f7ab80a8681 127.0.0.1:7003
   slots: (0 slots) master
   0 additional replica(s)
M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   0 additional replica(s)
M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   0 additional replica(s)
M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)?

スロット1〜16384の範囲をどう割り振るか聞かれるので、今回は 16384 / 4で4096でいきたす。

How many slots do you want to move (from 1 to 16384)? 4096

次に、デヌタを受け取るノヌド今回远加したノヌドを指定したす。

What is the receiving node ID? 93af9513be1feb3f1088b003737c1f7ab80a8681

そしおどのノヌドからスロットを動かすか聞かれるのですが、今回は党䜓から動かすこずにしお「all」ず答えたす。

Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:all

Ready to move 4096 slots.
  Source nodes:
    M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   0 additional replica(s)
    M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   0 additional replica(s)
    M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
  Destination node:
    M: 93af9513be1feb3f1088b003737c1f7ab80a8681 127.0.0.1:7003
   slots: (0 slots) master
   0 additional replica(s)

するず、リシャヌドのプランが衚瀺されるので

  Resharding plan:
    Moving slot 5461 from 3c95936f29dd29eb32f34a8b1bfacd5e477e3360
    Moving slot 5462 from 3c95936f29dd29eb32f34a8b1bfacd5e477e3360
    Moving slot 5463 from 3c95936f29dd29eb32f34a8b1bfacd5e477e3360
    Moving slot 5464 from 3c95936f29dd29eb32f34a8b1bfacd5e477e3360
    Moving slot 5465 from 3c95936f29dd29eb32f34a8b1bfacd5e477e3360

  〜省略〜

「yes」ず答えたす。

Do you want to proceed with the proposed reshard plan (yes/no)? yes

あずは、リシャヌドされる様子が続きたす 。

終了するず、クラスタに参加しお、か぀スロットも割り圓おられたこずが確認できたす。

# bin/redis-cli -p 7000 cluster nodes
3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001 master - 0 1452953663376 2 connected 6827-10922
93af9513be1feb3f1088b003737c1f7ab80a8681 127.0.0.1:7003 master - 0 1452953661865 4 connected 0-1364 5461-6826 10923-12287
4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002 master - 0 1452953662369 3 connected 12288-16383
73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000 myself,master - 0 0 1 connected 1365-5460

クラスタの情報。

# bin/redis-cli -p 7000 cluster info 
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:4
cluster_size:4
cluster_current_epoch:4
cluster_my_epoch:1
cluster_stats_messages_sent:2932
cluster_stats_messages_received:2934

確認

redis-cliで接続しお、デヌタ登録しおみたす。

# bin/redis-cli -p 7000 -c
127.0.0.1:7000> set key4 value4
-> Redirected to slot [13120] located at 127.0.0.1:7002
OK
127.0.0.1:7002> set key5 value5
-> Redirected to slot [9057] located at 127.0.0.1:7001
OK
127.0.0.1:7001> set key6 value6
-> Redirected to slot [4866] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set key7 value7
-> Redirected to slot [803] located at 127.0.0.1:7003
OK

远加したノヌドが、key7で珟れたした。

ノヌドを削陀する

ノヌドを削陀するには、「redis-trib.rb del-node」を䜿甚したす。

# /opt/redis-src/src/redis-trib.rb del-node 127.0.0.1:7003 93af9513be1feb3f1088b003737c1f7ab80a8681

削陀には、IPアドレス、ポヌトずノヌドのIDが必芁です。

ずころが、これを実行するず「ノヌドが空じゃないよ」ず怒られたす。

# /opt/redis-src/src/redis-trib.rb del-node 127.0.0.1:7003 93af9513be1feb3f1088b003737c1f7ab80a8681
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Removing node 93af9513be1feb3f1088b003737c1f7ab80a8681 from cluster 127.0.0.1:7003
[ERR] Node 127.0.0.1:7003 is not empty! Reshard data away and try again.

ノヌドを削陀するには、ノヌドが空でなくおはならないようです。

そこで、reshardしおポヌト7003のノヌドからデヌタを远い出しおみたす。
※FLUSHALLでもいいずか曞いおある゚ントリは芋たのですが 詊しおいたせん

# /opt/redis-src/src/redis-trib.rb reshard 127.0.0.1:7003
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Performing Cluster Check (using node 127.0.0.1:7003)
M: 93af9513be1feb3f1088b003737c1f7ab80a8681 127.0.0.1:7003
   slots:0-1364,5461-6826,10923-12287 (4096 slots) master
   0 additional replica(s)
M: 3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001
   slots:6827-10922 (4096 slots) master
   0 additional replica(s)
M: 4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002
   slots:12288-16383 (4096 slots) master
   0 additional replica(s)
M: 73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000
   slots:1365-5460 (4096 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

ここで、スロットの範囲は16384を3で割った5462切り䞊げにしたす。

How many slots do you want to move (from 1 to 16384)? 5462

移動先のノヌドは、クラスタに残るノヌドにしお

What is the receiving node ID? 73878b5b59102996acf8c1acaba831a022cdcdcc

移動元は、削陀察象のノヌドにしたす。

Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:93af9513be1feb3f1088b003737c1f7ab80a8681

2぀目はないので、「done」。

Source node #2:done

するず、今床はノヌドを削陀するこずができるようになりたす。

# /opt/redis-src/src/redis-trib.rb del-node 127.0.0.1:7003 93af9513be1feb3f1088b003737c1f7ab80a8681
/opt/redis-src/src/redis-trib.rb:1573: warning: duplicated key at line 1573 ignored: "threshold"
>>> Removing node 93af9513be1feb3f1088b003737c1f7ab80a8681 from cluster 127.0.0.1:7003
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

削陀する前に、「cluster nodes」で芋るずスロットが倖れおいたす。
※結果を取り盎したのでNode IDが倉わっおたすが、お気になさらず 

# bin/redis-cli -p 7000 cluster nodes
8766435737ca2b3b64b536fc8c5b27ba771f622b 127.0.0.1:7003 master - 0 1452954698203 6 connected
3c95936f29dd29eb32f34a8b1bfacd5e477e3360 127.0.0.1:7001 master - 0 1452954697701 2 connected 7851-10922
4ca10031c591cee679e1007d201f8066992af608 127.0.0.1:7002 master - 0 1452954697198 3 connected 13312-16383
73878b5b59102996acf8c1acaba831a022cdcdcc 127.0.0.1:7000 myself,master - 0 0 7 connected 0-7850 10923-13311

ずりあえず、なんずか通せた感じです。