MEAN-stack и Docker. Часть 5 - Mongo Replica Set в Docker Swarm

Пятая часть цикла, посвященного контейнеризации MEAN-stack приложений, в которой мы развернем MongoDB Replica Set из трех узлов в Docker Swarm.

Содержание цикла

Введение

В предыдущей части мы задеплоили приложение в Docker Swarm. Однако сервис базы данных у нас не был реплицирован. В данной статье исправим это досадное недоразумение и развернем 3 реплики базы данных на нодах нашего Docker-роя. Но с репликацией mongo есть небольшая сложность - нельзя просто указать в compose-файле replicas: 3. В случае падения одной из рабочих нод докер перенесет сервис mongo на ноду, где такой сервис уже есть. И эти сервисы начнут работать с общей data/db. Но это недопустимо. Поэтому предстоит провести небольшую настройку.

Маркируем ноды

Каждой ноде укажем label с требуемым id реплики mongo. Для этого на менеджере выполним следующие команды:

docker node update --label-add mongo.replica=0 vm0
docker node update --label-add mongo.replica=1 vm1
docker node update --label-add mongo.replica=2 vm2

Настроим сервисы

В compose-файле вместо сервиса db создадим 3 других:

services:

  # ...

  mongo0:
    image: mongo
    command:
      - "--smallfiles"
      - "--replSet"
      - "rs0"
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.labels.mongo.replica == 0
      labels:
        - traefik.enable=false
    volumes:
      - mongodata0:/data/db
    networks:
      - db-net


  mongo1:
    image: mongo
    command:
      - "--smallfiles"
      - "--replSet"
      - "rs0"
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.labels.mongo.replica == 1
      labels:
        - traefik.enable=false
    volumes:
      - mongodata1:/data/db
    networks:
      - db-net


  mongo2:
    image: mongo
    command:
      - "--smallfiles"
      - "--replSet"
      - "rs0"
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
      placement:
        constraints:
          - node.labels.mongo.replica == 2
      labels:
        - traefik.enable=false
    volumes:
      - mongodata2:/data/db
    networks:
      - db-net

В командах указываем запускать mongo как replica set с именем rs0. В deploy указываем глобальный режим mode: global и задаем constraints-правило node.labels.mongo.replica == 0, т.е. запускать mongo0 только на ноде с меткой mongo.replica=0.

У сервера изменим путь для подключения mongoose к базе данных:

  server:
    ...
    environment:
      - "db:uri=mongodb://mongo0,mongo1,mongo2/docker?replicaSet=rs0"

В конфиге других сервисов ничего не меняется (см. предыдущую часть цикла).

Volumes

Для хранения баз данных создадим следующие volumes:

volumes:
  mongodata0:
  mongodata1:
  mongodata2:

и используем их в сервисах mongo:

  mongo0:
    ...
    volumes:
      - mongodata0:/data/db

Deploy

docker stack deploy -c docker-stack.mongo-rs.yml meanstack

Инициируем Replica Set в самой mongo

docker exec -it <mongo_container_id> sh

> mongo

> rs.initiate( {
   _id : "rs0",
   members: [
      { _id: 0, host: "mongo0:27017" },
      { _id: 1, host: "mongo1:27017" },
      { _id: 2, host: "mongo2:27017" }
   ]
})

Результат

В браузере по адресу http://visualizer.docker-example.local/ мы должны увидеть что-то похожее:

Код проекта на GitHub >>