Files
Alexander Abakumov 15e744da49 Initial commit: Complete Software Architecture course with 11 modules
- Added comprehensive course structure with 11 modules
- Included theoretical content, practical examples, and tasks
- Multi-language code examples (Java, Rust, Node.js, Python)
- Detailed analysis of architectural approaches and trade-offs
- Complete caching strategies documentation
- Architecture examples from real-world systems (Twitter, Netflix, Uber)
- Structured navigation and learning path
- Ready for educational use
2025-09-09 22:08:07 +03:00

50 KiB
Raw Permalink Blame History

Модуль 3: Контейнеризация и оркестрация

Содержание модуля

  1. Основы контейнеризации
  2. Docker
  3. Kubernetes
  4. Infrastructure as Code
  5. CI/CD с контейнерами
  6. Мониторинг контейнеров

Основы контейнеризации

Что такое контейнеризация

Контейнеризация — это технология упаковки приложений и их зависимостей в легковесные, переносимые контейнеры.

Преимущества контейнеризации

1. Портабельность

  • Одинаковая среда на всех платформах
  • "Работает на моей машине" больше не проблема
  • Легкая миграция между средами

2. Изоляция

  • Приложения изолированы друг от друга
  • Контроль ресурсов
  • Безопасность

3. Масштабируемость

  • Быстрое создание и удаление контейнеров
  • Горизонтальное масштабирование
  • Эффективное использование ресурсов

4. Консистентность

  • Одинаковая среда разработки, тестирования и продакшена
  • Предсказуемое поведение
  • Упрощение развертывания

Контейнеры vs Виртуальные машины

Аспект Контейнеры Виртуальные машины
Изоляция Процессная Аппаратная
Размер МБ ГБ
Запуск Секунды Минуты
Ресурсы Общие Выделенные
Безопасность Процессная Аппаратная

Компоненты контейнеризации

1. Container Runtime

  • containerd — стандартный runtime
  • runc — низкоуровневый runtime
  • CRI-O — Kubernetes-специфичный runtime

2. Container Image

  • Неизменяемый образ приложения
  • Слоистая структура
  • Версионирование

3. Container Registry

  • Хранение образов
  • Версионирование
  • Безопасность

Docker

Основы Docker

Docker — платформа для разработки, доставки и запуска приложений в контейнерах.

Архитектура Docker

┌─────────────────────────────────────┐
│           Docker Client             │
├─────────────────────────────────────┤
│           Docker Daemon             │
│  ┌─────────────┐ ┌─────────────────┐ │
│  │   Images    │ │   Containers    │ │
│  └─────────────┘ └─────────────────┘ │
├─────────────────────────────────────┤
│           Container Runtime          │
└─────────────────────────────────────┘

Dockerfile

Dockerfile — текстовый файл с инструкциями для создания образа.

Технический пример - Dockerfile для Spring Boot приложения:

# Многоэтапная сборка для оптимизации размера образа
# Этап 1: Сборка приложения
FROM maven:3.8.6-openjdk-17-slim AS build

# Установка рабочей директории
WORKDIR /app

# Копирование файлов pom.xml для кэширования зависимостей
COPY pom.xml .
COPY src ./src

# Сборка приложения
RUN mvn clean package -DskipTests

# Этап 2: Создание финального образа
FROM openjdk:17-jre-slim

# Установка рабочей директории
WORKDIR /app

# Создание пользователя для безопасности
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Копирование собранного JAR файла
COPY --from=build /app/target/*.jar app.jar

# Изменение владельца файлов
RUN chown -R appuser:appuser /app
USER appuser

# Открытие порта
EXPOSE 8080

# Переменные окружения
ENV JAVA_OPTS="-Xmx512m -Xms256m"
ENV SPRING_PROFILES_ACTIVE=production

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/actuator/health || exit 1

# Запуск приложения
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Dockerfile для микросервиса на Node.js:

# Базовый образ Node.js
FROM node:18-alpine AS base

# Установка рабочей директории
WORKDIR /app

# Установка системных зависимостей
RUN apk add --no-cache \
    dumb-init \
    curl

# Создание пользователя для безопасности
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001

# Этап установки зависимостей
FROM base AS deps
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Этап сборки
FROM base AS builder
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Финальный этап
FROM base AS runner
ENV NODE_ENV=production

# Копирование зависимостей
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public

# Копирование конфигурационных файлов
COPY --from=builder /app/package.json ./package.json

# Изменение владельца файлов
RUN chown -R nextjs:nodejs /app
USER nextjs

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

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

# Запуск приложения
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]

Дополнительные Node.js Dockerfile примеры:

Dockerfile для Express.js микросервиса с TypeScript:

# Многоэтапная сборка для TypeScript приложения
# Этап 1: Сборка приложения
FROM node:18-alpine AS build

WORKDIR /app

# Копирование package.json и package-lock.json
COPY package*.json ./
COPY tsconfig.json ./

# Установка всех зависимостей (включая dev)
RUN npm ci

# Копирование исходного кода
COPY src ./src

# Компиляция TypeScript
RUN npm run build

# Этап 2: Продакшн образ
FROM node:18-alpine AS production

WORKDIR /app

# Копирование package.json для установки только продакшн зависимостей
COPY package*.json ./

# Установка только продакшн зависимостей
RUN npm ci --only=production && npm cache clean --force

# Копирование собранного приложения
COPY --from=build /app/dist ./dist

# Создание пользователя для безопасности
RUN addgroup -g 1001 -S nodejs && \
    adduser -S express -u 1001

# Изменение владельца файлов
RUN chown -R express:nodejs /app
USER express

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

# Переменные окружения
ENV NODE_ENV=production
ENV PORT=3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

# Запуск приложения
CMD ["node", "dist/index.js"]

Dockerfile для NestJS микросервиса:

# Многоэтапная сборка для NestJS приложения
FROM node:18-alpine AS build

WORKDIR /app

# Копирование файлов конфигурации
COPY package*.json ./
COPY tsconfig*.json ./
COPY nest-cli.json ./

# Установка зависимостей
RUN npm ci

# Копирование исходного кода
COPY src ./src

# Сборка приложения
RUN npm run build

# Продакшн образ
FROM node:18-alpine AS production

WORKDIR /app

# Копирование package.json
COPY package*.json ./

# Установка только продакшн зависимостей
RUN npm ci --only=production && npm cache clean --force

# Копирование собранного приложения
COPY --from=build /app/dist ./dist

# Создание пользователя
RUN addgroup -g 1001 -S nestjs && \
    adduser -S nestjs -u 1001

# Изменение владельца
RUN chown -R nestjs:nestjs /app
USER nestjs

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

# Переменные окружения
ENV NODE_ENV=production
ENV PORT=3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

# Запуск приложения
CMD ["node", "dist/main.js"]

Dockerfile для Fastify микросервиса:

# Оптимизированный Dockerfile для Fastify
FROM node:18-alpine AS base

# Установка необходимых пакетов
RUN apk add --no-cache dumb-init

WORKDIR /app

# Копирование package.json
COPY package*.json ./

# Установка зависимостей
RUN npm ci --only=production && npm cache clean --force

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

# Создание пользователя
RUN addgroup -g 1001 -S fastify && \
    adduser -S fastify -u 1001

# Изменение владельца
RUN chown -R fastify:fastify /app
USER fastify

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

# Переменные окружения
ENV NODE_ENV=production
ENV PORT=3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

# Использование dumb-init для правильной обработки сигналов
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "server.js"]

Docker Compose для микросервисной архитектуры:

version: '3.8'

services:
  # API Gateway
  api-gateway:
    build: 
      context: ./api-gateway
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka:8761/eureka/
    depends_on:
      - eureka
      - user-service
      - order-service
      - payment-service
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Service Discovery
  eureka:
    image: steeltoeoss/eureka-server:latest
    ports:
      - "8761:8761"
    environment:
      - EUREKA_CLIENT_REGISTER_WITH_EUREKA=false
      - EUREKA_CLIENT_FETCH_REGISTRY=false
    networks:
      - microservices-network

  # User Service
  user-service:
    build:
      context: ./user-service
      dockerfile: Dockerfile
    ports:
      - "8081:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - SPRING_DATASOURCE_URL=jdbc:postgresql://user-db:5432/userdb
      - SPRING_DATASOURCE_USERNAME=user
      - SPRING_DATASOURCE_PASSWORD=password
      - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka:8761/eureka/
    depends_on:
      - user-db
      - eureka
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Order Service
  order-service:
    build:
      context: ./order-service
      dockerfile: Dockerfile
    ports:
      - "8082:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - SPRING_DATASOURCE_URL=jdbc:postgresql://order-db:5432/orderdb
      - SPRING_DATASOURCE_USERNAME=order
      - SPRING_DATASOURCE_PASSWORD=password
      - USER_SERVICE_URL=http://user-service:8080
      - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka:8761/eureka/
    depends_on:
      - order-db
      - user-service
      - eureka
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Payment Service
  payment-service:
    build:
      context: ./payment-service
      dockerfile: Dockerfile
    ports:
      - "8083:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - SPRING_DATASOURCE_URL=jdbc:postgresql://payment-db:5432/paymentdb
      - SPRING_DATASOURCE_USERNAME=payment
      - SPRING_DATASOURCE_PASSWORD=password
      - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka:8761/eureka/
    depends_on:
      - payment-db
      - eureka
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Databases
  user-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=userdb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - user_data:/var/lib/postgresql/data
      - ./init-scripts/user-db-init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d userdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  order-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=orderdb
      - POSTGRES_USER=order
      - POSTGRES_PASSWORD=password
    volumes:
      - order_data:/var/lib/postgresql/data
      - ./init-scripts/order-db-init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U order -d orderdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  payment-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=paymentdb
      - POSTGRES_USER=payment
      - POSTGRES_PASSWORD=password
    volumes:
      - payment_data:/var/lib/postgresql/data
      - ./init-scripts/payment-db-init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U payment -d paymentdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Message Queue
  rabbitmq:
    image: rabbitmq:3.11-management-alpine
    ports:
      - "5672:5672"
      - "15672:15672"
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Monitoring
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=200h'
      - '--web.enable-lifecycle'
    networks:
      - microservices-network

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
      - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
      - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources
    networks:
      - microservices-network

volumes:
  user_data:
  order_data:
  payment_data:
  rabbitmq_data:
  prometheus_data:
  grafana_data:

networks:
  microservices-network:
    driver: bridge

Docker Compose для Node.js микросервисной архитектуры:

version: '3.8'

services:
  # API Gateway (Express.js)
  api-gateway:
    build: 
      context: ./api-gateway
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - PORT=3000
      - USER_SERVICE_URL=http://user-service:3001
      - ORDER_SERVICE_URL=http://order-service:3002
      - PAYMENT_SERVICE_URL=http://payment-service:3003
    depends_on:
      - user-service
      - order-service
      - payment-service
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # User Service (Express.js + TypeScript)
  user-service:
    build:
      context: ./user-service
      dockerfile: Dockerfile
    ports:
      - "3001:3001"
    environment:
      - NODE_ENV=production
      - PORT=3001
      - DATABASE_URL=postgresql://user:password@user-db:5432/userdb
      - REDIS_URL=redis://redis:6379
    depends_on:
      - user-db
      - redis
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Order Service (NestJS)
  order-service:
    build:
      context: ./order-service
      dockerfile: Dockerfile
    ports:
      - "3002:3002"
    environment:
      - NODE_ENV=production
      - PORT=3002
      - DATABASE_URL=postgresql://order:password@order-db:5432/orderdb
      - PAYMENT_SERVICE_URL=http://payment-service:3003
      - RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672
    depends_on:
      - order-db
      - rabbitmq
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3002/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Payment Service (Fastify)
  payment-service:
    build:
      context: ./payment-service
      dockerfile: Dockerfile
    ports:
      - "3003:3003"
    environment:
      - NODE_ENV=production
      - PORT=3003
      - DATABASE_URL=postgresql://payment:password@payment-db:5432/paymentdb
      - PAYMENT_GATEWAY_URL=https://api.payment-gateway.com
      - PAYMENT_GATEWAY_KEY=${PAYMENT_GATEWAY_KEY}
    depends_on:
      - payment-db
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3003/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Databases
  user-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=userdb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - user_data:/var/lib/postgresql/data
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d userdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  order-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=orderdb
      - POSTGRES_USER=order
      - POSTGRES_PASSWORD=password
    volumes:
      - order_data:/var/lib/postgresql/data
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U order -d orderdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  payment-db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=paymentdb
      - POSTGRES_USER=payment
      - POSTGRES_PASSWORD=password
    volumes:
      - payment_data:/var/lib/postgresql/data
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U payment -d paymentdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis for caching
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # RabbitMQ for messaging
  rabbitmq:
    image: rabbitmq:3-management-alpine
    ports:
      - "5672:5672"
      - "15672:15672"
    environment:
      - RABBITMQ_DEFAULT_USER=guest
      - RABBITMQ_DEFAULT_PASS=guest
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
    networks:
      - microservices-network
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Monitoring
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
    networks:
      - microservices-network

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    networks:
      - microservices-network

volumes:
  user_data:
  order_data:
  payment_data:
  redis_data:
  rabbitmq_data:
  grafana_data:

networks:
  microservices-network:
    driver: bridge

Docker команды для управления контейнерами:

# Сборка образа
docker build -t user-service:latest ./user-service

# Запуск контейнера
docker run -d --name user-service -p 8081:8080 \
  -e SPRING_DATASOURCE_URL=jdbc:postgresql://host.docker.internal:5432/userdb \
  user-service:latest

# Просмотр логов
docker logs -f user-service

# Выполнение команд в контейнере
docker exec -it user-service bash

# Мониторинг ресурсов
docker stats user-service

# Остановка и удаление
docker stop user-service
docker rm user-service

# Очистка неиспользуемых образов
docker system prune -a

# Запуск с Docker Compose
docker-compose up -d
docker-compose down
docker-compose logs -f user-service

Копирование файлов зависимостей

COPY package*.json ./

Установка зависимостей

RUN npm ci --only=production

Копирование исходного кода

COPY . .

Открытие порта

EXPOSE 3000

Команда запуска

CMD ["npm", "start"]


### Команды Docker

#### Основные команды:
```bash
# Сборка образа
docker build -t myapp:latest .

# Запуск контейнера
docker run -p 3000:3000 myapp:latest

# Просмотр запущенных контейнеров
docker ps

# Просмотр всех контейнеров
docker ps -a

# Остановка контейнера
docker stop <container_id>

# Удаление контейнера
docker rm <container_id>

# Просмотр образов
docker images

# Удаление образа
docker rmi <image_id>

Продвинутые команды:

# Запуск в фоновом режиме
docker run -d -p 3000:3000 myapp:latest

# Подключение к контейнеру
docker exec -it <container_id> /bin/bash

# Просмотр логов
docker logs <container_id>

# Мониторинг ресурсов
docker stats <container_id>

Docker Compose

Docker Compose — инструмент для определения и запуска многоконтейнерных приложений.

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
      - redis

  db:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:6-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Лучшие практики Docker

1. Оптимизация размера образа

# Используйте многоэтапную сборку
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
CMD ["npm", "start"]

2. Безопасность

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

3. Кэширование слоев

# Копируйте package.json перед исходным кодом
COPY package*.json ./
RUN npm ci
COPY . .

4. Health Checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

Kubernetes

Что такое Kubernetes

Kubernetes (K8s) — система оркестрации контейнеров для автоматизации развертывания, масштабирования и управления приложениями.

Архитектура Kubernetes

┌─────────────────────────────────────────────────────────┐
│                    Control Plane                        │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐   │
│  │ API Server  │ │ Scheduler   │ │ Controller Mgr  │   │
│  └─────────────┘ └─────────────┘ └─────────────────┘   │
│  ┌─────────────┐ ┌─────────────┐                       │
│  │ etcd        │ │ Cloud Ctlr   │                       │
│  └─────────────┘ └─────────────┘                       │
└─────────────────────────────────────────────────────────┘
                              │
┌─────────────────────────────────────────────────────────┐
│                    Worker Nodes                         │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐   │
│  │ kubelet     │ │ kube-proxy  │ │ Container Runtime│   │
│  └─────────────┘ └─────────────┘ └─────────────────┘   │
└─────────────────────────────────────────────────────────┘

Основные компоненты

Плоскость управления:

  • API Server — центральный компонент управления
  • etcd — хранилище конфигурации
  • Scheduler — планировщик подов
  • Controller Manager — контроллеры системы

Рабочие узлы:

  • kubelet — агент на каждом узле
  • kube-proxy — сетевой прокси
  • Container Runtime — Docker, containerd, CRI-O

Объекты Kubernetes

1. Pod

Pod — наименьшая единица развертывания в Kubernetes.

Технический пример - Pod для микросервиса:

apiVersion: v1
kind: Pod
metadata:
  name: user-service-pod
  labels:
    app: user-service
    version: v1.0.0
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/actuator/prometheus"
spec:
  containers:
  - name: user-service
    image: user-service:latest
    ports:
    - containerPort: 8080
      name: http
      protocol: TCP
    env:
    - name: SPRING_PROFILES_ACTIVE
      value: "kubernetes"
    - name: SPRING_DATASOURCE_URL
      valueFrom:
        secretKeyRef:
          name: user-db-secret
          key: url
    - name: SPRING_DATASOURCE_USERNAME
      valueFrom:
        secretKeyRef:
          name: user-db-secret
          key: username
    - name: SPRING_DATASOURCE_PASSWORD
      valueFrom:
        secretKeyRef:
          name: user-db-secret
          key: password
    resources:
      requests:
        memory: "256Mi"
        cpu: "250m"
      limits:
        memory: "512Mi"
        cpu: "500m"
    livenessProbe:
      httpGet:
        path: /actuator/health/liveness
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
      timeoutSeconds: 5
      failureThreshold: 3
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 3
      failureThreshold: 3
    volumeMounts:
    - name: config-volume
      mountPath: /app/config
      readOnly: true
  volumes:
  - name: config-volume
    configMap:
      name: user-service-config
  restartPolicy: Always
  terminationGracePeriodSeconds: 30

2. Deployment

Deployment — управляет репликами подов.

Технический пример - Deployment для микросервиса:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-deployment
  labels:
    app: user-service
    version: v1.0.0
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
        prometheus.io/path: "/actuator/prometheus"
    spec:
      containers:
      - name: user-service
        image: user-service:v1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "kubernetes"
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: SPRING_DATASOURCE_URL
          valueFrom:
            secretKeyRef:
              name: user-db-secret
              key: url
        - name: SPRING_DATASOURCE_USERNAME
          valueFrom:
            secretKeyRef:
              name: user-db-secret
              key: username
        - name: SPRING_DATASOURCE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: user-db-secret
              key: password
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
          readOnly: true
        - name: logs-volume
          mountPath: /app/logs
      volumes:
      - name: config-volume
        configMap:
          name: user-service-config
      - name: logs-volume
        emptyDir: {}
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 2000

HorizontalPodAutoscaler для автоматического масштабирования:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-service-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60

3. Service

Service — обеспечивает сетевой доступ к подам.

Технический пример - Service для микросервиса:

apiVersion: v1
kind: Service
metadata:
  name: user-service
  labels:
    app: user-service
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/actuator/prometheus"
spec:
  selector:
    app: user-service
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  - name: metrics
    protocol: TCP
    port: 9090
    targetPort: 9090
  type: ClusterIP
  sessionAffinity: None

Ingress для внешнего доступа:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: microservices-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - api.example.com
    secretName: api-tls-secret
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /api/users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80
      - path: /api/orders
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 80
      - path: /api/payments
        pathType: Prefix
        backend:
          service:
            name: payment-service
            port:
              number: 80

ConfigMap для конфигурации:

apiVersion: v1
kind: ConfigMap
metadata:
  name: user-service-config
  labels:
    app: user-service
data:
  application.yml: |
    server:
      port: 8080
    spring:
      application:
        name: user-service
      datasource:
        driver-class-name: org.postgresql.Driver
        hikari:
          maximum-pool-size: 10
          minimum-idle: 5
          connection-timeout: 20000
          idle-timeout: 300000
          max-lifetime: 1200000
      jpa:
        hibernate:
          ddl-auto: validate
        show-sql: false
        properties:
          hibernate:
            dialect: org.hibernate.dialect.PostgreSQLDialect
            format_sql: true
      rabbitmq:
        host: rabbitmq-service
        port: 5672
        username: admin
        password: admin
    management:
      endpoints:
        web:
          exposure:
            include: health,info,prometheus,metrics
      endpoint:
        health:
          show-details: always
      metrics:
        export:
          prometheus:
            enabled: true
  logback-spring.xml: |
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
        <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
        
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>/app/logs/user-service.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>/app/logs/user-service.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
                <maxFileSize>100MB</maxFileSize>
                <maxHistory>30</maxHistory>
                <totalSizeCap>3GB</totalSizeCap>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </encoder>
        </appender>
        
        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
            <appender-ref ref="FILE"/>
        </root>
    </configuration>

Secret для чувствительных данных:

apiVersion: v1
kind: Secret
metadata:
  name: user-db-secret
  labels:
    app: user-service
type: Opaque
data:
  url: cG9zdGdyZXNxbDovL3VzZXItZGItc2VydmljZToyNTQzMi91c2VyZGI=  # base64 encoded
  username: dXNlcg==  # base64 encoded
  password: cGFzc3dvcmQ=  # base64 encoded

PersistentVolumeClaim для базы данных:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: user-db-pvc
  labels:
    app: user-db
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: fast-ssd

StatefulSet для базы данных:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: user-db
  labels:
    app: user-db
spec:
  serviceName: user-db
  replicas: 1
  selector:
    matchLabels:
      app: user-db
  template:
    metadata:
      labels:
        app: user-db
    spec:
      containers:
      - name: postgres
        image: postgres:15-alpine
        ports:
        - containerPort: 5432
          name: postgres
        env:
        - name: POSTGRES_DB
          value: userdb
        - name: POSTGRES_USER
          valueFrom:
            secretKeyRef:
              name: user-db-secret
              key: username
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: user-db-secret
              key: password
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - user
            - -d
            - userdb
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command:
            - pg_isready
            - -U
            - user
            - -d
            - userdb
          initialDelaySeconds: 5
          periodSeconds: 5
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
      storageClassName: fast-ssd

4. ConfigMap

ConfigMap — хранит конфигурационные данные.

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  database_url: "postgresql://localhost:5432/mydb"
  api_key: "secret-key"

5. Secret

Secret — хранит чувствительные данные.

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: YWRtaW4=
  password: cGFzc3dvcmQ=

Команды Kubernetes

Основные команды:

# Применение манифеста
kubectl apply -f deployment.yaml

# Просмотр подов
kubectl get pods

# Просмотр сервисов
kubectl get services

# Просмотр деплойментов
kubectl get deployments

# Описание ресурса
kubectl describe pod <pod-name>

# Логи пода
kubectl logs <pod-name>

# Подключение к поду
kubectl exec -it <pod-name> -- /bin/bash

# Масштабирование деплоймента
kubectl scale deployment my-deployment --replicas=5

Сетевая модель Kubernetes

1. Cluster Networking

  • Каждый под имеет уникальный IP
  • Поды могут общаться друг с другом
  • Сервисы обеспечивают стабильные IP

2. Service Types

  • ClusterIP — внутренний IP кластера
  • NodePort — доступ через порт узла
  • LoadBalancer — внешний балансировщик нагрузки
  • ExternalName — внешний DNS

3. Ingress

Ingress — управляет внешним доступом к сервисам.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-service
            port:
              number: 80

Хранилище в Kubernetes

1. Volumes

apiVersion: v1
kind: Pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: my-volume
      mountPath: /data
  volumes:
  - name: my-volume
    persistentVolumeClaim:
      claimName: my-pvc

2. PersistentVolume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: fast-ssd

3. PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: fast-ssd

Infrastructure as Code

Что такое IaC

Infrastructure as Code (IaC) — подход к управлению инфраструктурой через код.

Преимущества IaC

1. Версионирование

  • История изменений инфраструктуры
  • Откат к предыдущим версиям
  • Code review для инфраструктуры

2. Повторяемость

  • Одинаковая инфраструктура в разных средах
  • Автоматизация развертывания
  • Устранение дрейфа конфигурации

3. Документация

  • Код как документация
  • Понятная структура инфраструктуры
  • Автоматическая генерация диаграмм

Terraform

Terraform — инструмент для управления инфраструктурой через код.

Основные концепции:

1. Provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}
2. Resource
resource "aws_instance" "web" {
  ami           = "ami-0c02fb55956c7d316"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
  }
}
3. Data Source
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"]

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
}
4. Variables
variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}

variable "environment" {
  description = "Environment name"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}
5. Outputs
output "instance_ip" {
  description = "Public IP of the instance"
  value       = aws_instance.web.public_ip
}

Команды Terraform

# Инициализация
terraform init

# Планирование изменений
terraform plan

# Применение изменений
terraform apply

# Уничтожение инфраструктуры
terraform destroy

# Просмотр состояния
terraform show

# Форматирование кода
terraform fmt

# Валидация конфигурации
terraform validate

Модули Terraform

# main.tf
module "vpc" {
  source = "./modules/vpc"
  
  environment = var.environment
  cidr_block  = "10.0.0.0/16"
}

module "ec2" {
  source = "./modules/ec2"
  
  vpc_id = module.vpc.vpc_id
  subnet_id = module.vpc.public_subnet_id
}

Ansible

Ansible — инструмент автоматизации конфигурации и развертывания.

Пример Playbook:

---
- name: Deploy web application
  hosts: web_servers
  become: yes
  vars:
    app_name: myapp
    app_port: 3000
  
  tasks:
    - name: Install Node.js
      package:
        name: nodejs
        state: present
    
    - name: Install npm dependencies
      npm:
        path: /opt/{{ app_name }}
        state: present
    
    - name: Start application
      systemd:
        name: "{{ app_name }}"
        state: started
        enabled: yes

CI/CD с контейнерами

CI/CD Pipeline

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

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Build Docker image
      run: docker build -t ${{ secrets.REGISTRY }}/myapp:${{ github.sha }} .
    
    - name: Push to registry
      run: docker push ${{ secrets.REGISTRY }}/myapp:${{ github.sha }}
    
    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/myapp myapp=${{ secrets.REGISTRY }}/myapp:${{ github.sha }}
        kubectl rollout status deployment/myapp

GitOps

GitOps — подход к управлению инфраструктурой через Git.

Пример ArgoCD:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/myapp
    targetRevision: HEAD
    path: k8s
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Мониторинг контейнеров

Prometheus + Grafana

Конфигурация Prometheus:

# prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
    - role: pod

Дашборд Grafana:

{
  "dashboard": {
    "title": "Kubernetes Cluster",
    "panels": [
      {
        "title": "CPU Usage",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(container_cpu_usage_seconds_total[5m])"
          }
        ]
      }
    ]
  }
}

ELK Stack

Elasticsearch + Logstash + Kibana:

# docker-compose.yml
version: '3.8'
services:
  elasticsearch:
    image: elasticsearch:7.14.0
    environment:
      - discovery.type=single-node
    ports:
      - "9200:9200"

  logstash:
    image: logstash:7.14.0
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    ports:
      - "5044:5044"

  kibana:
    image: kibana:7.14.0
    ports:
      - "5601:5601"

Практические задания

Задание 1: Docker

  1. Создайте Dockerfile для Node.js приложения
  2. Соберите образ и запустите контейнер
  3. Создайте docker-compose.yml для многоконтейнерного приложения

Задание 2: Kubernetes

  1. Создайте Deployment для веб-приложения
  2. Создайте Service для доступа к приложению
  3. Настройте ConfigMap и Secret
  4. Разверните приложение в кластере

Задание 3: Terraform

  1. Создайте инфраструктуру в AWS с помощью Terraform
  2. Используйте модули для организации кода
  3. Настройте переменные и outputs

Дополнительные ресурсы

Документация

Книги

  • "Kubernetes in Action" by Marko Lukša
  • "Terraform: Up & Running" by Yevgeniy Brikman

Контрольные вопросы

  1. Что такое контейнеризация и каковы её преимущества?
  2. Как работает Docker и какие основные команды вы знаете?
  3. Что такое Kubernetes и какова его архитектура?
  4. Какие основные объекты Kubernetes вы знаете?
  5. Что такое Infrastructure as Code и зачем это нужно?
  6. Как настроить CI/CD для контейнеризованных приложений?
  7. Как мониторить контейнеры и кластеры?
  8. Какие best practices для Docker и Kubernetes?