МАТЕРИАЛЫ КУРСА
СИИ • НАВИГАЦИЯ

Docker - Практические примеры и case studies

Реальные примеры использования Docker в разработке - от простых веб-приложений до сложных микросервисных архитектур

~15 МИН ЧТЕНИЯ
ОБНОВЛЕНО НЕДАВНО

Docker - Практические примеры и case studies

Пример 1: Развертывание веб-приложения на Node.js

Архитектура приложения

Структура проекта

nodejs-docker-app/
├── package.json
├── server.js
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
└── public/
    └── index.html

Файлы приложения

package.json:

{
  "name": "nodejs-docker-app",
  "version": "1.0.0",
  "description": "Example Node.js app with Docker",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "redis": "^4.6.0",
    "pg": "^8.11.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.0"
  }
}

server.js:

const express = require('express');
const redis = require('redis');
const { Client } = require('pg');
const path = require('path');

const app = express();
const PORT = process.env.PORT || 3000;

// Подключение к Redis
const redisClient = redis.createClient({
  host: process.env.REDIS_HOST || 'localhost',
  port: process.env.REDIS_PORT || 6379
});

// Подключение к PostgreSQL
const pgClient = new Client({
  host: process.env.POSTGRES_HOST || 'localhost',
  port: process.env.POSTGRES_PORT || 5432,
  database: process.env.POSTGRES_DB || 'myapp',
  user: process.env.POSTGRES_USER || 'postgres',
  password: process.env.POSTGRES_PASSWORD || 'password'
});

app.use(express.static('public'));
app.use(express.json());

// Инициализация подключений
async function initConnections() {
  try {
    await redisClient.connect();
    await pgClient.connect();
    console.log('Connected to Redis and PostgreSQL');
  } catch (err) {
    console.error('Connection error:', err);
  }
}

// API endpoints
app.get('/api/health', (req, res) => {
  res.json({ status: 'healthy', timestamp: new Date().toISOString() });
});

app.get('/api/counter', async (req, res) => {
  try {
    const count = await redisClient.incr('page_views');
    res.json({ count });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.get('/api/users', async (req, res) => {
  try {
    const result = await pgClient.query('SELECT * FROM users LIMIT 10');
    res.json(result.rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
  initConnections();
});

Dockerfile:

# Используем официальный Node.js образ
FROM node:18-alpine

# Устанавливаем рабочую директорию
WORKDIR /app

# Копируем файлы зависимостей
COPY package*.json ./

# Устанавливаем зависимости
RUN npm ci --only=production

# Копируем исходный код
COPY . .

# Создаем пользователя без привилегий
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001

# Меняем владельца файлов
RUN chown -R nodejs:nodejs /app
USER nodejs

# Открываем порт
EXPOSE 3000

# Healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
  CMD node healthcheck.js

# Запускаем приложение
CMD ["npm", "start"]

docker-compose.yml:

version: '3.8'

services:
  # Node.js приложение
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - REDIS_HOST=redis
      - POSTGRES_HOST=database
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secure_password
    depends_on:
      - redis
      - database
    restart: unless-stopped
    networks:
      - app-network

  # Redis для кэширования
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    restart: unless-stopped
    networks:
      - app-network

  # PostgreSQL база данных
  database:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secure_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: unless-stopped
    networks:
      - app-network

  # Nginx прокси
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app
    restart: unless-stopped
    networks:
      - app-network

volumes:
  redis_data:
  postgres_data:

networks:
  app-network:
    driver: bridge

Пример 2: Микросервисная архитектура

Структура проекта

microservices-app/
├── docker-compose.yml
├── gateway/
│   ├── Dockerfile
│   └── nginx.conf
├── user-service/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── product-service/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── order-service/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
└── monitoring/
    ├── prometheus.yml
    └── grafana/

docker-compose.yml:

version: '3.8'

services:
  # API Gateway
  gateway:
    build: ./gateway
    ports:
      - "80:80"
    depends_on:
      - user-service
      - product-service
      - order-service
    networks:
      - frontend
      - backend

  # Сервис пользователей
  user-service:
    build: ./user-service
    environment:
      - DATABASE_URL=postgresql://postgres:password@user-db:5432/users
      - REDIS_URL=redis://redis:6379
    depends_on:
      - user-db
      - redis
    networks:
      - backend
    deploy:
      replicas: 2

  # База данных пользователей
  user-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=users
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - user_db_data:/var/lib/postgresql/data
    networks:
      - backend

  # Сервис продуктов
  product-service:
    build: ./product-service
    environment:
      - DATABASE_URL=postgresql://postgres:password@product-db:5432/products
    depends_on:
      - product-db
    networks:
      - backend
    deploy:
      replicas: 2

  # База данных продуктов
  product-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=products
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - product_db_data:/var/lib/postgresql/data
    networks:
      - backend

  # Сервис заказов
  order-service:
    build: ./order-service
    environment:
      - DATABASE_URL=postgresql://postgres:password@order-db:5432/orders
      - USER_SERVICE_URL=http://user-service:3000
      - PRODUCT_SERVICE_URL=http://product-service:3000
      - RABBITMQ_URL=amqp://rabbitmq:5672
    depends_on:
      - order-db
      - rabbitmq
    networks:
      - backend

  # База данных заказов
  order-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=orders
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - order_db_data:/var/lib/postgresql/data
    networks:
      - backend

  # Redis для кэширования
  redis:
    image: redis:7-alpine
    networks:
      - backend

  # RabbitMQ для очередей сообщений
  rabbitmq:
    image: rabbitmq:3-management
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=password
    ports:
      - "15672:15672"  # Management UI
    networks:
      - backend

  # Prometheus мониторинг
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - monitoring
      - backend

  # Grafana дашборды
  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - monitoring

volumes:
  user_db_data:
  product_db_data:
  order_db_data:
  grafana_data:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
  monitoring:
    driver: bridge

Пример 3: Полный стек с React и Python

Структура проекта

fullstack-app/
├── docker-compose.yml
├── frontend/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app/
├── database/
│   └── init/
└── nginx/
    └── nginx.conf

docker-compose.yml:

version: '3.8'

services:
  # React Frontend
  frontend:
    build:
      context: ./frontend
      target: production
    volumes:
      - frontend_build:/app/build
    networks:
      - frontend

  # Python Backend (FastAPI)
  backend:
    build: ./backend
    environment:
      - DATABASE_URL=postgresql://postgres:password@database:5432/app
      - REDIS_URL=redis://redis:6379
      - SECRET_KEY=your-secret-key-here
    depends_on:
      - database
      - redis
    networks:
      - backend
      - frontend

  # Nginx веб-сервер
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - frontend_build:/var/www/html
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    depends_on:
      - frontend
      - backend
    networks:
      - frontend

  # PostgreSQL база данных
  database:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./database/init:/docker-entrypoint-initdb.d
    networks:
      - backend

  # Redis
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    networks:
      - backend

  # Celery worker для фоновых задач
  celery:
    build: ./backend
    command: celery -A app.celery worker --loglevel=info
    environment:
      - DATABASE_URL=postgresql://postgres:password@database:5432/app
      - REDIS_URL=redis://redis:6379
    depends_on:
      - database
      - redis
    networks:
      - backend

  # Flower для мониторинга Celery
  flower:
    build: ./backend
    command: celery -A app.celery flower --port=5555
    ports:
      - "5555:5555"
    environment:
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
    networks:
      - backend

volumes:
  postgres_data:
  redis_data:
  frontend_build:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

Frontend Dockerfile (React):

# Этап разработки
FROM node:18-alpine AS development
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

# Этап сборки
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Продакшн этап
FROM nginx:alpine AS production
COPY --from=build /app/build /var/www/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Backend Dockerfile (FastAPI):

FROM python:3.11-slim

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

# Установка Python зависимостей
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

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

# Создание пользователя
RUN adduser --disabled-password --gecos '' appuser
RUN chown -R appuser:appuser /app
USER appuser

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

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Пример 4: CI/CD с Docker

GitHub Actions Workflow

.github/workflows/docker.yml:

name: Docker Build and Deploy

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Run tests
      run: |
        docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit
        docker-compose -f docker-compose.test.yml down

  build:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Log in to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=sha

    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Deploy to production
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.KEY }}
        script: |
          cd /opt/myapp
          docker-compose pull
          docker-compose up -d
          docker system prune -f

Docker Compose для тестирования

docker-compose.test.yml:

version: '3.8'

services:
  app:
    build:
      context: .
      target: test
    environment:
      - NODE_ENV=test
      - DATABASE_URL=postgresql://postgres:password@test-db:5432/test
    depends_on:
      - test-db
    command: npm test

  test-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=test
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    tmpfs:
      - /var/lib/postgresql/data

Пример 5: Масштабирование и Load Balancing

docker-compose.scale.yml:

version: '3.8'

services:
  # Load Balancer
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - app

  # Приложение (масштабируемое)
  app:
    build: .
    environment:
      - DATABASE_URL=postgresql://postgres:password@database:5432/app
      - REDIS_URL=redis://redis:6379
    depends_on:
      - database
      - redis

  # База данных
  database:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # Redis
  redis:
    image: redis:7-alpine

  # Мониторинг
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml

volumes:
  postgres_data:

Nginx конфигурация для балансировки:

upstream app_servers {
    server app_1:3000;
    server app_2:3000;
    server app_3:3000;
}

server {
    listen 80;
    
    location / {
        proxy_pass http://app_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # Health check
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    }
    
    location /health {
        access_log off;
        return 200 "healthy\n";
    }
}

Команды для масштабирования:

# Запуск с 3 репликами приложения
docker-compose -f docker-compose.scale.yml up --scale app=3

# Масштабирование во время работы
docker-compose -f docker-compose.scale.yml up --scale app=5 -d

# Автоматическое масштабирование с Docker Swarm
docker stack deploy -c docker-compose.scale.yml myapp

Заключение

Эти практические примеры демонстрируют:

  • Простые приложения - базовая контейнеризация
  • Микросервисы - сложные архитектуры с множеством сервисов
  • Полный стек - интеграция frontend, backend и базы данных
  • CI/CD - автоматизация сборки и развертывания
  • Масштабирование - управление нагрузкой и репликами

Каждый пример включает готовые к использованию конфигурации, которые можно адаптировать под ваши потребности.

ВСЕ МАТЕРИАЛЫ