# Модуль 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 # Удаление контейнера docker rm # Просмотр образов docker images # Удаление образа docker rmi ``` #### Продвинутые команды: ```bash # Запуск в фоновом режиме docker run -d -p 3000:3000 myapp:latest # Подключение к контейнеру docker exec -it /bin/bash # Просмотр логов docker logs # Мониторинг ресурсов docker stats ``` ### 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: | /app/logs/user-service.log /app/logs/user-service.%d{yyyy-MM-dd}.%i.log 100MB 30 3GB %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n ``` **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 # Логи пода kubectl logs # Подключение к поду kubectl exec -it -- /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?