概要
docker 上で redis + sentinel を試してみました
最初は docker コマンドで master 1 台、slave 1 台、sentinel 1 台を構築しフェイルオーバーの挙動を確認します
その後で docker-compose 化しスケールなどに対応します
環境
- macOS 10.14.4
- docker 18.09.2
- Redis 5.0.3
とりあえず master/slave 構成を作成する
master コンテンを起動します
docker run -d --name master redis
次に slave コンテナを起動します
master を参照できる必要があるので link で master コンテナの名前と紐付けます
そして salve として起動させるために起動コマンドに --slaveof
を付与して起動します
docker run -d --link master --name slave1 redis redis-server --slaveof master 6379
これで slave の状態を確認しましょう
以下のようになっていれば OK です
docker exec slave1 redis-cli info replication
# Replication
role:slave
master_host:master
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:98
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:b403efc891b46f6d9e1ef6b663f21c2ae43739dc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:98
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:98
動作確認
master に書き込みをして slave 側にもデータが反映されているか確認します
docker exec master redis-cli set a a
docker exec master redis-cli get a
=> a
docker exec slave1 redis-cli get a
=> a
また slave 側に書き込みを行えないことも確認します
docker exec slave1 redis-cli set b b
READONLY You can't write against a read only replica.
sentinel を組み合わせる
redis の単純な master/slave 構成を構築したところで次に sentinel と組み合わせます
sentinel と組み合わせることで master がダウンした際に slave が自動的に master に昇格することができます
sentinel 用のイメージの作成から始めます
sentinel 用の設定ファイル sentinel.conf
を作成します
vim sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster master 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 5000
sentinel は 1 台のみ起動するので monitor
は 1 にします
次に Dockerfile
です
設定ファイルを元に redis-server
を起動するようにすれば OK です
vim Dockerfile
FROM redis
ADD sentinel.conf /etc/redis/sentinel.conf
RUN chown redis:redis /etc/redis/sentinel.conf
CMD ["redis-server", "/etc/redis/sentinel.conf", "--sentinel"]
これでイメージをビルドしてコンテナを起動しましょう
コンテナを起動する際は link
で master と slave を参照できるようにします
docker build -t sentinel .
docker run -d --link master --link slave1 --name sentinel1 sentinel
sentinel コンテナが起動したら sentinel API を使って状態を書くにします
まずは slave として登録されているコンテナを取得します
docker exec sentinel1 redis-cli -p 26379 sentinel slaves mymaster | grep -A 1 'name'
=> 172.17.0.3:6379
次に master として登録されているコンテナを確認します
それぞれ別のコンテナが登録されていることがわかります
docker exec sentinel1 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
=> 172.17.0.2
master を停止さて昇格するか確認
では本題のフェイルオーバーを試してみます
master コンテナを停止して slave が master になるか確認してみましょう
docker stop master
sentinel コンテナのログには以下のように表示されました
docker logs -f sentinel1
1:X 14 May 2019 00:26:27.421 # +sdown master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.421 # +odown master mymaster 172.17.0.2 6379 #quorum 1/1
1:X 14 May 2019 00:26:27.421 # +new-epoch 1
1:X 14 May 2019 00:26:27.421 # +try-failover master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.428 # +vote-for-leader 6d8c18e7bbe1fe0c25c8fb8ea02d55795bc3aa11 1
1:X 14 May 2019 00:26:27.428 # +elected-leader master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.428 # +failover-state-select-slave master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.506 # +selected-slave slave 172.17.0.3:6379 172.17.0.3 6379 @ mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.506 * +failover-state-send-slaveof-noone slave 172.17.0.3:6379 172.17.0.3 6379 @ mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:27.584 * +failover-state-wait-promotion slave 172.17.0.3:6379 172.17.0.3 6379 @ mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:28.438 # +promoted-slave slave 172.17.0.3:6379 172.17.0.3 6379 @ mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:28.438 # +failover-state-reconf-slaves master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:28.490 # +failover-end master mymaster 172.17.0.2 6379
1:X 14 May 2019 00:26:28.490 # +switch-master mymaster 172.17.0.2 6379 172.17.0.3 6379
1:X 14 May 2019 00:26:28.491 * +slave slave 172.17.0.2:6379 172.17.0.2 6379 @ mymaster 172.17.0.3 6379
1:X 14 May 2019 00:26:33.506 # +sdown slave 172.17.0.2:6379 172.17.0.2 6379 @ mymaster 172.17.0.3 6379
これでフェイルオーバーは完了しています
今回のようなそれぞれ 1 台構成だとすべてが起動していないと sentinel API で状況を確認できないのでダウンした master を再度起動します
次に起動する際は redis の世界では slave として起動します
docker start master
1:X 14 May 2019 00:28:17.289 # -sdown slave 172.17.0.2:6379 172.17.0.2 6379 @ mymaster 172.17.0.3 6379
1:X 14 May 2019 00:28:27.266 * +convert-to-slave slave 172.17.0.2:6379 172.17.0.2 6379 @ mymaster 172.17.0.3 6379
動作確認
ではフェイルオーバーの動作確認をします
まずは先程実行しように master/slave として登録されているコンテナを確認します
docker exec sentinel1 redis-cli -p 26379 sentinel slaves mymaster | grep -A 1 'name'
=> 172.17.0.2:6379
docker exec sentinel1 redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
=> 172.17.0.3
ちゃんと入れ替わっていることが確認できると思います
次に master コンテナに対して set
命令をしてみます
docker exec master redis-cli set b b
READONLY You can't write against a read only replica.
このように master コンテナに対して set
できなくなっています
これは redis の世界ではすでに master コンテナが slave として扱われているためです
これが docker 上で sentinel を使った場合のややこしい点でフェイルオーバー後は docker の name と redis 内部で管理されている master/slave に齟齬が発生するので注意が必要です
sentinel に対して read/write できるのか
念の為確認しましたがそれはできないようです
docker exec sentinel1 redis-cli -p 26379 get a
ERR unknown command `get`, with args beginning with: `a`,
つまりアプリケーション側では常に master 側に書き込みを行うような処理を入れなければならないことがわかります
もしくは sentinel 以外を使って常に master にバランシングするようなミドルウェアの導入が必要です
docker-compose 化する
最後に docker-compose 化しましょう
vim docker-compose.yml
version: '2'
services:
master:
image: redis
slave:
image: redis
command: redis-server --slaveof master 6379
links:
- master
sentinel:
build: .
links:
- master
- slave
vim Dockerfile
FROM redis
ADD sentinel.conf /data/sentinel.conf
RUN chown redis:redis /data/sentinel.conf
CMD ["redis-server", "/data/sentinel.conf", "--sentinel"]
sentinel.conf
だけやや変えています
この後スケールさせるので monitor
を 1 -> 2 に変更しています
vim sentinel.conf
port 26379
dir /tmp
sentinel monitor mymaster master 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 5000
あとはビルドして各コンテナを起動すれば OK です
docker-compose build
docker-compose up -d
動作確認
まだそれぞれ 1 台構成ですがとりあえず起動しているか確認してみましょう
docker-compose exec sentinel redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
=> 172.21.0.2
docker-compose exec sentinel redis-cli -p 26379 sentinel slaves mymaster | grep -A 1 'name'
=> 172.21.0.3:6379
get/set
の確認もしておきます
docker-compose exec master redis-cli set a a
docker-compose exec master redis-cli get a
=> a
docker-compose exec slave redis-cli get a
=> a
スケールさせて動作確認
最後に sentinel と slave コンテナをスケールさせて挙動を確認します
sentinel コンテナを 3 台、slave コンテナを 4 台にします
docker-compose scale sentinel=3
docker-compose scale slave=4
これで master コンテナを停止しましょう
フェイルオーバーが発生し salve の 4 台のうちどれかが master に昇格しています
docker-compose stop master
docker-compose exec sentinel redis-cli -p 26379 sentinel get-master-addr-by-name mymaster
=> 172.21.0.8
先程 master だったコンテナが slave として新たに登録されています
docker-compose exec sentinel redis-cli -p 26379 sentinel slaves mymaster | grep -A 1 'name'
=> 172.21.0.9:6379, 172.21.0.2:6379, 172.21.0.7:6379, 172.21.0.3:6379
この挙動自体は何ら問題ないのですがアプリケーションの観点から見ると以下のような問題点が発生します
問題点
docker の世界のコンテナ名で set
を行おうとするとできなくなっています
docker-compose exec master redis-cli set a a
docker-compose exec master redis-cli set a a
(error) READONLY You can't write against a read only replica.
これは master だったものが slave になっているのが原因と slave が複数いるため本当の master を docker-compose exec
では見つけられないため発生しています
もし docker コマンドで操作したい場合は各 slave コンテナの IP を調べて master に昇格しているコンテナを探した上でそのコンテナに対して docker exec
すれば set
命令することができます
docker inspect sentinel_test_slave_4 | grep 'IPAddress'
=> "IPAddress": "172.21.0.8"
docker exec sentinel_test_slave_4 redis-cli set b b
=> OK
docker-compose exec master redis-cli get b
=> b
こんな感じです
ここから考察するに docker-compose を使って sentinel を構築した場合、アプリケーション側は link
の名前ではなく IP ベースで master を追跡できるような仕組みを検討しないとダメかもしれません
最後に
docker 上で redis + sentinel 環境を構築し実際にフェイルオーバーやスケールなどをさせて簡単に挙動を確認してみました
一番問題なのは docker の世界の name と redis の世界の master/slave に齟齬が発生する点かなと思います
たぶん調べればバランシングするコンテナなどと組み合わせてアプリケーションは常にそこにアクセスするようにすれば解決できる方法はあると思います
ただ純正の sentinel の機能を使うだけだとそれは厳しいということがわかりました
正直なところ docker + sentinel は少し相性が悪いのかなといった印象を受けました
0 件のコメント:
コメントを投稿