0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Теги: linux, nosql, linux-администрирование, redis, кластер, система управления базами данных, линукс, docker swarm</p>
1
<p>Теги: linux, nosql, linux-администрирование, redis, кластер, система управления базами данных, линукс, docker swarm</p>
2
<p>Всем привет, это заключительная часть статьи, где подробно описывается развёртывание<strong>Redis-кластера</strong>. Начало смотрите<a>здесь</a>.</p>
2
<p>Всем привет, это заключительная часть статьи, где подробно описывается развёртывание<strong>Redis-кластера</strong>. Начало смотрите<a>здесь</a>.</p>
3
<p>Итак, изначально было принято решение описать каждый сервис отдельно для удобного их размещения на нодах кластера.<strong>Docker-compose.yml</strong>будет выглядеть следующим образом:</p>
3
<p>Итак, изначально было принято решение описать каждый сервис отдельно для удобного их размещения на нодах кластера.<strong>Docker-compose.yml</strong>будет выглядеть следующим образом:</p>
4
redis-master: image: username/redis-master:0.1 ports: - mode: host protocol: tcp published: 6379 target: 6379 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-master == true networks: redis-net: aliases: - redis-master<p>В данном примере описан сервис<strong>redis-master</strong>. В секции ports мы описываем какой режим сети использовать (в нашем случае host позволяет напрямую использовать сеть ноды кластера), какие порты контейнера мы выносим из контейнера.</p>
4
redis-master: image: username/redis-master:0.1 ports: - mode: host protocol: tcp published: 6379 target: 6379 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-master == true networks: redis-net: aliases: - redis-master<p>В данном примере описан сервис<strong>redis-master</strong>. В секции ports мы описываем какой режим сети использовать (в нашем случае host позволяет напрямую использовать сеть ноды кластера), какие порты контейнера мы выносим из контейнера.</p>
5
<p>Endpoint_mode: dnsrr означает, что мы принудительно выключаем mesh-сеть, которая по умолчанию работает в<strong>Docker swarm</strong>. Отключения mesh-сети являются крайне важным моментом в нашем сетапе. Если бы она была включена, то подключаясь к порту 6379 к любой ноде кластера, клиент был бы автоматически смаршрутизирован в любой доступный нам контейнер и не факт, что он бы подключился именно к мастеру.</p>
5
<p>Endpoint_mode: dnsrr означает, что мы принудительно выключаем mesh-сеть, которая по умолчанию работает в<strong>Docker swarm</strong>. Отключения mesh-сети являются крайне важным моментом в нашем сетапе. Если бы она была включена, то подключаясь к порту 6379 к любой ноде кластера, клиент был бы автоматически смаршрутизирован в любой доступный нам контейнер и не факт, что он бы подключился именно к мастеру.</p>
6
<p>Более подробно о типе сетей в Docker swarm вы можете ознакомиться по данной<a>ссылке</a>.<strong>Aliases</strong>- на всякий случай ещё раз указываем сетевой алиас нашего сервиса.<strong>Networks</strong>- указываем, к какой сети будет присоединен наш сервис, в данном случае к redis-net.<strong>Placement constraints</strong>позволяет нам ограничить размещение нашего сервиса, в данном случае мы используем ограничение по тегам, которые выставили ранее.</p>
6
<p>Более подробно о типе сетей в Docker swarm вы можете ознакомиться по данной<a>ссылке</a>.<strong>Aliases</strong>- на всякий случай ещё раз указываем сетевой алиас нашего сервиса.<strong>Networks</strong>- указываем, к какой сети будет присоединен наш сервис, в данном случае к redis-net.<strong>Placement constraints</strong>позволяет нам ограничить размещение нашего сервиса, в данном случае мы используем ограничение по тегам, которые выставили ранее.</p>
7
<p>Секция, описывающая redis-slave, выглядит следующим образом:</p>
7
<p>Секция, описывающая redis-slave, выглядит следующим образом:</p>
8
redis-slave-1: image: mrgreyves/redis-slave:0.1 ports: - mode: host protocol: tcp published: 6379 target: 6379 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-slave-1 == true depends_on: - redis-master networks: - redis-net<p>Основные отличия в описании redis-slave заключаются в директиве depend_on. Она позволяет указать зависимость в запуске сервисов. Slave будет запущен только после того, как запустится redis-master.</p>
8
redis-slave-1: image: mrgreyves/redis-slave:0.1 ports: - mode: host protocol: tcp published: 6379 target: 6379 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-slave-1 == true depends_on: - redis-master networks: - redis-net<p>Основные отличия в описании redis-slave заключаются в директиве depend_on. Она позволяет указать зависимость в запуске сервисов. Slave будет запущен только после того, как запустится redis-master.</p>
9
<p>Секция, описывающая redis-sentinel:</p>
9
<p>Секция, описывающая redis-sentinel:</p>
10
redis-sentinel-1: image: mrgreyves/redis-sentinel:0.6 ports: - mode: host protocol: tcp published: 5000 target: 5000 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-sentinel-1 == true depends_on: - redis-master networks: redis-net:<p>Все директивы мы уже разобрали немного ранее. И вот, настал тот торжественный момент, когда мы с вами можем запустить наш кластер. Для это воспользуемся следующей командой:</p>
10
redis-sentinel-1: image: mrgreyves/redis-sentinel:0.6 ports: - mode: host protocol: tcp published: 5000 target: 5000 deploy: replicas: 1 endpoint_mode: dnsrr placement: constraints: - node.labels.redis-sentinel-1 == true depends_on: - redis-master networks: redis-net:<p>Все директивы мы уже разобрали немного ранее. И вот, настал тот торжественный момент, когда мы с вами можем запустить наш кластер. Для это воспользуемся следующей командой:</p>
11
docker stack deploy --compose-file=docker-compose-v2.yml redis<p>--compose-file= - указываем, какой именно файл использовать. Redis - название нашего стака.</p>
11
docker stack deploy --compose-file=docker-compose-v2.yml redis<p>--compose-file= - указываем, какой именно файл использовать. Redis - название нашего стака.</p>
12
<p>Также хочу отметить, что образы, которые мы создавали ранее, мы запушили в публичный репозиторий на docker hub. Если же вы используете приватный, необходимо использовать дополнительную опцию --with-registry-auth и не забыть перед этим залогиниться в нужном реджестри командой docker login.</p>
12
<p>Также хочу отметить, что образы, которые мы создавали ранее, мы запушили в публичный репозиторий на docker hub. Если же вы используете приватный, необходимо использовать дополнительную опцию --with-registry-auth и не забыть перед этим залогиниться в нужном реджестри командой docker login.</p>
13
<p>Для проверки нашего стака используем команду:</p>
13
<p>Для проверки нашего стака используем команду:</p>
14
docker stack services redis<p>Если всё прошло хорошо, то вывод будет следующим:</p>
14
docker stack services redis<p>Если всё прошло хорошо, то вывод будет следующим:</p>
15
<p>Убедимся, что redis-master действительно master. Для это подключаемся любым клиентом к ноде, на которой он запущен, и воспользуемся командой<strong>INFO</strong>. Нас интересует секция<strong>Replication</strong>, если в ней указано<strong>role:master</strong>, то всё прошло хорошо.</p>
15
<p>Убедимся, что redis-master действительно master. Для это подключаемся любым клиентом к ноде, на которой он запущен, и воспользуемся командой<strong>INFO</strong>. Нас интересует секция<strong>Replication</strong>, если в ней указано<strong>role:master</strong>, то всё прошло хорошо.</p>
16
<p>Далее подключаемся к следующей ноде и воспользуемся аналогичной командой. Если мы видим, что<strong>role:slave</strong>, то значит, что у нас всё хорошо.</p>
16
<p>Далее подключаемся к следующей ноде и воспользуемся аналогичной командой. Если мы видим, что<strong>role:slave</strong>, то значит, что у нас всё хорошо.</p>
17
<p>А теперь начинается самая интересная часть: мы будем ломать наш кластер и сделаем это слегка в софтовом режиме, а именно: просто удалим сервис<strong>redis-master</strong>. Для этого в<strong>docker-compose.yml</strong>просто меняем количество реплик на 0 и деплоимся.</p>
17
<p>А теперь начинается самая интересная часть: мы будем ломать наш кластер и сделаем это слегка в софтовом режиме, а именно: просто удалим сервис<strong>redis-master</strong>. Для этого в<strong>docker-compose.yml</strong>просто меняем количество реплик на 0 и деплоимся.</p>
18
<p>Логи redis sentinel будут следующими:</p>
18
<p>Логи redis sentinel будут следующими:</p>
19
1:X 02 Feb 10:50:58.299 * +slave slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.291 # +sdown master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.363 # +odown master mymaster 10.0.3.16 6379 #quorum 2/2 1:X 02 Feb 12:03:50.363 # +new-epoch 1 1:X 02 Feb 12:03:50.363 # +try-failover master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.367 # +vote-for-leader 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.374 # 289730ac61e05b7edc005c348088625db26d3983 voted for 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.381 # 6428c92d37154089ce67a33123f3fd0b86afe4e6 voted for 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.422 # +elected-leader master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.422 # +failover-state-select-slave master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.485 # +selected-slave slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.485 * +failover-state-send-slaveof-noone slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.549 * +failover-state-wait-promotion slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.440 # +promoted-slave slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.440 # +failover-state-reconf-slaves master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.512 * +slave-reconf-sent slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.447 * +slave-reconf-inprog slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.447 * +slave-reconf-done slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.510 # -odown master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.510 # +failover-end master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.511 # +switch-master mymaster 10.0.3.16 6379 10.0.3.17 6379 1:X 02 Feb 12:03:52.511 * +slave slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.17 6379 1:X 02 Feb 12:03:52.511 * +slave slave 10.0.3.16:6379 10.0.3.16 6379 @ mymaster 10.0.3.17 6379 1:X 02 Feb 12:03:55.563 # +sdown slave 10.0.3.16:6379 10.0.3.16 6379 @ mymaster 10.0.3.17 6379<p>Из них мы видим, что зафиксировано падение мастера:</p>
19
1:X 02 Feb 10:50:58.299 * +slave slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.291 # +sdown master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.363 # +odown master mymaster 10.0.3.16 6379 #quorum 2/2 1:X 02 Feb 12:03:50.363 # +new-epoch 1 1:X 02 Feb 12:03:50.363 # +try-failover master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.367 # +vote-for-leader 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.374 # 289730ac61e05b7edc005c348088625db26d3983 voted for 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.381 # 6428c92d37154089ce67a33123f3fd0b86afe4e6 voted for 37e8f4093969307733548e1948c184a1a69c2552 1 1:X 02 Feb 12:03:50.422 # +elected-leader master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.422 # +failover-state-select-slave master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.485 # +selected-slave slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.485 * +failover-state-send-slaveof-noone slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:50.549 * +failover-state-wait-promotion slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.440 # +promoted-slave slave 10.0.3.17:6379 10.0.3.17 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.440 # +failover-state-reconf-slaves master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:51.512 * +slave-reconf-sent slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.447 * +slave-reconf-inprog slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.447 * +slave-reconf-done slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.510 # -odown master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.510 # +failover-end master mymaster 10.0.3.16 6379 1:X 02 Feb 12:03:52.511 # +switch-master mymaster 10.0.3.16 6379 10.0.3.17 6379 1:X 02 Feb 12:03:52.511 * +slave slave 10.0.3.18:6379 10.0.3.18 6379 @ mymaster 10.0.3.17 6379 1:X 02 Feb 12:03:52.511 * +slave slave 10.0.3.16:6379 10.0.3.16 6379 @ mymaster 10.0.3.17 6379 1:X 02 Feb 12:03:55.563 # +sdown slave 10.0.3.16:6379 10.0.3.16 6379 @ mymaster 10.0.3.17 6379<p>Из них мы видим, что зафиксировано падение мастера:</p>
20
+sdown master mymaster 10.0.3.16 6379<p>И начался выбор нового мастера, который впоследствии стал успешно выбран:</p>
20
+sdown master mymaster 10.0.3.16 6379<p>И начался выбор нового мастера, который впоследствии стал успешно выбран:</p>
21
+elected-leader master mymaster 10.0.3.16 6379<p>После этого мы подключаемся к соседней ноде и командой<strong>INFO</strong>проверяем его роль. Если роль -<strong>master</strong>, значит переключение произошло успешно.</p>
21
+elected-leader master mymaster 10.0.3.16 6379<p>После этого мы подключаемся к соседней ноде и командой<strong>INFO</strong>проверяем его роль. Если роль -<strong>master</strong>, значит переключение произошло успешно.</p>
22
<p><em>Полезная заметка? Напишите в комментариях!</em></p>
22
<p><em>Полезная заметка? Напишите в комментариях!</em></p>
23
23