Перейти к содержанию

Рекомендации по кластеризации и повышению отказоустойчивости Консоли управления

В статье описаны подходы для повышения отказоустойчивости решения путем репликации базы данных MongoDB, кластеризации бэкенд-сервисов и настройки балансировщика нагрузки.

Шаг 1. Настройка репликации MongoDB

MongoDB является основным компонентом системы. Для обеспечения бесперебойной работы настройте кластер из трех нод в виде replica set.

  1. Создайте на хостовой машине директорию и файл ключей для безопасного взаимодействия нод кластера:

      mkdir ./keyfile-volume
      openssl rand -base64 756 > ./keyfile-volume/mongodb-keyfile
    

  2. Добавьте в файл docker-compose.yml два дополнительных сервиса для реплик MongoDB:

      # Новые сервисы для реплик
      mongo-replica-1:
          image: mongo:8.0.5
          container_name: api-fw-mongo-replica-1
          restart: unless-stopped
          networks:
          - api-firewall-manager-network
          environment:
          MONGO_INITDB_ROOT_USERNAME: ${MONGO_LOGIN}
          MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWD}
          MONGO_INITDB_DATABASE: ${MONGO_INITDB}
          volumes:
          - ./keyfile-volume:/opt/mongo
          - ./mongo-data-replica-1:/data/db
          - ./mongo-config-replica-1:/data/configdb
          command: mongod --bind_ip_all --replSet rs0 --auth --keyFile /opt/mongo/mongodb-keyfile
          healthcheck:
          test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok"]
          interval: 10s
          timeout: 5s
          retries: 5
          start_period: 10s
    
      mongo-replica-2:
          image: mongo:8.0.5
          container_name: api-fw-mongo-replica-2
          restart: unless-stopped
          networks:
          - api-firewall-manager-network
          environment:
          MONGO_INITDB_ROOT_USERNAME: ${MONGO_LOGIN}
          MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWD}
          MONGO_INITDB_DATABASE: ${MONGO_INITDB}
          volumes:
          - ./keyfile-volume:/opt/mongo
          - ./mongo-data-replica-2:/data/db
          - ./mongo-config-replica-2:/data/configdb
          command: mongod --bind_ip_all --replSet rs0 --auth --keyFile /opt/mongo/mongodb-keyfile
          healthcheck:
          test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok"]
          interval: 10s
          timeout: 5s
          retries: 5
          start_period: 10s
    

  3. Настройте сервис инициализации mongo-init для автоматического добавления всех нод в replica set:

  • Добавьте в секцию depends_on зависимости с условием service_healthy для всех сервисов MongoDB.

  • Модифицируйте команду rs.initiate(), указав в конфигурации имена всех трех сервисов ( например, api-fw-mongo, api-fw-mongo-replica-1 и api-fw-mongo-replica-2) в качестве хостов.

    mongo-init:
    image: mongo:8.0.5
    networks:
      - api-firewall-manager-network
    volumes:
      - ./keyfile-volume:/opt/mongo
    depends_on:
      mongo:
        condition: service_healthy
      mongo-replica-1:
        condition: service_healthy
      mongo-replica-2:
        condition: service_healthy
    command: >
      mongosh "mongodb://${MONGO_LOGIN}:${MONGO_PASSWD}@api-fw-mongo:27017/?authSource=admin" --eval '
        try {
          const status = rs.initiate({
            _id: "rs0",
            members: [
              { _id: 0, host: "api-fw-mongo:27017" },
              { _id: 1, host: "api-fw-mongo-replica-1:27017" },
              { _id: 2, host: "api-fw-mongo-replica-2:27017" }
            ]
          });
          printjson(status);
        } catch (e) {
          if (e.codeName === "AlreadyInitialized") {
            print("Replica set is already initialized, skipping.");
          } else {
            printjson(e);
            throw e;
          }
        }'
    restart: "no"
    
  1. Для сервисов migrations и manager_backend измените строку подключения к базе данных:

    migrations:
        ... 
        environment:
          MONGO_URI: mongodb://apifw:${MONGO_PASSWD}@api-fw-mongo:27017,api-fw-mongo-replica-1:27017,api-fw-mongo-replica-2:27017/?replicaSet=rs0     
    
      manager_backend:
        ...
        environment:
            MONGO_URI: mongodb://apifw:${MONGO_PASSWD}@api-fw-mongo:27017,api-fw-mongo-replica-1:27017,api-fw-mongo-replica-2:27017/?replicaSet=rs0
        ...
    

Шаг 2. Масштабирование сервиса manager_backend

  1. Добавьте второй экземпляр сервиса manager_backend: в файле docker-compose.yml продублируйте сервис manager_backend (например, назовите его manager_backend_2). Во избежание конфликтов портов замените параметр ports на expose для обоих экземпляров manager_backend. Это откроет порты только внутри Docker-сети, а не на хост-машине.

      manager_backend_1:
      container_name: api-fw-manager-1
      image: registry.webmonitorx.ru/api-firewall/apifw-manager:1.2.4
      # grpc для безопасного соединения c ПроAPI Защита
      # volumes:
      #   - ./gen_grpc_cert/server-cert.pem:/etc/ssl/certs/grpc-server-cert.pem
      #   - ./gen_grpc_cert/server-key.pem:/etc/ssl/certs/grpc-server-key.pem
      environment:
        MONGO_URI: mongodb://${MONGO_LOGIN}:${MONGO_PASSWD}@api-fw-mongo:27017,api-fw-mongo-replica-1:27017,api-fw-mongo-replica-2:27017/?replicaSet=rs0
        URL_MANAGER: ${URL_MANAGER}
        LICENSE_KEY: ${LICENSE_KEY}
        SET_REAL_IP_FROM: "0.0.0.0/0"
        NODES_DELETED_AFTER: "72h" # Удалять неактивные ноды через заданное время
        EVENTS_DELETED_AFTER: "720h" # Удалять события старше
      # GRPC_SERVER_CERT_FILE: /etc/ssl/certs/grpc-server-cert.pem # Путь до файла сертификата для настройки защищенного gRPC соединения Manager<>Node
      # GRPC_SERVER_KEY_FILE: /etc/ssl/certs/grpc-server-key.pem # Путь до файла закрытого ключа сертификата
      expose:
        - "8081"
        - "8082"
      depends_on:
        migrations:
          condition: service_completed_successfully
        mongo:
          condition: service_healthy
      networks:
        - api-firewall-manager-network
    
    manager_backend_2:
      container_name: api-fw-manager-2
      image: registry.webmonitorx.ru/api-firewall/apifw-manager:1.2.4
      # grpc для безопасного соединения c ПроAPI Защита
      # volumes:
      #   - ./gen_grpc_cert/server-cert.pem:/etc/ssl/certs/grpc-server-cert.pem
      #   - ./gen_grpc_cert/server-key.pem:/etc/ssl/certs/grpc-server-key.pem
      environment:
        MONGO_URI: mongodb://${MONGO_LOGIN}:${MONGO_PASSWD}@api-fw-mongo:27017,api-fw-mongo-replica-1:27017,api-fw-mongo-replica-2:27017/?replicaSet=rs0
        URL_MANAGER: ${URL_MANAGER}
        LICENSE_KEY: ${LICENSE_KEY}
        SET_REAL_IP_FROM: "0.0.0.0/0"
        NODES_DELETED_AFTER: "72h" # Удалять неактивные ноды через заданное время
        EVENTS_DELETED_AFTER: "720h" # Удалять события старше
      # GRPC_SERVER_CERT_FILE: /etc/ssl/certs/grpc-server-cert.pem # Путь до файла сертификата для настройки защищенного gRPC соединения Manager<>Node
      # GRPC_SERVER_KEY_FILE: /etc/ssl/certs/grpc-server-key.pem # Путь до файла закрытого ключа сертификата
      expose:
        - "8081"
        - "8082"
      depends_on:
        migrations:
          condition: service_completed_successfully
        mongo:
          condition: service_healthy
      networks:
        - api-firewall-manager-network
    
  2. Настройте балансировщик нагрузки: добавьте в docker-compose.yml сервис nginx_lb, который будет распределять входящие запросы между двумя экземплярами manager_backend.

    nginx_lb:
      image: nginx:latest
      container_name: api-fw-loadbalancer
      volumes:
        - ./files/nginx/balancer.conf:/etc/nginx/conf.d/balancer.conf # Файл конфигурации Nginx
      ports:
        - "8081:8081"
        - "8082:80"
      networks:
        - api-firewall-manager-network
      depends_on:
        - manager_backend_1
        - manager_backend_2
    

    upstream manager_backend_group {
      server api-fw-manager-1:8082 max_fails=3 fail_timeout=30s;
      server api-fw-manager-2:8082 max_fails=3 fail_timeout=30s;
    }
    
    server {
        listen 80;
        server_name _;
    
        location /api/ {
            # Проксирование трафика на группу бэкендов
            proxy_pass http://manager_backend_group/api/;
    
            # Стандартные заголовки
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
    
    upstream manager_backend_grpc_group {
        server api-fw-manager-1:8081;
        server api-fw-manager-2:8081; 
    }
    
    server {
        listen 8081 http2;
        server_name _;  
    
        location / {
            # Проксирование на gRPC
            grpc_pass grpc://manager_backend_grpc_group;
    
            # Рекомендуемые заголовки для gRPC
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    

Шаг 3. Настройка сервиса Manager UI

  1. В сервисе manager_ui измените переменную окружения API_BACKEND_URL. Теперь она должна указывать на адрес балансировщика nginx_lb, а не на прямой адрес бэкенда.

       manager_ui:
     container_name: manager_ui
     image: registry.webmonitorx.ru/api-firewall/apifw-manager-ui:1.2.2
     volumes:
       - ./files/nginx/default.conf:/etc/nginx/conf.d/default.conf  # Конфигурационный файл внутреннеего nginx-сервера
       - ./files/ssl/fullchain.pem:/etc/ssl/fullchain.pem # Сертификат для HTTPS
       - ./files/ssl/privkey.pem:/etc/ssl/privkey.pem  # Сертификат для HTTPS
       - ./ssl/ssl-dhparams.pem:/etc/ssl/ssl-dhparams.pem # Сертификат для HTTPS
     environment:
       API_BASE_URL: ${API_BASE_URL}
       API_BACKEND_URL: http://api-fw-loadbalancer:80/api/
     ports:
       - "8088:8088"
       - "443:443"
     networks:
       - api-firewall-manager-network
     depends_on:
       - manager_backend_1
       - manager_backend_2
       - nginx_lb
    

  2. Обновите монтируемый конфигурационный файл default.conf для manager_ui. В секции location /api укажите в качестве upstream сервис nginx_lb.

        location /api {
        proxy_pass http://api-fw-loadbalancer:80/api;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      }
    

Шаг 4. Настройка фильтрующих нод и отказоустойчивости (failover)

  1. Запустите две фильтрующие ноды на разных портах.

  2. Сконфигурируйте Angie/NGINX для проксирования трафика на ноды фильтрации.

     # Группа апстрим для нескольких нод
     upstream apifw_node_group {
       server 172.17.0.3:8093;
       server 172.17.0.5:8094 backup;
     }
    
     server {
       listen 8443 ssl;
       listen [::]:8443 ssl;
       server_name домен_приложения;
    
       ssl_certificate /etc/angie/ssl/fullchain.pem;
       ssl_certificate_key /etc/angie/ssl/privkey.pem;
    
       # Проксирование API
       location /api/ {
           proxy_pass http://apifw_node_group/;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_set_header X-Forwarded-Proto $scheme;
           proxy_set_header Authorization $http_authorization;
           proxy_connect_timeout 75s;
           proxy_send_timeout 75s;
           proxy_read_timeout 75s;
       }