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

Сервисы инфраструктуры

Дата: 2026-01-23


1. CallBox — Веб-приложение

1.1 Backend (FastAPI)

Расположение: web-1, web-2 (Docker контейнеры)

Параметр Значение
Технология FastAPI + SQLAlchemy + Pydantic
Python 3.12
Порт 8000
Контейнер callbox-backend
Точка входа uvicorn app.main:app

Основные компоненты: - app/main.py — точка входа FastAPI - app/config.py — конфигурация из переменных окружения - app/database.py — подключение к PostgreSQL - app/models/ — SQLAlchemy модели - app/schemas/ — Pydantic схемы валидации - app/routes/ — API endpoints - app/services/ — бизнес-логика (asterisk_sync, tts_service)

API Endpoints:

/organizations          — CRUD организаций
/operators             — CRUD операторов
/queues                — CRUD очередей
/endpoints             — CRUD SIP терминалов
/incoming-routes       — CRUD входящих маршрутов
/working-hours         — Графики работы очередей
/statistics            — Статистика звонков
/monitoring            — Онлайн мониторинг
/recordings            — Записи разговоров
/auth                  — Аутентификация

Переменные окружения:

DATABASE_URL=postgresql://asterisk:***@db-1:5432/asterisk
SECRET_KEY=***
AMI_HOST=10.10.19.51
AMI_PORT=5038
AMI_USERNAME=webadmin
AMI_SECRET=***
ASTERISK_CONFIG_MODE=remote
ASTERISK_SSH_HOST=10.10.19.51
ASTERISK_SSH_USER=sysadmin
REDIS_URL=redis://:***@redis-1:6379/0

1.2 Frontend (React)

Расположение: web-1, web-2 (Docker контейнеры)

Параметр Значение
Технология React 19 + TypeScript + Vite
Порт 3000 (nginx)
Контейнер callbox-frontend
Сборка npm run build → nginx

Основные компоненты: - src/pages/admin/ — Административный портал - src/pages/client/ — Клиентский портал - src/components/ — Переиспользуемые компоненты - src/services/ — API клиенты (axios + TanStack Query) - src/schemas/ — Zod схемы валидации

Порталы: - /admin/* — Управление организациями, очередями, операторами - /client/:tenantId/* — Статистика, мониторинг, расписания


2. PostgreSQL кластер

2.1 Архитектура

┌─────────────────┐     Streaming      ┌─────────────────┐
│     db-1        │     Replication    │     db-2        │
│   10.10.19.31   │ ──────────────────►│   10.10.19.32   │
│    PRIMARY      │                    │    REPLICA      │
│   PostgreSQL    │                    │   PostgreSQL    │
│     16.11       │                    │     16.11       │
└────────┬────────┘                    └────────┬────────┘
         │                                      │
         │           Patroni HA                 │
         │                                      │
         ▼                                      ▼
┌─────────────────────────────────────────────────────────┐
│                     etcd cluster                         │
│  db-1:2379  ◄────────►  db-2:2379  ◄────────►  mon-1:2379│
└─────────────────────────────────────────────────────────┘

2.2 PostgreSQL Primary (db-1)

Параметр Значение
Версия PostgreSQL 16.11
Порт 5432
База данных asterisk
Пользователь asterisk
Роль Primary (pg_is_in_recovery = false)

Конфигурация Patroni:

scope: callbox-cluster
name: db-1
restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.10.19.31:8008
etcd3:
  hosts:
    - 10.10.19.31:2379
    - 10.10.19.32:2379
    - 10.10.19.60:2379
bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      use_slots: true
postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.10.19.31:5432
  data_dir: /var/lib/postgresql/16/main
  authentication:
    superuser:
      username: postgres
    replication:
      username: replicator

Основные таблицы: - organizations — Организации (тенанты) - operators — Операторы - queues — Очереди - ps_endpoints — PJSIP endpoints - ps_auths, ps_aors — PJSIP аутентификация - incoming_routes — Входящие маршруты - working_hours — Графики работы - call_detail_records — CDR (записи звонков) - users, staff_users — Пользователи системы

2.3 PostgreSQL Replica (db-2)

Параметр Значение
Версия PostgreSQL 16.11
Порт 5432
Роль Replica (pg_is_in_recovery = true)
Репликация Streaming от db-1

Использование: - Только для чтения (read-only queries) - Hot standby для failover - Автоматический failover через Patroni

2.4 etcd кластер

Нода IP Порты
db-1 10.10.19.31 2379, 2380
db-2 10.10.19.32 2379, 2380
mon-1 10.10.19.60 2379, 2380

Назначение: - Distributed consensus для Patroni - Leader election для PostgreSQL - Хранение состояния кластера


3. Redis

3.1 Redis Master (redis-1)

Параметр Значение
Версия Redis 7.0.15
Порт 6379
Sentinel порт 26379
Аутентификация Включена (requirepass)

Конфигурация Sentinel:

sentinel monitor callbox-redis 10.10.19.40 6379 2
sentinel down-after-milliseconds callbox-redis 5000
sentinel failover-timeout callbox-redis 60000

Sentinel nodes: - redis-1:26379 - web-1:26379 - web-2:26379

Использование: - Кэширование сессий - Кэширование API запросов - Pub/Sub для real-time событий - Rate limiting


4. Asterisk

4.1 Asterisk Primary (voip-1)

Параметр Значение
Версия Asterisk 20.17.0
Порт SIP 5060/UDP
Порт AMI 5038/TCP
Порт RTP 10000-20000/UDP
Realtime ODBC → PostgreSQL

Конфигурационные файлы:

/etc/asterisk/
├── pjsip.conf           # SIP endpoints (генерируется из БД)
├── queues.conf          # Очереди (генерируется из БД)
├── queues_generated.conf # Автогенерируемый файл очередей
├── extensions.conf      # Dialplan
├── func_odbc.conf       # ODBC функции для CDR
├── res_odbc.conf        # ODBC подключение к PostgreSQL
├── manager.conf         # AMI пользователи
└── modules.conf         # Загружаемые модули

PJSIP Realtime: - Endpoints загружаются из таблицы ps_endpoints - Auths загружаются из таблицы ps_auths - AORs загружаются из таблицы ps_aors

AMI пользователи:

[webadmin]
secret = ***
read = all
write = all

Dialplan контексты: - [incoming] — Входящие звонки - [internal] — Внутренние звонки - [outbound] — Исходящие звонки - [cdr-init] — Инициализация CDR - [operator-login] — Вход операторов в очереди

4.2 Asterisk Secondary (voip-2)

Параметр Значение
Версия Asterisk 20.17.0
Порт SIP 5060/UDP
Статус Hot standby

Назначение: - Резервный сервер - Ручное переключение при отказе voip-1

4.3 Синхронизация конфигурации

Автоматическая синхронизация (asterisk_sync.py): 1. При изменении очередей через API 2. Генерация queues_generated.conf из БД 3. SSH копирование на voip-1 4. Команда asterisk -rx "queue reload all"

Ручная синхронизация:

# На web-1 или web-2
python -c "from app.services.asterisk_sync import sync_queues_to_asterisk; sync_queues_to_asterisk()"

5. Nginx / Load Balancing

5.1 lb-1 (Primary Load Balancer)

Nginx конфигурация:

# Upstream для API
upstream backend {
    least_conn;
    server 10.10.19.21:8000;
    server 10.10.19.22:8000;
}

# Upstream для Frontend
upstream frontend {
    least_conn;
    server 10.10.19.21:3000;
    server 10.10.19.22:3000;
}

# HTTPS сервер
server {
    listen 443 ssl http2;
    server_name b2g.kz;

    ssl_certificate /etc/letsencrypt/live/b2g.kz/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/b2g.kz/privkey.pem;

    location /api/ {
        proxy_pass http://backend/;
        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;
    }

    location / {
        proxy_pass http://frontend/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# HTTP → HTTPS redirect
server {
    listen 80;
    server_name b2g.kz;
    return 301 https://$server_name$request_uri;
}

5.2 lb-2 (Secondary Load Balancer)

  • Аналогичная конфигурация nginx
  • Резервный публичный IP: 92.47.181.152
  • Используется при отказе lb-1

5.3 SIP/RTP NAT

iptables правила на lb-1/lb-2:

# DNAT SIP на voip-1
iptables -t nat -A PREROUTING -p udp --dport 5060 -j DNAT --to 10.10.19.51:5060

# DNAT RTP на voip-1
iptables -t nat -A PREROUTING -p udp --dport 10000:20000 -j DNAT --to 10.10.19.51

# MASQUERADE для ответов
iptables -t nat -A POSTROUTING -s 10.10.19.0/24 -j MASQUERADE

6. Мониторинг

6.1 Prometheus (mon-1)

Параметр Значение
Порт 9090
Retention 15 дней
Scrape interval 15 секунд

Targets (prometheus.yml):

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
        - 10.10.19.10:9100  # lb-1
        - 10.10.19.11:9100  # lb-2
        - 10.10.19.21:9100  # web-1
        - 10.10.19.22:9100  # web-2
        - 10.10.19.31:9100  # db-1
        - 10.10.19.32:9100  # db-2
        - 10.10.19.40:9100  # redis-1
        - 10.10.19.51:9100  # voip-1
        - 10.10.19.52:9100  # voip-2
        - 10.10.19.60:9100  # mon-1

Собираемые метрики: - CPU, Memory, Disk, Network (node_exporter) - PostgreSQL метрики (postgres_exporter) - Redis метрики (redis_exporter) - Docker метрики (cadvisor)

6.2 Grafana (mon-1)

Параметр Значение
Версия 12.3.1
Порт 3000
Доступ https://mon.b2g.kz

Dashboards: - Node Exporter Full — Системные метрики - PostgreSQL Overview — Метрики БД - Redis Dashboard — Метрики Redis - Docker Containers — Метрики контейнеров

6.3 node_exporter

Установлен на всех серверах:

# Системный сервис
/usr/bin/node_exporter --web.listen-address=:9100

Порт: 9100/TCP


7. Docker

7.1 Docker на web-1/web-2

docker-compose.yml:

version: '3.8'

services:
  backend:
    container_name: callbox-backend
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://asterisk:***@db-1:5432/asterisk
      - REDIS_URL=redis://:***@redis-1:6379/0
    volumes:
      - /var/lib/callbox:/var/lib/callbox
      - /root/.ssh:/root/.ssh:ro
    restart: always

  frontend:
    container_name: callbox-frontend
    build: ./frontend
    ports:
      - "3000:80"
    restart: always

networks:
  default:
    driver: bridge

Volumes: - /var/lib/callbox — Данные приложения (скриншоты, загрузки) - /root/.ssh — SSH ключи для подключения к voip-1

7.2 Docker на mon-1

Контейнеры: - prometheus — Сбор метрик - grafana — Визуализация - node-exporter — Метрики хоста


8. Системные сервисы

8.1 systemd сервисы

Сервер Сервисы
lb-1, lb-2 nginx, node_exporter
web-1, web-2 docker, node_exporter
db-1, db-2 postgresql, patroni, etcd, node_exporter
redis-1 redis-server, redis-sentinel, node_exporter
voip-1, voip-2 asterisk, node_exporter
mon-1 docker (prometheus, grafana), etcd, node_exporter

8.2 Управление сервисами

# Проверка статуса
systemctl status <service>

# Перезапуск
systemctl restart <service>

# Логи
journalctl -u <service> -f

# Docker контейнеры
docker ps
docker logs <container>
docker-compose restart

9. Интеграции

9.1 CallBox ↔ PostgreSQL

web-1/web-2 (SQLAlchemy)
     │
     │  TCP:5432
     │  postgresql://asterisk:***@db-1:5432/asterisk
     ▼
   db-1 (Primary)

9.2 CallBox ↔ Asterisk

web-1/web-2
     │
     ├── TCP:5038 (AMI) ─────────────────► voip-1
     │   - Мониторинг очередей
     │   - Статус endpoints
     │
     └── TCP:22 (SSH) ───────────────────► voip-1
         - Синхронизация конфигурации
         - Reload команды

9.3 Asterisk ↔ PostgreSQL

voip-1/voip-2 (ODBC Realtime)
     │
     │  TCP:5432
     │  ODBC: asterisk-connector
     ▼
   db-1
     │
     ├── Чтение: ps_endpoints, ps_auths, ps_aors
     └── Запись: call_detail_records

9.4 CallBox ↔ Redis

web-1/web-2
     │
     │  TCP:6379
     │  redis://:***@redis-1:6379/0
     ▼
 redis-1
     │
     ├── Кэш сессий
     ├── Кэш API
     └── Rate limiting

10. Безопасность сервисов

10.1 Аутентификация

Сервис Метод
PostgreSQL scram-sha-256
Redis requirepass
AMI secret в manager.conf
API JWT tokens
SSH Key-based

10.2 Шифрование

Соединение Шифрование
HTTPS TLS 1.2/1.3 (Let's Encrypt)
PostgreSQL Без шифрования (внутренняя сеть)
Redis Без шифрования (внутренняя сеть)
SIP Без шифрования (NAT через LB)

10.3 Firewall

Все сервисы защищены iptables: - Внешний доступ только через lb-1/lb-2 - Внутренние сервисы доступны только из 10.10.19.0/24 - SSH только с админских IP через lb-1