- 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
50 KiB
Модуль 3: Контейнеризация и оркестрация
Содержание модуля
- Основы контейнеризации
- Docker
- Kubernetes
- Infrastructure as Code
- CI/CD с контейнерами
- Мониторинг контейнеров
Основы контейнеризации
Что такое контейнеризация
Контейнеризация — это технология упаковки приложений и их зависимостей в легковесные, переносимые контейнеры.
Преимущества контейнеризации
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
- Создайте Dockerfile для Node.js приложения
- Соберите образ и запустите контейнер
- Создайте docker-compose.yml для многоконтейнерного приложения
Задание 2: Kubernetes
- Создайте Deployment для веб-приложения
- Создайте Service для доступа к приложению
- Настройте ConfigMap и Secret
- Разверните приложение в кластере
Задание 3: Terraform
- Создайте инфраструктуру в AWS с помощью Terraform
- Используйте модули для организации кода
- Настройте переменные и outputs
Дополнительные ресурсы
Документация
Книги
- "Kubernetes in Action" by Marko Lukša
- "Terraform: Up & Running" by Yevgeniy Brikman
Контрольные вопросы
- Что такое контейнеризация и каковы её преимущества?
- Как работает Docker и какие основные команды вы знаете?
- Что такое Kubernetes и какова его архитектура?
- Какие основные объекты Kubernetes вы знаете?
- Что такое Infrastructure as Code и зачем это нужно?
- Как настроить CI/CD для контейнеризованных приложений?
- Как мониторить контейнеры и кластеры?
- Какие best practices для Docker и Kubernetes?