- 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
2009 lines
50 KiB
Markdown
2009 lines
50 KiB
Markdown
# Модуль 3: Контейнеризация и оркестрация
|
||
|
||
## Содержание модуля
|
||
1. [Основы контейнеризации](#основы-контейнеризации)
|
||
2. [Docker](#docker)
|
||
3. [Kubernetes](#kubernetes)
|
||
4. [Infrastructure as Code](#infrastructure-as-code)
|
||
5. [CI/CD с контейнерами](#cicd-с-контейнерами)
|
||
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 приложения:**
|
||
|
||
```dockerfile
|
||
# Многоэтапная сборка для оптимизации размера образа
|
||
# Этап 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:**
|
||
|
||
```dockerfile
|
||
# Базовый образ 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:**
|
||
```dockerfile
|
||
# Многоэтапная сборка для 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 микросервиса:**
|
||
```dockerfile
|
||
# Многоэтапная сборка для 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
|
||
# Оптимизированный 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 для микросервисной архитектуры:**
|
||
|
||
```yaml
|
||
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 микросервисной архитектуры:**
|
||
|
||
```yaml
|
||
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 команды для управления контейнерами:**
|
||
|
||
```bash
|
||
# Сборка образа
|
||
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>
|
||
```
|
||
|
||
#### Продвинутые команды:
|
||
```bash
|
||
# Запуск в фоновом режиме
|
||
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** — инструмент для определения и запуска многоконтейнерных приложений.
|
||
|
||
```yaml
|
||
# 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. Оптимизация размера образа
|
||
```dockerfile
|
||
# Используйте многоэтапную сборку
|
||
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. Безопасность
|
||
```dockerfile
|
||
# Создайте пользователя без root прав
|
||
RUN addgroup -g 1001 -S nodejs
|
||
RUN adduser -S nextjs -u 1001
|
||
USER nextjs
|
||
```
|
||
|
||
#### 3. Кэширование слоев
|
||
```dockerfile
|
||
# Копируйте package.json перед исходным кодом
|
||
COPY package*.json ./
|
||
RUN npm ci
|
||
COPY . .
|
||
```
|
||
|
||
#### 4. Health Checks
|
||
```dockerfile
|
||
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 для микросервиса:**
|
||
|
||
```yaml
|
||
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 для микросервиса:**
|
||
|
||
```yaml
|
||
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 для автоматического масштабирования:**
|
||
|
||
```yaml
|
||
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 для микросервиса:**
|
||
|
||
```yaml
|
||
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 для внешнего доступа:**
|
||
|
||
```yaml
|
||
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 для конфигурации:**
|
||
|
||
```yaml
|
||
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 для чувствительных данных:**
|
||
|
||
```yaml
|
||
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 для базы данных:**
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: PersistentVolumeClaim
|
||
metadata:
|
||
name: user-db-pvc
|
||
labels:
|
||
app: user-db
|
||
spec:
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
resources:
|
||
requests:
|
||
storage: 10Gi
|
||
storageClassName: fast-ssd
|
||
```
|
||
|
||
**StatefulSet для базы данных:**
|
||
|
||
```yaml
|
||
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** — хранит конфигурационные данные.
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: my-config
|
||
data:
|
||
database_url: "postgresql://localhost:5432/mydb"
|
||
api_key: "secret-key"
|
||
```
|
||
|
||
#### 5. Secret
|
||
**Secret** — хранит чувствительные данные.
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: my-secret
|
||
type: Opaque
|
||
data:
|
||
username: YWRtaW4=
|
||
password: cGFzc3dvcmQ=
|
||
```
|
||
|
||
### Команды Kubernetes
|
||
|
||
#### Основные команды:
|
||
```bash
|
||
# Применение манифеста
|
||
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** — управляет внешним доступом к сервисам.
|
||
|
||
```yaml
|
||
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
|
||
```yaml
|
||
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
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: PersistentVolume
|
||
metadata:
|
||
name: my-pv
|
||
spec:
|
||
capacity:
|
||
storage: 10Gi
|
||
accessModes:
|
||
- ReadWriteOnce
|
||
persistentVolumeReclaimPolicy: Retain
|
||
storageClassName: fast-ssd
|
||
```
|
||
|
||
#### 3. PersistentVolumeClaim
|
||
```yaml
|
||
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
|
||
```hcl
|
||
terraform {
|
||
required_providers {
|
||
aws = {
|
||
source = "hashicorp/aws"
|
||
version = "~> 4.0"
|
||
}
|
||
}
|
||
}
|
||
|
||
provider "aws" {
|
||
region = "us-west-2"
|
||
}
|
||
```
|
||
|
||
##### 2. Resource
|
||
```hcl
|
||
resource "aws_instance" "web" {
|
||
ami = "ami-0c02fb55956c7d316"
|
||
instance_type = "t2.micro"
|
||
|
||
tags = {
|
||
Name = "HelloWorld"
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 3. Data Source
|
||
```hcl
|
||
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
|
||
```hcl
|
||
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
|
||
```hcl
|
||
output "instance_ip" {
|
||
description = "Public IP of the instance"
|
||
value = aws_instance.web.public_ip
|
||
}
|
||
```
|
||
|
||
#### Команды Terraform
|
||
|
||
```bash
|
||
# Инициализация
|
||
terraform init
|
||
|
||
# Планирование изменений
|
||
terraform plan
|
||
|
||
# Применение изменений
|
||
terraform apply
|
||
|
||
# Уничтожение инфраструктуры
|
||
terraform destroy
|
||
|
||
# Просмотр состояния
|
||
terraform show
|
||
|
||
# Форматирование кода
|
||
terraform fmt
|
||
|
||
# Валидация конфигурации
|
||
terraform validate
|
||
```
|
||
|
||
#### Модули Terraform
|
||
|
||
```hcl
|
||
# 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:
|
||
```yaml
|
||
---
|
||
- 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
|
||
|
||
```yaml
|
||
# .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:
|
||
```yaml
|
||
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:
|
||
```yaml
|
||
# prometheus.yml
|
||
global:
|
||
scrape_interval: 15s
|
||
|
||
scrape_configs:
|
||
- job_name: 'kubernetes-pods'
|
||
kubernetes_sd_configs:
|
||
- role: pod
|
||
```
|
||
|
||
#### Дашборд Grafana:
|
||
```json
|
||
{
|
||
"dashboard": {
|
||
"title": "Kubernetes Cluster",
|
||
"panels": [
|
||
{
|
||
"title": "CPU Usage",
|
||
"type": "graph",
|
||
"targets": [
|
||
{
|
||
"expr": "rate(container_cpu_usage_seconds_total[5m])"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### ELK Stack
|
||
|
||
#### Elasticsearch + Logstash + Kibana:
|
||
```yaml
|
||
# 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
|
||
|
||
---
|
||
|
||
## Дополнительные ресурсы
|
||
|
||
### Документация
|
||
- [Docker Documentation](https://docs.docker.com/)
|
||
- [Kubernetes Documentation](https://kubernetes.io/docs/)
|
||
- [Terraform Documentation](https://www.terraform.io/docs/)
|
||
|
||
### Книги
|
||
- "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?
|