Глава 21. Production Deployment
"Локально работает — это только начало пути."
21.1. От ноутбука до облака
Три уровня зрелости
Уровень 1: Ноутбук
python app.py
# Работает только у вас
Уровень 2: Сервер
ssh user@server
python app.py &
# Работает пока сервер не перезагрузится
Уровень 3: Production
docker build → k8s deploy → auto-scale → monitoring
# Работает 24/7, масштабируется, самовосстанавливается
21.2. Docker — упаковка приложения
Зачем Docker
Проблема: "У меня работает"
Developer: "У меня на Python 3.11 работает"
Server: *Python 3.8* — ошибка!
Решение: Docker
- Упаковываем приложение + зависимости + окружение
- Работает одинаково везде
Dockerfile для AI-приложения
# Базовый образ
FROM python:3.11-slim
# Рабочая директория
WORKDIR /app
# Копируем зависимости
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копируем код
COPY . .
# Порт
EXPOSE 8000
# Запуск
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
requirements.txt
fastapi==0.104.1
uvicorn==0.24.0
openai==1.3.0
langchain==0.0.350
pydantic==2.5.0
python-dotenv==1.0.0
Сборка и запуск
# Сборка образа
docker build -t my-ai-app .
# Запуск контейнера
docker run -d \
-p 8000:8000 \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
--name ai-app \
my-ai-app
# Проверка
curl http://localhost:8000/health
Docker Compose для нескольких сервисов
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8000:8000"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- DATABASE_URL=postgresql://user:pass@db:5432/myapp
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
Запуск:
docker-compose up -d
21.3. Kubernetes — оркестрация в масштабе
Когда нужен Kubernetes
Docker достаточно если:
- 1 сервер
- Низкая нагрузка
- Простое приложение
Kubernetes нужен если:
- Много серверов
- Auto-scaling
- High availability (99.9%+)
- Микросервисы
Основные концепции K8s
Pod — наименьшая единица (1+ контейнеров) Deployment — управление репликами Pods Service — сетевой доступ к Pods Ingress — HTTP маршрутизация
Deployment manifest
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-app
spec:
replicas: 3 # 3 копии приложения
selector:
matchLabels:
app: ai-app
template:
metadata:
labels:
app: ai-app
spec:
containers:
- name: ai-app
image: my-ai-app:latest
ports:
- containerPort: 8000
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: api-keys
key: openai
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
Service для доступа
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: ai-app-service
spec:
selector:
app: ai-app
ports:
- port: 80
targetPort: 8000
type: LoadBalancer
Применение
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Проверка
kubectl get pods
kubectl get services
Auto-scaling
# hpa.yaml (Horizontal Pod Autoscaler)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Автоматически масштабирует от 2 до 10 pods в зависимости от CPU.
21.4. Cloud Providers
AWS vs GCP vs Azure
| Сервис | AWS | GCP | Azure |
|---|---|---|---|
| Compute | EC2 | Compute Engine | Virtual Machines |
| Containers | ECS/EKS | GKE | AKS |
| Serverless | Lambda | Cloud Functions | Functions |
| Storage | S3 | Cloud Storage | Blob Storage |
| Database | RDS | Cloud SQL | SQL Database |
| AI Services | SageMaker | Vertex AI | Azure AI |
AWS Lambda для AI (Serverless)
Идея: Код запускается только при запросе. Оплата за выполнение.
# lambda_function.py
import json
import openai
import os
openai.api_key = os.environ['OPENAI_API_KEY']
def lambda_handler(event, context):
"""AWS Lambda handler"""
# Получаем запрос
body = json.loads(event['body'])
prompt = body.get('prompt', '')
# Вызываем OpenAI
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
# Возвращаем результат
return {
'statusCode': 200,
'body': json.dumps({
'response': response.choices[0].message.content
})
}
Деплой:
# Упаковать
zip function.zip lambda_function.py
# Загрузить в AWS Lambda
aws lambda create-function \
--function-name ai-function \
--runtime python3.11 \
--handler lambda_function.lambda_handler \
--zip-file fileb://function.zip
Преимущества:
- Не нужно управлять серверами
- Автоматическое масштабирование
- Оплата только за использование
Недостатки:
- Cold start (первый запрос медленнее)
- Лимиты на время выполнения (15 минут AWS)
GCP Cloud Run (Container-based serverless)
# Деплой Docker образа
gcloud run deploy ai-app \
--image gcr.io/my-project/ai-app \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars OPENAI_API_KEY=$OPENAI_API_KEY
Получаете URL: https://ai-app-xxx.run.app
Автоматически масштабируется от 0 до 1000+ экземпляров.
21.5. CI/CD для AI-приложений
Что такое CI/CD
CI (Continuous Integration):
- Автоматические тесты при каждом commit
- Сборка Docker образа
- Проверка качества кода
CD (Continuous Deployment):
- Автоматический деплой при успешных тестах
- Rolling updates (постепенное обновление)
- Rollback при ошибках
GitHub Actions pipeline
# .github/workflows/deploy.yml
name: Deploy AI App
on:
push:
branches: [main]
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
- name: Run tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: pytest tests/
build-and-push:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t my-ai-app:${{ github.sha }} .
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker tag my-ai-app:${{ github.sha }} username/my-ai-app:latest
docker push username/my-ai-app:latest
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/ai-app ai-app=username/my-ai-app:latest
Что происходит:
- Push в main → запускаются тесты
- Тесты прошли → сборка Docker образа
- Образ загружен → деплой в K8s
- Всё автоматически!
21.6. Стратегии деплоя
Rolling Update (по умолчанию в K8s)
Old version: [Pod1] [Pod2] [Pod3]
[Pod1] [Pod2] [New1] ← Заменяем по одному
[Pod1] [New1] [New2]
[New1] [New2] [New3] ← Все обновлены
Преимущества: Нет downtime Недостатки: Два версии работают одновременно
Blue-Green Deployment
Blue (old): [Pod1] [Pod2] [Pod3] ← Пользователи здесь
Green (new): [Pod4] [Pod5] [Pod6] ← Запущено параллельно
Switch traffic → Green
Blue (old): [Pod1] [Pod2] [Pod3] ← Можно удалить
Green (new): [Pod4] [Pod5] [Pod6] ← Теперь пользователи здесь
Преимущества: Быстрый rollback Недостатки: 2x ресурсов на момент деплоя
Canary Deployment
Old: [Pod1] [Pod2] [Pod3] ← 90% трафика
New: [Pod4] ← 10% трафика (тест)
Если OK:
Old: [Pod1] [Pod2] ← 50% трафика
New: [Pod3] [Pod4] ← 50% трафика
Если OK:
New: [Pod1] [Pod2] [Pod3] [Pod4] ← 100% трафика
Преимущества: Постепенное тестирование на реальных пользователях Недостатки: Сложнее настроить
21.7. Environment management
Development → Staging → Production
Development (dev):
- Ваш ноутбук
- Быстрые итерации
- Можно ломать
Staging (stage):
- Копия production
- Тестирование перед релизом
- Интеграционные тесты
Production (prod):
- Реальные пользователи
- Высокая доступность
- Нельзя ломать!
Управление конфигурацией
# config.py
import os
from enum import Enum
class Environment(Enum):
DEVELOPMENT = "dev"
STAGING = "stage"
PRODUCTION = "prod"
class Config:
ENV = os.getenv("ENV", "dev")
# Общие настройки
APP_NAME = "AI App"
# Специфичные для окружения
if ENV == Environment.DEVELOPMENT.value:
DEBUG = True
DATABASE_URL = "sqlite:///dev.db"
OPENAI_MODEL = "gpt-3.5-turbo" # Дешевле для dev
LOG_LEVEL = "DEBUG"
elif ENV == Environment.STAGING.value:
DEBUG = True
DATABASE_URL = os.getenv("STAGING_DB_URL")
OPENAI_MODEL = "gpt-4"
LOG_LEVEL = "INFO"
else: # Production
DEBUG = False
DATABASE_URL = os.getenv("PROD_DB_URL")
OPENAI_MODEL = "gpt-4"
LOG_LEVEL = "WARNING"
SENTRY_DSN = os.getenv("SENTRY_DSN") # Error tracking
21.8. Secrets management
Никогда не коммитьте секреты!
Плохо:
OPENAI_API_KEY = "sk-abc123..." # В коде!
Хорошо:
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
Environment variables
.env файл (локально):
# .env
OPENAI_API_KEY=sk-abc123...
DATABASE_URL=postgresql://...
# В коде
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
ВАЖНО: Добавьте .env в .gitignore!
Kubernetes Secrets
# Создать secret
kubectl create secret generic api-keys \
--from-literal=openai=sk-abc123...
# Использовать в deployment
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: api-keys
key: openai
AWS Secrets Manager / GCP Secret Manager
from google.cloud import secretmanager
client = secretmanager.SecretManagerServiceClient()
name = "projects/my-project/secrets/openai-key/versions/latest"
response = client.access_secret_version(request={"name": name})
api_key = response.payload.data.decode("UTF-8")
Ключевые выводы главы
✅ Docker: Упаковывает приложение + зависимости
✅ Kubernetes: Оркестрация, auto-scaling, high availability
✅ Cloud: AWS/GCP/Azure для hosting, serverless для простоты
✅ CI/CD: Автоматические тесты и деплой (GitHub Actions)
✅ Deployment strategies: Rolling, Blue-Green, Canary
✅ Environments: dev → staging → production
✅ Secrets: НИКОГДА не коммитьте, используйте env vars или secret managers
✅ Infrastructure as Code: Описывайте инфраструктуру в файлах (YAML)
Следующая глава: Performance optimization — скорость и масштабирование