feat: Add production Docker orchestration with monitoring

Production Stack (7 services):
- buh_bot: Main bot from registry (1 CPU, 1GB RAM)
- nginx: Reverse proxy with rate limiting (10 req/s)
- prometheus: Metrics collection (30d retention)
- grafana: Monitoring dashboards (port 3000)
- node_exporter: Host metrics (port 9100)
- cadvisor: Container metrics (port 8080)
- watchtower: Auto-updates (hourly check)

Configuration:
- docker-compose.prod.yml with 7-service stack
- nginx.conf with SSL-ready config and healthchecks
- prometheus.yml with scrape configs
- grafana datasource and dashboard provisioning
- .env.prod.example template
- Custom network 172.20.0.0/16
- Persistent volumes in /var/lib/buh_bot
- Log rotation: 50MB x 5 files
This commit is contained in:
admin i 2025-11-03 14:20:48 +03:00
parent b75b8e62a6
commit 4800e8c375
6 changed files with 488 additions and 0 deletions

45
.env.prod.example Normal file
View File

@ -0,0 +1,45 @@
# Production Environment Variables
# ===== Основные настройки =====
# Telegram Bot Token (обязательно!)
TELEGRAM_BOT_TOKEN=your_production_bot_token_here
# МойСклад API
MOYSKLAD_API_URL=https://api.moysklad.ru/api/remap/1.2
# Timezone
TZ=Europe/Moscow
# Уровень логирования (DEBUG, INFO, WARNING, ERROR)
LOG_LEVEL=INFO
# ===== Docker Registry =====
# Для использования собственного registry
DOCKER_REGISTRY=ghcr.io
DOCKER_USERNAME=your_github_username
BOT_VERSION=latest
# ===== Nginx =====
NGINX_HTTP_PORT=80
NGINX_HTTPS_PORT=443
# ===== Мониторинг =====
# Prometheus
PROMETHEUS_PORT=9090
# Grafana
GRAFANA_PORT=3000
GRAFANA_USER=admin
GRAFANA_PASSWORD=change_me_in_production
# ===== Watchtower (auto-update) =====
# Уведомления (опционально)
# Примеры:
# Telegram: telegram://token@telegram?channels=channel_id
# Email: smtp://username:password@host:port/?from=sender@example.com&to=receiver@example.com
WATCHTOWER_NOTIFICATION_URL=
# ===== Backup =====
BACKUP_ENABLED=true
BACKUP_SCHEDULE=0 2 * * *
BACKUP_RETENTION_DAYS=30

286
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,286 @@
version: '3.8'
# Production Docker Compose для BUH Bot
# Использует готовые образы, nginx, мониторинг
services:
# Telegram бот
buh_bot:
image: ${DOCKER_REGISTRY:-ghcr.io}/${DOCKER_USERNAME:-username}/buh_bot:${BOT_VERSION:-latest}
container_name: buh_bot_prod
restart: always
environment:
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
- MOYSKLAD_API_URL=${MOYSKLAD_API_URL:-https://api.moysklad.ru/api/remap/1.2}
- TZ=${TZ:-Europe/Moscow}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
- DATA_DIR=/app/data
- LOGS_DIR=/app/logs
volumes:
# Персистентные данные на хосте
- /var/lib/buh_bot/data:/app/data
- /var/log/buh_bot:/app/logs
- /var/tmp/buh_bot:/app/temp_documents
networks:
- buh_network
# Ограничения ресурсов для production
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
# Healthcheck для мониторинга
healthcheck:
test: ["CMD", "python", "-c", "import sys; sys.exit(0)"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Логирование с ротацией
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
labels: "service=buh_bot,environment=production"
labels:
- "com.buh_bot.service=telegram-bot"
- "com.buh_bot.environment=production"
# Nginx reverse proxy (для webhook режима или API)
nginx:
image: nginx:alpine
container_name: buh_bot_nginx
restart: always
ports:
- "${NGINX_HTTP_PORT:-80}:80"
- "${NGINX_HTTPS_PORT:-443}:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- /var/log/nginx:/var/log/nginx
networks:
- buh_network
depends_on:
- buh_bot
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
interval: 30s
timeout: 5s
retries: 3
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "3"
# Prometheus для метрик
prometheus:
image: prom/prometheus:latest
container_name: buh_bot_prometheus
restart: always
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
networks:
- buh_network
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Grafana для визуализации метрик
grafana:
image: grafana/grafana:latest
container_name: buh_bot_grafana
restart: always
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin}
- GF_INSTALL_PLUGINS=
volumes:
- grafana_data:/var/lib/grafana
- ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
- ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources:ro
networks:
- buh_network
ports:
- "${GRAFANA_PORT:-3000}:3000"
depends_on:
- prometheus
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Node Exporter для метрик хоста
node_exporter:
image: prom/node-exporter:latest
container_name: buh_bot_node_exporter
restart: always
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
networks:
- buh_network
ports:
- "9100:9100"
deploy:
resources:
limits:
cpus: '0.2'
memory: 128M
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "2"
# cAdvisor для метрик контейнеров
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: buh_bot_cadvisor
restart: always
privileged: true
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
networks:
- buh_network
ports:
- "8080:8080"
deploy:
resources:
limits:
cpus: '0.3'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "2"
# Watchtower для автоматического обновления образов
watchtower:
image: containrrr/watchtower:latest
container_name: buh_bot_watchtower
restart: always
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_POLL_INTERVAL=3600
- WATCHTOWER_INCLUDE_STOPPED=false
- WATCHTOWER_REVIVE_STOPPED=false
- WATCHTOWER_NOTIFICATIONS=shoutrrr
- WATCHTOWER_NOTIFICATION_URL=${WATCHTOWER_NOTIFICATION_URL:-}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- buh_network
deploy:
resources:
limits:
cpus: '0.2'
memory: 128M
logging:
driver: "json-file"
options:
max-size: "5m"
max-file: "2"
# Сети
networks:
buh_network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
# Volumes для персистентных данных
volumes:
prometheus_data:
driver: local
grafana_data:
driver: local

View File

@ -0,0 +1,12 @@
apiVersion: 1
providers:
- name: 'BUH Bot Dashboards'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards

View File

@ -0,0 +1,11 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
jsonData:
timeInterval: "15s"

47
monitoring/prometheus.yml Normal file
View File

@ -0,0 +1,47 @@
# Prometheus configuration for BUH Bot monitoring
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'buh_bot_production'
environment: 'production'
# Alerting configuration
alerting:
alertmanagers:
- static_configs:
- targets: []
# Scrape configurations
scrape_configs:
# Prometheus self-monitoring
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# Node Exporter (host metrics)
- job_name: 'node_exporter'
static_configs:
- targets: ['node_exporter:9100']
labels:
instance: 'host'
# cAdvisor (container metrics)
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
labels:
instance: 'containers'
# Docker daemon metrics (если включено)
# - job_name: 'docker'
# static_configs:
# - targets: ['host.docker.internal:9323']
# BUH Bot metrics (если бот экспортирует метрики)
# - job_name: 'buh_bot'
# static_configs:
# - targets: ['buh_bot:8000']
# labels:
# service: 'telegram_bot'

87
nginx/nginx.conf Normal file
View File

@ -0,0 +1,87 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Логирование
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Производительность
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 20M;
# Gzip сжатие
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss;
# SSL параметры
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Rate limiting
limit_req_zone $binary_remote_addr zone=bot_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# Healthcheck endpoint
server {
listen 80;
server_name _;
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
location /metrics {
access_log off;
return 200 "nginx_up 1\n";
add_header Content-Type text/plain;
}
}
# Webhook endpoint (если используется)
# server {
# listen 443 ssl http2;
# server_name your-domain.com;
#
# ssl_certificate /etc/nginx/ssl/fullchain.pem;
# ssl_certificate_key /etc/nginx/ssl/privkey.pem;
#
# location /webhook {
# limit_req zone=bot_limit burst=20 nodelay;
# limit_conn conn_limit 10;
#
# proxy_pass http://buh_bot:8443;
# 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;
# }
# }
}