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:
parent
b75b8e62a6
commit
4800e8c375
45
.env.prod.example
Normal file
45
.env.prod.example
Normal 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
286
docker-compose.prod.yml
Normal 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
|
||||
12
monitoring/grafana/dashboards/dashboard.yml
Normal file
12
monitoring/grafana/dashboards/dashboard.yml
Normal 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
|
||||
11
monitoring/grafana/datasources/prometheus.yml
Normal file
11
monitoring/grafana/datasources/prometheus.yml
Normal 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
47
monitoring/prometheus.yml
Normal 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
87
nginx/nginx.conf
Normal 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;
|
||||
# }
|
||||
# }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user