architect/_archive/2025-11-cleanup/platform-v2-cifra/archive/2025-11-10-restructure-v2/DEPLOYMENT_GUIDE.md

CIFRA Platform - Deployment Guide

Дата: 2025-11-10
Версия: 1.0
Статус: Production Ready


Обзор

Этот документ описывает полный процесс развёртывания CIFRA Platform от development до production.


1. ОКРУЖЕНИЯ

1.1 Development (Локальная разработка)

Назначение: Разработка и отладка

Инфраструктура:

Hardware:
  CPU: 2-4 cores
  RAM: 8 GB
  Disk: 20 GB SSD

Software:
  OS: Linux/macOS/Windows
  Python: 3.10+
  Docker: 24+
  Docker Compose: 2.0+
  Git: 2.30+

Установка:

# 1. Клонировать репозиторий
git clone https://github.com/cifra/cifra-platform.git
cd cifra-platform

# 2. Создать виртуальное окружение
python3 -m venv venv
source venv/bin/activate  # Linux/macOS
# venv\Scripts\activate   # Windows

# 3. Установить зависимости
pip install -r requirements-dev.txt

# 4. Скопировать конфигурацию
cp .env.example .env

# 5. Редактировать .env
nano .env

# 6. Запустить зависимости (PostgreSQL, Redis)
docker-compose -f docker-compose.dev.yml up -d

# 7. Применить миграции
alembic upgrade head

# 8. Создать суперпользователя
python scripts/create_superuser.py

# 9. Запустить сервер
uvicorn cifra.main:app --reload --port 8000

# 10. В отдельном терминале - Celery worker
celery -A cifra.worker worker -l info

# 11. В третьем терминале - Celery beat
celery -A cifra.worker beat -l info

Проверка:

# API
curl http://localhost:8000/health
# {"status": "ok", "version": "1.0.0"}

# Admin UI
open http://localhost:8000/admin

# API Docs
open http://localhost:8000/docs  # Swagger UI

1.2 Staging (Тестовое окружение)

Назначение: Тестирование перед production

Инфраструктура:

Hardware:
  CPU: 2 cores
  RAM: 4 GB
  Disk: 40 GB SSD

Cloud:
  Provider: DigitalOcean / AWS / GCP / Azure
  Instance: $20-40/month

Software:
  OS: Ubuntu 22.04 LTS
  Docker: 24+
  Docker Compose: 2.0+

Развёртывание:

# 1. Подключиться к серверу
ssh deploy@staging.cifra.io

# 2. Клонировать репозиторий
git clone https://github.com/cifra/cifra-platform.git /opt/cifra
cd /opt/cifra

# 3. Checkout нужной ветки
git checkout develop

# 4. Скопировать production конфигурацию
cp .env.staging .env

# 5. Редактировать .env
nano .env

# Обязательные переменные:
DATABASE_URL=postgresql://user:pass@db:5432/cifra_staging
REDIS_URL=redis://redis:6379/0
SECRET_KEY=<random-secret-key>
ALLOWED_HOSTS=staging.cifra.io
DEBUG=false
ENVIRONMENT=staging

# 6. Запустить через Docker Compose
docker-compose -f docker-compose.staging.yml up -d

# 7. Применить миграции
docker-compose exec app alembic upgrade head

# 8. Создать суперпользователя
docker-compose exec app python scripts/create_superuser.py

# 9. Собрать статику (если есть)
docker-compose exec app python scripts/collectstatic.py

docker-compose.staging.yml:

version: '3.8'

services:
  app:
    build: .
    image: cifra/platform:staging
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - SECRET_KEY=${SECRET_KEY}
    depends_on:
      - db
      - redis
    restart: unless-stopped
    volumes:
      - ./media:/app/media
      - ./logs:/app/logs

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: cifra
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: cifra_staging
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7
    volumes:
      - redis_data:/data
    restart: unless-stopped

  celery:
    image: cifra/platform:staging
    command: celery -A cifra.worker worker -l info
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
    depends_on:
      - redis
      - db
    restart: unless-stopped

  celery-beat:
    image: cifra/platform:staging
    command: celery -A cifra.worker beat -l info
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
    depends_on:
      - redis
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/staging.conf:/etc/nginx/conf.d/default.conf
      - ./ssl:/etc/nginx/ssl
      - ./media:/usr/share/nginx/media
    depends_on:
      - app
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

nginx/staging.conf:

upstream app {
    server app:8000;
}

server {
    listen 80;
    server_name staging.cifra.io;

    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name staging.cifra.io;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    client_max_body_size 100M;

    location / {
        proxy_pass http://app;
        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 /media {
        alias /usr/share/nginx/media;
    }

    location /static {
        alias /usr/share/nginx/static;
    }
}

SSL сертификат (Let's Encrypt):

# Установить certbot
sudo apt install certbot python3-certbot-nginx

# Получить сертификат
sudo certbot --nginx -d staging.cifra.io

# Автоматическое обновление
sudo certbot renew --dry-run

1.3 Production (Боевое окружение)

Назначение: Production для пользователей

Инфраструктура:

Вариант 1: Single Server (до 1000 пользователей)

Hardware:
  CPU: 4 cores
  RAM: 8 GB
  Disk: 100 GB SSD

Cloud:
  Provider: DigitalOcean / AWS / GCP / Azure
  Instance: $80-120/month

Вариант 2: Multi-Server (1000-10000 пользователей)

Load Balancer: 1x (2 cores, 2GB RAM)
App Servers: 3x (4 cores, 8GB RAM)
Database: 1x Primary + 1x Replica (4 cores, 16GB RAM)
Redis Cluster: 3x (2 cores, 4GB RAM)
Celery Workers: 2x (2 cores, 4GB RAM)

Total: ~$500-800/month

Вариант 3: Kubernetes (10000+ пользователей)

Cluster:
  Nodes: 5-10 nodes (4 cores, 16GB RAM each)
  Autoscaling: enabled
  Multi-zone: yes

Services:
  - App: 3-10 pods (autoscale)
  - Celery: 2-5 pods (autoscale)
  - PostgreSQL: Managed service (AWS RDS, GCP CloudSQL)
  - Redis: Managed service (AWS ElastiCache, GCP Memorystore)
  - S3: Object storage (AWS S3, GCP GCS)

Total: $1000-5000/month

2. DOCKER DEPLOYMENT (Production Single Server)

2.1 Dockerfile

# Dockerfile
FROM python:3.11-slim

# Установка системных зависимостей
RUN apt-get update && apt-get install -y \
    postgresql-client \
    build-essential \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# Рабочая директория
WORKDIR /app

# Копирование зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Копирование кода
COPY . .

# Создание пользователя (не root)
RUN useradd -m -u 1000 cifra && chown -R cifra:cifra /app
USER cifra

# Healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# Expose порт
EXPOSE 8000

# Запуск
CMD ["uvicorn", "cifra.main:app", "--host", "0.0.0.0", "--port", "8000"]

2.2 docker-compose.production.yml

version: '3.8'

services:
  app:
    build: .
    image: cifra/platform:${VERSION:-latest}
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - SECRET_KEY=${SECRET_KEY}
      - ENVIRONMENT=production
    depends_on:
      - db
      - redis
    volumes:
      - ./media:/app/media
      - ./logs:/app/logs
    networks:
      - cifra-network

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backups:/backups
    networks:
      - cifra-network
    restart: unless-stopped
    # Backup script
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7
    command: redis-server --appendonly yes --maxmemory 2gb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    networks:
      - cifra-network
    restart: unless-stopped

  celery:
    image: cifra/platform:${VERSION:-latest}
    command: celery -A cifra.worker worker -l info --concurrency=4
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
    depends_on:
      - redis
      - db
    networks:
      - cifra-network
    restart: unless-stopped
    deploy:
      replicas: 2

  celery-beat:
    image: cifra/platform:${VERSION:-latest}
    command: celery -A cifra.worker beat -l info
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
    depends_on:
      - redis
    networks:
      - cifra-network
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/production.conf:/etc/nginx/conf.d/default.conf
      - ./ssl:/etc/nginx/ssl
      - ./media:/usr/share/nginx/media
    depends_on:
      - app
    networks:
      - cifra-network
    restart: unless-stopped

  # Monitoring
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"
    networks:
      - cifra-network
    restart: unless-stopped

  grafana:
    image: grafana/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
    volumes:
      - grafana_data:/var/lib/grafana
    ports:
      - "3000:3000"
    networks:
      - cifra-network
    restart: unless-stopped

networks:
  cifra-network:
    driver: bridge

volumes:
  postgres_data:
  redis_data:
  prometheus_data:
  grafana_data:

2.3 Развёртывание

# 1. Подключиться к серверу
ssh deploy@production.cifra.io

# 2. Клонировать репозиторий
git clone https://github.com/cifra/cifra-platform.git /opt/cifra
cd /opt/cifra

# 3. Checkout production ветки
git checkout main

# 4. Создать .env
cp .env.production.example .env
nano .env

# 5. Сгенерировать SECRET_KEY
python -c "import secrets; print(secrets.token_urlsafe(50))"

# 6. Запустить
docker-compose -f docker-compose.production.yml up -d

# 7. Проверить статус
docker-compose ps

# 8. Применить миграции
docker-compose exec app alembic upgrade head

# 9. Создать суперпользователя
docker-compose exec app python scripts/create_superuser.py

# 10. Проверить логи
docker-compose logs -f app

# 11. Проверить доступность
curl https://production.cifra.io/health

3. KUBERNETES DEPLOYMENT

3.1 Namespace

# k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: cifra

3.2 ConfigMap

# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cifra-config
  namespace: cifra
data:
  ENVIRONMENT: "production"
  ALLOWED_HOSTS: "app.cifra.io,*.cifra.io"
  LOG_LEVEL: "INFO"

3.3 Secrets

# k8s/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: cifra-secrets
  namespace: cifra
type: Opaque
data:
  # Base64 encoded
  DATABASE_URL: cG9zdGdyZXNxbDovL3VzZXI6cGFzc0BkYjo1NDMyL2NpZnJh
  REDIS_URL: cmVkaXM6Ly9yZWRpczozNjM3OS8w
  SECRET_KEY: c3VwZXItc2VjcmV0LWtleQ==

Создание секретов:

kubectl create secret generic cifra-secrets \
  --from-literal=DATABASE_URL="postgresql://user:pass@db:5432/cifra" \
  --from-literal=REDIS_URL="redis://redis:6379/0" \
  --from-literal=SECRET_KEY="super-secret-key" \
  -n cifra

3.4 Deployment

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cifra-app
  namespace: cifra
spec:
  replicas: 3
  selector:
    matchLabels:
      app: cifra
  template:
    metadata:
      labels:
        app: cifra
    spec:
      containers:
      - name: app
        image: cifra/platform:1.0.0
        ports:
        - containerPort: 8000
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: cifra-secrets
              key: DATABASE_URL
        - name: REDIS_URL
          valueFrom:
            secretKeyRef:
              name: cifra-secrets
              key: REDIS_URL
        - name: SECRET_KEY
          valueFrom:
            secretKeyRef:
              name: cifra-secrets
              key: SECRET_KEY
        envFrom:
        - configMapRef:
            name: cifra-config
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 5

3.5 Service

# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: cifra-service
  namespace: cifra
spec:
  selector:
    app: cifra
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: LoadBalancer

3.6 Ingress

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cifra-ingress
  namespace: cifra
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.cifra.io
    secretName: cifra-tls
  rules:
  - host: app.cifra.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: cifra-service
            port:
              number: 80

3.7 HorizontalPodAutoscaler

# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cifra-hpa
  namespace: cifra
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cifra-app
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

3.8 Развёртывание в Kubernetes

# 1. Создать namespace
kubectl apply -f k8s/namespace.yaml

# 2. Создать секреты
kubectl apply -f k8s/secrets.yaml

# 3. Создать ConfigMap
kubectl apply -f k8s/configmap.yaml

# 4. Развернуть приложение
kubectl apply -f k8s/deployment.yaml

# 5. Создать Service
kubectl apply -f k8s/service.yaml

# 6. Создать Ingress
kubectl apply -f k8s/ingress.yaml

# 7. Создать HPA
kubectl apply -f k8s/hpa.yaml

# 8. Проверить статус
kubectl get pods -n cifra
kubectl get svc -n cifra
kubectl get ingress -n cifra

# 9. Проверить логи
kubectl logs -f deployment/cifra-app -n cifra

# 10. Применить миграции
kubectl exec -it deployment/cifra-app -n cifra -- alembic upgrade head

4. CI/CD PIPELINE

4.1 GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Install dependencies
      run: |
        pip install -r requirements.txt
        pip install pytest pytest-cov

    - name: Run tests
      run: pytest --cov=cifra tests/

    - name: Upload coverage
      uses: codecov/codecov-action@v3

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2

    - name: Login to DockerHub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}

    - name: Build and push
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: |
          cifra/platform:latest
          cifra/platform:${{ github.sha }}
          cifra/platform:${{ github.ref_name }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
    - name: Deploy to production
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.PRODUCTION_HOST }}
        username: deploy
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd /opt/cifra
          git pull origin main
          docker-compose pull
          docker-compose up -d
          docker-compose exec -T app alembic upgrade head

4.2 GitLab CI

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: cifra/platform

test:
  stage: test
  image: python:3.11
  script:
    - pip install -r requirements.txt
    - pip install pytest pytest-cov
    - pytest --cov=cifra tests/
  coverage: '/TOTAL.*\s+(\d+%)$/'

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
    - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
    - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
    - docker tag $DOCKER_IMAGE:$CI_COMMIT_SHA $DOCKER_IMAGE:latest
    - docker push $DOCKER_IMAGE:latest
  only:
    - main

deploy_production:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
  script:
    - ssh deploy@$PRODUCTION_HOST "cd /opt/cifra && ./deploy.sh"
  only:
    - main
  when: manual

5. ZERO-DOWNTIME DEPLOYMENT

5.1 Blue-Green Deployment

#!/bin/bash
# deploy-blue-green.sh

# Current version (blue)
CURRENT_VERSION=$(docker ps --filter "name=cifra-app-blue" --format "{{.Image}}")
NEW_VERSION="cifra/platform:${1:-latest}"

echo "Current version: $CURRENT_VERSION"
echo "New version: $NEW_VERSION"

# Deploy green
echo "Deploying green..."
docker-compose -f docker-compose.green.yml up -d

# Wait for green to be healthy
echo "Waiting for green to be healthy..."
for i in {1..30}; do
  if curl -f http://localhost:8001/health; then
    echo "Green is healthy!"
    break
  fi
  sleep 2
done

# Switch traffic to green
echo "Switching traffic to green..."
# Update nginx config to point to green
sed -i 's/app-blue/app-green/g' /etc/nginx/sites-available/cifra
nginx -s reload

# Wait 30 seconds
sleep 30

# Check if everything is OK
if ! curl -f https://app.cifra.io/health; then
  echo "ERROR: Green is not responding! Rolling back..."
  sed -i 's/app-green/app-blue/g' /etc/nginx/sites-available/cifra
  nginx -s reload
  exit 1
fi

# Stop blue
echo "Stopping blue..."
docker-compose -f docker-compose.blue.yml down

echo "Deployment complete!"

5.2 Rolling Update (Kubernetes)

# Rolling update with kubectl
kubectl set image deployment/cifra-app \
  app=cifra/platform:1.0.1 \
  -n cifra

# Проверить статус
kubectl rollout status deployment/cifra-app -n cifra

# Rollback если нужно
kubectl rollout undo deployment/cifra-app -n cifra

6. DATABASE MIGRATIONS

6.1 Создание миграции

# Development
alembic revision --autogenerate -m "Add user preferences table"

# Проверить что сгенерировалось
cat alembic/versions/xxxx_add_user_preferences_table.py

# Применить локально
alembic upgrade head

6.2 Применение в Production

# ВАЖНО: Сделать backup БД ПЕРЕД миграцией!

# 1. Backup
docker-compose exec db pg_dump -U cifra cifra > backup_$(date +%Y%m%d_%H%M%S).sql

# 2. Применить миграцию
docker-compose exec app alembic upgrade head

# 3. Проверить
docker-compose exec db psql -U cifra -c "\dt"

# 4. Если что-то пошло не так - откат
docker-compose exec app alembic downgrade -1

# 5. Или восстановление из backup
docker-compose exec -T db psql -U cifra cifra < backup_20251110_123456.sql

7. BACKUP & RESTORE

7.1 Database Backup

#!/bin/bash
# scripts/backup-db.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/postgres"
FILENAME="cifra_${DATE}.sql"

# Backup
docker-compose exec -T db pg_dump -U cifra cifra | gzip > ${BACKUP_DIR}/${FILENAME}.gz

# Upload to S3
aws s3 cp ${BACKUP_DIR}/${FILENAME}.gz s3://cifra-backups/postgres/

# Keep only last 30 days locally
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +30 -delete

echo "Backup complete: ${FILENAME}.gz"

Cron job:

# crontab -e
0 3 * * * /opt/cifra/scripts/backup-db.sh

7.2 Restore from Backup

#!/bin/bash
# scripts/restore-db.sh

BACKUP_FILE=$1

if [ -z "$BACKUP_FILE" ]; then
  echo "Usage: ./restore-db.sh <backup-file.sql.gz>"
  exit 1
fi

# Download from S3 if needed
if [[ $BACKUP_FILE == s3://* ]]; then
  aws s3 cp $BACKUP_FILE /tmp/restore.sql.gz
  BACKUP_FILE="/tmp/restore.sql.gz"
fi

# Extract
gunzip -c $BACKUP_FILE > /tmp/restore.sql

# Restore
docker-compose exec -T db psql -U cifra cifra < /tmp/restore.sql

# Cleanup
rm /tmp/restore.sql

echo "Restore complete!"

8. MONITORING

8.1 Health Checks

# cifra/api/health.py
from fastapi import APIRouter, status
from sqlalchemy import text

router = APIRouter()

@router.get("/health")
async def health_check():
    """Basic health check"""
    return {"status": "ok", "version": "1.0.0"}

@router.get("/ready")
async def readiness_check(db: AsyncSession = Depends(get_db)):
    """Readiness check (checks DB connection)"""
    try:
        # Check DB
        await db.execute(text("SELECT 1"))

        # Check Redis
        await redis.ping()

        return {"status": "ready"}
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
            detail=f"Service not ready: {str(e)}"
        )

8.2 Prometheus Metrics

# cifra/metrics.py
from prometheus_client import Counter, Histogram, Gauge
from fastapi import Request
import time

# Metrics
http_requests_total = Counter(
    'http_requests_total',
    'Total HTTP requests',
    ['method', 'endpoint', 'status']
)

http_request_duration_seconds = Histogram(
    'http_request_duration_seconds',
    'HTTP request duration',
    ['method', 'endpoint']
)

active_users = Gauge(
    'active_users',
    'Number of active users'
)

# Middleware
@app.middleware("http")
async def metrics_middleware(request: Request, call_next):
    start_time = time.time()

    response = await call_next(request)

    duration = time.time() - start_time

    http_requests_total.labels(
        method=request.method,
        endpoint=request.url.path,
        status=response.status_code
    ).inc()

    http_request_duration_seconds.labels(
        method=request.method,
        endpoint=request.url.path
    ).observe(duration)

    return response

# Metrics endpoint
from prometheus_client import generate_latest

@app.get("/metrics")
async def metrics():
    return Response(
        generate_latest(),
        media_type="text/plain"
    )

9. LOGGING

9.1 Structured Logging

# cifra/logging_config.py
import logging
import sys
from loguru import logger

# Remove default handler
logger.remove()

# Add JSON formatted handler for production
if settings.ENVIRONMENT == "production":
    logger.add(
        sys.stdout,
        format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {name}:{function}:{line} | {message}",
        serialize=True,  # JSON output
        level="INFO"
    )
else:
    # Human-readable for development
    logger.add(
        sys.stdout,
        format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
        level="DEBUG"
    )

# File handler (rotated)
logger.add(
    "logs/cifra_{time:YYYY-MM-DD}.log",
    rotation="00:00",  # Rotate daily
    retention="30 days",
    compression="gz",
    level="INFO"
)

# Error handler (separate file)
logger.add(
    "logs/errors_{time:YYYY-MM-DD}.log",
    rotation="00:00",
    retention="90 days",
    level="ERROR"
)

10. SECURITY CHECKLIST

Production Checklist:

Environment:
  - [ ] DEBUG=false
  - [ ] ENVIRONMENT=production
  - [ ] SECRET_KEY - случайный, 50+ символов
  - [ ] ALLOWED_HOSTS - только production домены

Database:
  - [ ] Сильный пароль (20+ символов)
  - [ ] Не использовать default пользователя
  - [ ] Включить SSL соединение
  - [ ] Регулярные backups (ежедневно)

Redis:
  - [ ] Пароль установлен
  - [ ] Не слушает на публичном интерфейсе
  - [ ] maxmemory policy настроен

HTTPS:
  - [ ] SSL сертификат установлен (Let's Encrypt / commercial)
  - [ ] HTTP → HTTPS redirect
  - [ ] HSTS header включён
  - [ ] SSL Labs оценка A+

Headers:
  - [ ] X-Frame-Options: DENY
  - [ ] X-Content-Type-Options: nosniff
  - [ ] X-XSS-Protection: 1; mode=block
  - [ ] Content-Security-Policy настроен
  - [ ] Strict-Transport-Security

CORS:
  - [ ] Настроены allowed origins
  - [ ] Не используется "*" wildcard

Rate Limiting:
  - [ ] Включён на уровне nginx/application
  - [ ] DDoS защита (Cloudflare)

Firewall:
  - [ ] Только нужные порты открыты (80, 443)
  - [ ] SSH только с определённых IP
  - [ ] Database не доступна извне

Monitoring:
  - [ ] Prometheus + Grafana настроены
  - [ ] Alerting настроен (PagerDuty, Slack)
  - [ ] Log aggregation (ELK, CloudWatch)

Backups:
  - [ ] Автоматические backups БД (ежедневно)
  - [ ] Backups files (еженедельно)
  - [ ] Backups хранятся offsite (S3)
  - [ ] Restore процедура протестирована

11. TROUBLESHOOTING

App не запускается:

# 1. Проверить логи
docker-compose logs app

# 2. Проверить переменные окружения
docker-compose exec app env | grep DATABASE

# 3. Проверить соединение с БД
docker-compose exec app python -c "from cifra.db import engine; print(engine.url)"

# 4. Проверить миграции
docker-compose exec app alembic current

Высокая нагрузка:

# 1. Проверить топ процессов
docker stats

# 2. Проверить медленные запросы
docker-compose exec db psql -U cifra -c "SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;"

# 3. Проверить Redis memory
docker-compose exec redis redis-cli info memory

# 4. Включить query logging (временно!)
# postgresql.conf: log_min_duration_statement = 1000 (>1 second)

12. ROLLBACK ПРОЦЕДУРА

#!/bin/bash
# rollback.sh

PREVIOUS_VERSION=$1

if [ -z "$PREVIOUS_VERSION" ]; then
  echo "Usage: ./rollback.sh <previous-version>"
  exit 1
fi

echo "Rolling back to version: $PREVIOUS_VERSION"

# 1. Deploy previous version
docker-compose pull cifra/platform:$PREVIOUS_VERSION
docker-compose up -d

# 2. Rollback database migration (if needed)
read -p "Rollback database? (y/n) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
  docker-compose exec app alembic downgrade -1
fi

# 3. Verify
curl -f https://app.cifra.io/health

echo "Rollback complete!"

Версия: 1.0
Дата: 2025-11-10
Статус: Production Ready ✅