Облачная инфраструктура Production

Cloud Production — подход к построению и эксплуатации облачной инфраструктуры, рассчитанной на рабочую нагрузку: отказоустойчивость, масштабирование, безопасность, наблюдаемость и контролируемую стоимость.

В production-среде обычно используют управляемые сервисы облачного провайдера. Провайдер обслуживает часть инфраструктурного слоя, а команда отвечает за конфигурацию, данные, права доступа, сетевую архитектуру и приложение.

Пример типовой архитектуры:

Пользователи
    |
DNS / CDN / WAF
    |
Облачный Load Balancer
    |
Managed Kubernetes в нескольких Availability Zones
    |                         |
Managed Database          Object Storage
Multi-AZ                  резервные копии

Ключевая идея production-архитектуры — устранять единичные точки отказа и чётко разделять ответственность между облачным провайдером и владельцем системы.

Содержание


Основные принципы Cloud Production

Production-инфраструктура должна продолжать работу при отказе отдельного экземпляра, узла или зоны доступности. Для этого применяются:

Модель общей ответственности

Облачный провайдер и клиент отвечают за разные уровни системы.

Область Обычно отвечает провайдер Обычно отвечает клиент
Физический дата-центр Да Нет
Физические серверы и сеть Да Нет
Управляемый control plane Kubernetes Да Частично: конфигурация и доступ
Гостевая ОС виртуальной машины Нет или частично Да
Конфигурация приложения Нет Да
IAM и права доступа Предоставляет механизм Настраивает клиент
Данные и их классификация Нет Да
Резервное копирование Предоставляет возможности Включает и проверяет клиент
Шифрование Предоставляет сервисы Выбирает и настраивает клиент

Использование managed-сервиса не означает, что провайдер полностью отвечает за приложение и данные. Например, провайдер может обновлять control plane Kubernetes, но политики RBAC, сетевые правила и безопасность контейнеров остаются ответственностью команды.

Availability Zone и Region

Region — отдельный географический регион облачного провайдера.

Availability Zone, или AZ, — изолированная площадка внутри региона со своей инфраструктурой питания и сети. В одном регионе обычно доступно несколько зон.

Region
├── Availability Zone A
├── Availability Zone B
└── Availability Zone C

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

RTO и RPO

Требования к восстановлению удобно описывать двумя показателями:

Пример:

RTO: 30 минут
RPO: 5 минут

Это означает, что сервис должен быть восстановлен не позднее чем через 30 минут, а допустимая потеря данных не должна превышать примерно 5 минут.

Архитектура, частота резервных копий и стоимость системы зависят от требуемых RTO и RPO.


Managed Kubernetes

Managed Kubernetes — Kubernetes-кластер, в котором облачный провайдер управляет control plane полностью или частично.

К распространённым сервисам относятся:

Облако Сервис Kubernetes Managed database Балансировка
AWS Amazon EKS Amazon RDS, Aurora ELB: ALB, NLB
Google Cloud Google Kubernetes Engine Cloud SQL, AlloyDB Cloud Load Balancing
Microsoft Azure Azure Kubernetes Service Azure SQL, Azure Database for PostgreSQL Azure Load Balancer, Application Gateway
Другие провайдеры Managed Kubernetes Управляемые SQL/NoSQL-сервисы Облачные L4/L7-балансировщики

Точные названия и возможности зависят от провайдера, но общие архитектурные принципы похожи.

Что обычно управляется провайдером

В managed Kubernetes провайдер обычно берёт на себя:

Пользователь обычно отвечает за:

Managed control plane и worker nodes

Облачный провайдер
└── Managed control plane
    ├── API Server
    ├── etcd
    ├── Scheduler
    └── Controller Manager

Проект клиента
└── Data plane
    ├── Node group A
    ├── Node group B
    ├── Pods
    ├── Services
    └── Ingress

Worker nodes могут запускаться как:

Преимущества Managed Kubernetes

Ограничения


Amazon EKS

Amazon Elastic Kubernetes Service, или EKS, — управляемый Kubernetes в AWS.

Основные элементы EKS:

Типовая структура EKS

VPC
├── Public subnet, AZ-a
│   └── Load Balancer
├── Public subnet, AZ-b
│   └── Load Balancer
├── Private subnet, AZ-a
│   └── EKS worker nodes
├── Private subnet, AZ-b
│   └── EKS worker nodes
└── Database subnets
    └── RDS Multi-AZ

Worker nodes обычно размещают в приватных подсетях. Внешний трафик принимает публичный балансировщик, а исходящий доступ узлов при необходимости проходит через NAT Gateway или VPC endpoints.

Доступ Pod к AWS API

Не следует передавать постоянные AWS-ключи в Kubernetes Secret, если доступна интеграция сервисного аккаунта с облачной ролью.

Принцип:

Pod
└── Kubernetes ServiceAccount
    └── IAM role
        └── IAM policy
            └── разрешённые AWS API

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


Google Kubernetes Engine

Google Kubernetes Engine, или GKE, — управляемый Kubernetes в Google Cloud.

Основные варианты:

Типовые интеграции GKE:

Workload Identity

Workload Identity связывает Kubernetes ServiceAccount с облачной учётной записью. Это позволяет Pod получать временные учётные данные без хранения постоянного ключа в контейнере.

Общая схема аналогична другим облакам:

Pod → ServiceAccount → Cloud IAM identity → разрешённый сервис

Regional-кластеры

Для production предпочтительнее архитектура, в которой control plane и worker nodes распределены по нескольким зонам региона. Зональный кластер может оказаться более уязвимым к отказу одной зоны.


Аналоги Managed Kubernetes

Несмотря на различия в названиях, управляемые Kubernetes-сервисы обычно предоставляют одинаковые базовые возможности:

Возможность Назначение
Managed control plane Управление API Server, etcd и контроллерами
Node pools / node groups Группировка узлов по типу и назначению
Cluster autoscaler Изменение количества узлов
Load Balancer integration Создание облачного балансировщика из Kubernetes
Block storage integration Динамическое выделение дисков через CSI
Workload identity Доступ Pod к облачным API без постоянных ключей
Managed add-ons Обслуживание системных компонентов
Observability integration Передача метрик и логов в облачные сервисы

При выборе сервиса следует оценивать не только стоимость узлов, но и:


Проектирование production-кластера

Node pools

Разные типы нагрузок удобно размещать в отдельных группах узлов:

Кластер
├── system node pool
├── application node pool
├── memory-optimized node pool
└── spot/preemptible node pool

Для управления размещением применяются:

Пример выбора группы узлов:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: reports
spec:
  replicas: 2
  selector:
    matchLabels:
      app: reports
  template:
    metadata:
      labels:
        app: reports
    spec:
      nodeSelector:
        workload: memory-optimized
      containers:
        - name: reports
          image: registry.example.com/reports:1.4.0
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "2"
              memory: "2Gi"

Requests и limits

requests используются Scheduler для размещения Pod и влияют на масштабирование узлов.

limits ограничивают максимальное потребление ресурсов контейнером.

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "512Mi"

Если requests сильно завышены, узлы используются неэффективно. Если они занижены, на одном узле может оказаться слишком много Pod, что повышает риск нехватки ресурсов.

При превышении memory limit контейнер может быть завершён с причиной OOMKilled. CPU limit обычно приводит к ограничению процессорного времени, а не к завершению контейнера.

Распределение Pod по зонам

topologySpreadConstraints помогают не размещать все реплики в одной зоне:

spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: api
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: api
      containers:
        - name: api
          image: registry.example.com/api:2.1.0

Для защиты от обслуживания узлов применяется PodDisruptionBudget:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

PodDisruptionBudget ограничивает обровольные прерывания, например при обновлении узлов. Он не гарантирует доступность при аварийном отказе узла или зоны.

Обновление кластера

Безопасный процесс обновления обычно включает:

  1. проверку совместимости API и дополнений;
  2. обновление тестового кластера;
  3. обновление control plane;
  4. обновление системных add-ons;
  5. создание новой группы узлов;
  6. перенос нагрузки на новые узлы;
  7. удаление старой группы после проверки.

Перед обновлением необходимо проверить устаревшие Kubernetes API, версии Ingress Controller, CSI-драйверов и сетевых плагинов.


Managed databases

Managed database — база данных, для которой облачный провайдер автоматизирует часть административных операций.

Примеры категорий:

Категория Примеры технологий Типичные задачи
Реляционные БД PostgreSQL, MySQL, SQL Server Транзакции, связи, SQL
Документные БД Совместимые с document model Каталоги, профили, гибкая схема
Key-value Распределённые key-value-хранилища Сессии, быстрый доступ по ключу
In-memory Redis-совместимые сервисы Кэш, очереди, rate limiting
Data warehouse Аналитические колоночные системы BI и аналитика больших объёмов

Провайдер обычно автоматизирует:

Команда по-прежнему отвечает за:

Выбор managed database

При выборе оценивают:

Подключение приложения

База данных обычно размещается в приватных подсетях и не получает публичный адрес.

Application Pod / VM
    |
private network
    |
Managed Database endpoint

Доступ ограничивается сетевыми правилами и учётной записью БД. Не следует разрешать подключение ко всем адресам 0.0.0.0/0.

Пример строки подключения через переменные окружения:

env:
  - name: DB_HOST
    value: postgres.internal.example
  - name: DB_PORT
    value: "5432"
  - name: DB_NAME
    value: application
  - name: DB_USER
    valueFrom:
      secretKeyRef:
        name: database-credentials
        key: username
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: database-credentials
        key: password

В production предпочтительно получать секреты из специализированного secret manager и автоматически ротировать их, если платформа это поддерживает.

Connection pooling

Каждый Pod приложения может создавать несколько подключений к базе. При автоматическом масштабировании общее количество подключений быстро растёт:

20 Pod × 20 соединений = 400 соединений

Чтобы избежать исчерпания лимита, применяются:


Высокая доступность баз данных

Primary и standby

В Multi-AZ-конфигурации основная база реплицирует данные на резервный экземпляр в другой зоне.

AZ-a                          AZ-b
Primary database  ────────>  Standby database
        ^
        |
  единый endpoint

При отказе primary управляемый сервис переключает endpoint на standby. Конкретное время переключения зависит от сервиса, конфигурации и характера отказа.

Standby и read replica

Эти механизмы решают разные задачи.

Механизм Основная цель Обычно обслуживает чтение
Multi-AZ standby Высокая доступность и failover Не всегда
Read replica Масштабирование чтения Да

Read replica может реплицироваться асинхронно, поэтому данные на ней иногда отстают от primary. Это следует учитывать для операций, где требуется немедленно прочитать только что записанные данные.

Вертикальное масштабирование

Вертикальное масштабирование увеличивает ресурсы одного экземпляра:

4 vCPU, 16 GiB → 8 vCPU, 32 GiB

Это простой подход, но у него есть предел. Изменение класса экземпляра также может потребовать перезапуска или failover.

Горизонтальное масштабирование

Для масштабирования чтения применяются read replicas. Горизонтальное масштабирование записи сложнее и может требовать:

Миграции схемы

Миграции должны быть совместимы с поэтапным обновлением приложения.

Безопасная последовательность:

  1. добавить новые поля или таблицы без удаления старых;
  2. развернуть версию приложения, поддерживающую обе схемы;
  3. перенести или заполнить данные;
  4. переключить чтение на новую схему;
  5. удалить старые поля отдельным изменением.

Следует избегать блокирующих изменений больших таблиц в часы пик.


Резервное копирование и восстановление

Резервная копия полезна только в том случае, если из неё можно восстановить данные.

Основные механизмы

Point-in-Time Recovery

PITR позволяет восстановить базу на выбранный момент времени в пределах периода хранения журналов.

12:00 — полная резервная копия
12:00–15:30 — журналы изменений
15:30 — требуемая точка восстановления

Обычно восстановление создаёт новый экземпляр базы. После этого приложение необходимо переключить на новый endpoint или перенести нужные данные.

Проверка восстановления

Регулярная проверка должна подтверждать:

Защита резервных копий

Резервные копии должны иметь:


Load balancers в облаке

Load Balancer принимает входящий трафик и распределяет его между несколькими целевыми экземплярами.

Клиенты
   |
Load Balancer
├── Instance / Pod A
├── Instance / Pod B
└── Instance / Pod C

Основные функции:

Health checks

Балансировщик периодически проверяет backend:

GET /health/ready

Если проверка не проходит, backend временно исключается из балансировки.

Endpoint проверки должен:

Не следует использовать endpoint, который всегда возвращает 200, даже если приложение потеряло доступ к критической зависимости.

TLS termination

Балансировщик может завершать HTTPS-соединение:

Client -- HTTPS --> Load Balancer -- HTTP/HTTPS --> Backend

Сертификаты удобно хранить и обновлять через управляемый certificate manager. Для чувствительного трафика можно применять шифрование и между балансировщиком и backend.

Sticky sessions

Sticky sessions направляют клиента на один и тот же backend. Это иногда необходимо для устаревших stateful-приложений, но усложняет масштабирование и failover.

Предпочтительнее хранить состояние вне экземпляра приложения:


Виды балансировщиков

Layer 4

L4-балансировщик работает на транспортном уровне и маршрутизирует TCP или UDP-соединения.

Подходит для:

TCP connection → L4 Load Balancer → Backend

Layer 7

L7-балансировщик понимает HTTP и HTTPS и может маршрутизировать запросы по содержимому.

api.example.com      → API service
static.example.com   → Static service
/admin               → Admin service

Возможности L7:

Internal и internet-facing

Internet-facing Load Balancer доступен из интернета.

Internal Load Balancer имеет приватный адрес и используется для внутренних сервисов.

Internet → Public LB → Web application
Internal services → Internal LB → Internal API

Внутренние сервисы не следует публиковать наружу без необходимости.

Cross-zone load balancing

Cross-zone-балансировка позволяет распределять трафик между backend в разных AZ. Она улучшает равномерность нагрузки, но может создавать межзонный трафик, которы в некоторых облаках тарифицируется отдельно.


Балансировка трафика в Kubernetes

В managed Kubernetes облачный балансировщик обычно создаётся через Service типа LoadBalancer или через Ingress/Gateway-контроллер.

Service типа LoadBalancer

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  type: LoadBalancer
  selector:
    app: api
  ports:
    - name: http
      port: 80
      targetPort: 8080

Облачный контроллер создаёт внешний или внутренний балансировщик и направляет трафик к сервису.

Такой подход удобен для отдельного L4-балансировщика, но отдельный балансировщик для каждого сервиса может быть дорогим.

Ingress

Ingress позволяет использовать один L7-балансировщик для нескольких приложений:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: applications
spec:
  ingressClassName: cloud-ingress
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 80
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend
                port:
                  number: 80

Для работы Ingress необходим Ingress Controller. В облаке им может быть контроллер, создающий managed load balancer, или отдельный контроллер внутри кластера.

External traffic policy

Для Service типа LoadBalancer параметр externalTrafficPolicy влияет на маршрутизацию внешнего трафика:

spec:
  type: LoadBalancer
  externalTrafficPolicy: Local

Local может помочь сохранить исходный IP клиента и избежать дополнительного межузлового перехода, но требует достаточного числа локальных endpoint на узлах, принимающих трафик.


Multi-AZ-развёртывания

Multi-AZ означает размещение компонентов приложения в нескольких зонах доступности одного региона.

Region
├── AZ-a
│   ├── Load Balancer node
│   ├── Kubernetes nodes
│   └── Database primary
├── AZ-b
│   ├── Load Balancer node
│   ├── Kubernetes nodes
│   └── Database standby
└── AZ-c
    ├── Load Balancer node
    └── Kubernetes nodes

Что необходимо распределять

Для полной Multi-AZ-архитектуры недостаточно распределить только виртуальные машины. Нужно проверить:

Подсети

Типичная VPC содержит публичные и приватные подсети в каждой зоне:

VPC 10.0.0.0/16
├── AZ-a
│   ├── public-a  10.0.0.0/24
│   └── private-a 10.0.10.0/24
├── AZ-b
│   ├── public-b  10.0.1.0/24
│   └── private-b 10.0.11.0/24
└── AZ-c
    ├── public-c  10.0.2.0/24
    └── private-c 10.0.12.0/24

Публичные подсети используются для компонентов, которым необходим прямой маршрут через Internet Gateway, например для публичных балансировщиков. Приложения и базы данных обычно находятся в приватных подсетях.

Зональные диски

Многие блочные диски привязаны к одной Availability Zone. Pod с таким диском нельзя произвольно запустить в другой зоне без восстановления или репликации данных.

Следует учитывать:

Пример StorageClass с отложенным созданием тома:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: production-block
provisioner: csi.example.cloud
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

WaitForFirstConsumer позволяет выбрать зону диска с учётом размещения Pod.

NAT и исходящий доступ

Один NAT Gateway в одной AZ может стать точкой отказа и источником межзонного трафика. Более отказоустойчивая схема использует отдельный NAT в каждой зоне и зональные таблицы маршрутизации.

private-a → NAT-a
private-b → NAT-b
private-c → NAT-c

Это повышает доступность, но также увеличивает стоимость. Для доступа к облачным сервисам можно применять private endpoints, если они доступны, сокращая зависимость от NAT и стоимость обработки трафика.

Multi-AZ и Multi-Region

Характеристика Multi-AZ Multi-Region
Защита от отказа узла Да Да
Защита от отказа зоны Да Да
Защита от отказа региона Нет Да
Задержка между компонентами Обычно низкая Выше
Сложность данных Умеренная Высокая
Стоимость Выше single-AZ Обычно значительно выше

Multi-Region требуется не каждому проекту. Решение должно исходить из бизнес-требований, а не только из желания получить максимально сложную архитектуру.


Отказоустойчивость приложения

Несколько реплик

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: registry.example.com/api:2.1.0
          ports:
            - containerPort: 8080

Нескольк реплик помогают пережить отказ одного Pod или узла. Реплики должны быть распределены между узлами и зонами.

Readiness, liveness и startup probes

containers:
  - name: api
    image: registry.example.com/api:2.1.0
    readinessProbe:
      httpGet:
        path: /health/ready
        port: 8080
      periodSeconds: 5
      failureThreshold: 3
    livenessProbe:
      httpGet:
        path: /health/live
        port: 8080
      periodSeconds: 10
      failureThreshold: 3
    startupProbe:
      httpGet:
        path: /health/startup
        port: 8080
      periodSeconds: 5
      failureThreshold: 30

Liveness-проверка не должна завершать контейнер только из-за кратковременной недоступности внешней базы данных. Иначе общий сбой зависимости может вызвать массовые перезапуски.

Graceful shutdown

При завершении Pod приложение должно:

  1. перестать принимать новые запросы;
  2. завершить текущие операции;
  3. закрыть соединения;
  4. остановиться до окончания terminationGracePeriodSeconds.
spec:
  terminationGracePeriodSeconds: 30
  containers:
    - name: api
      lifecycle:
        preStop:
          exec:
            command: ["/bin/sh", "-c", "sleep 5"]

Простой sleep иногда используют, чтобы дать балансировке время исключить endpoint, но лучше, чтобы само приложение корректно обрабатывало сигнал завершения.

Retry и timeout

Сетевые вызовы могут временно завершаться ошибкой. Клиенты должны использовать:

Неограниченные повторы увеличивают нагрузку во время сбоя и могут вызвать retry storm.


Cost optimization

Cost optimization — систематическая работа по снижению расходов без нарушения требований к доступности, производительности и безопасности.

Оптимизация не означает выбор самого дешёвого ресурса. Необходимо оценивать полную стоимость системы и последствия отказа.

Основные источники расходов

Теги и распределение затрат

Ресурсы следует помечать тегами или labels:

environment = production
service     = payments
team        = platform
cost-center = commerce
managed-by  = terraform

Теги позволяют строить отчёты по командам, сервисам и средам. Стандарт тегирования должен применяться автоматически через Terraform-модули или организационные политики.

Rightsizing

Rightsizing — подбор ресурсов по фактической нагрузке.

Примеры:

Изменения следует делать на основании метрик за репрезентативный период, включая часы пик.

Автомасштабирование

На разных уровнях могут работать:

Эти механизмы должны быть согласованы. Например, HPA создаёт дополнительные Pod, а cluster autoscaler добавляет узлы, если Pod некуда разместить.

Spot и preemptible instances

Прерываемые экземпляры дешевле обычных, но облако может забрать их с коротким уведомлением.

Подходят для:

Не следует размещать всю production-нагрузку только на прерываемых экземплярах. Обычно используют сочетание обычных и spot-узлов.

Node pool A: on-demand, базовая ёмкость
Node pool B: spot, дополнительная ёмкость

Приложение должно корректно обрабатывать эвакуацию Pod и повторное выполнение задач.

Commitments и reserved capacity

Для постоянной предсказуемой нагрузки провайдеры предлагают модели обязательств на длительный срок. Они могут снизить стоимость вычислений, но уменьшают гибкость.

Перед покупкой обязательств следует оценить:

Хранилища

Оптимизация хранения включает:

Пример жизненного цикла объектов:

0–30 дней    → Standard
31–90 дней   → Infrequent Access
после 90 дней → Archive
после 365 дней → Delete

Переходы между классами и раннее удаление могут тарифицироваться, поэтому политику следует сопоставлять с реальным профилем доступа.

Сетевой трафик

Сетевые расходы часто недооценивают. Отдельно могут тарифицироваться:

Способы оптимизации:

Экономия на межзонном трафике не должна разрушать отказоустойчивость. Например, размещение всех реплик в одной зоне может снизить сетевые расходы, но создаст риск полного отказа сервиса при проблеме с этой зоной.

Логи и метрики

Стоимость observability может расти быстрее стоимости вычислений.

Рекомендуется:

Бюджеты и оповещения

Необходимо настроить:

Бюджетное оповещение обычно не останавливает ресурсы автоматически. Автоматическое отключение production-компонентов из-за превышения бюджета может привести к аварии и должно применяться только при явно продуманной политике.


Наблюдаемость и эксплуатация

Production-система должна предоставлять информацию о своём состоянии.

Три основных сигнала

Дополнительно отслеживают события инфраструктуры, изменения конфигурации и audit logs.

Основные метрики

Для HTTP-сервиса полезны:

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

SLI, SLO и SLA

Пример SLO:

99.9% HTTP-запросов за 30 дней завершаются успешно.
95% запросов выполняются не дольше 300 мс.

Оповещения полезнее строить вокруг пользовательских симптомов и расходования error budget, а не только вокруг CPU отдельной виртуальной машины.

Централизованные логи

Логи нескольких Pod и узлов должны собираться централизованно. Запись только в локальный файл контейнера ненадёжна: Pod может быть удалён или перемещён.

Структурированный лог:

{
  "timestamp": "2026-09-24T12:00:00Z",
  "level": "error",
  "service": "payments-api",
  "request_id": "req-8f31",
  "message": "database timeout"
}

Не следует записывать в логи:

Runbooks

Для критичных оповещений полезно иметь runbook:

Alert: высокая доля HTTP 5xx
1. Проверить область воздействия.
2. Проверить последние deployment.
3. Проверить доступность базы и внешних зависимостей.
4. Проверить saturation и число реплик.
5. При необходимости выполнить rollback.
6. Зафиксировать временную шкалу инцидента.

Runbook должен быть коротким, проверенным и доступным дежурной команде.


Безопасность production-инфраструктуры

IAM и минимальные привилегии

Каждый компонент получает только необходимые права:

Application A → чтение из bucket A
Application B → запись в queue B
CI/CD          → обновление конкретного deployment
Administrator  → отдельная роль с усиленной аутентификацией

Следует избегать:

Workload identity

Для доступа Pod к облачным сервисам применяют workload identity или аналогичный механизм:

Kubernetes ServiceAccount
        ↓
Cloud IAM role/account
        ↓
Краткоживущие credentials

Это безопаснее постоянных ключей в Kubernetes Secret.

Сетевая сегментация

Шифрование

Следует применять:

Управление секретами

Секреты лучше хранить в managed secret manager или vault-системе. Kubernetes Secret сам по себе не является полноценным внешним хранилищем секретов.

Безопасная схема:

Secret Manager
    ↓ временный доступ
CSI driver / operator / application
    ↓
Pod

Секреты не должны попадать в:

Audit logs

Audit logs помогают установить:

Для критичных журналов следует настроить достаточный срок хранения и защиту от удаления.


Общий пример архитектуры

Рассмотрим production-приложение из frontend, API и PostgreSQL.

Internet
   |
DNS
   |
CDN / WAF
   |
Public L7 Load Balancer
   |
Managed Kubernetes cluster
├── AZ-a
│   ├── frontend Pod
│   └── api Pod
├── AZ-b
│   ├── frontend Pod
│   └── api Pod
└── AZ-c
    ├── frontend Pod
    └── api Pod
          |
          +── Managed PostgreSQL Multi-AZ
          |
          +── Object Storage
          |
          +── Secret Manager

Компоненты

Компонент Назначение
DNS Преобразование домена в адрес сервиса
CDN Кэширование статического контента ближе к пользователю
WAF Фильтрация типовых вредоносных HTTP-запросов
L7 Load Balancer TLS и маршрутизация HTTP-трафика
Managed Kubernetes Запуск и масштабирование контейнеров
Managed PostgreSQL Транзакционные данные приложения
Object Storage Пользовательские файлы и артефакты
Secret Manager Хранение секретов
Monitoring Метрики, dashboard и alerting
Centralized Logging Поиск и хранение журналов

Поток запроса

  1. Пользователь обращается к app.example.com.
  2. DNS возвращает адрес CDN или балансировщика.
  3. WAF проверяет HTTP-запрос.
  4. L7 Load Balancer завершает TLS.
  5. Ingress направляет запрос в нужный Kubernetes Service.
  6. Service выбирает готовый Pod.
  7. API обращается к базе данных через приватную сеть.
  8. Файлы сохраняются в object storage через workload identity.
  9. Метрики, логи и трассировки отправляются в систему наблюдаемости.

Пример HPA

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 20
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 65

Минимум три реплики обеспечивает базовое распределение по зонам. Фактическое распределение следует закрепить topology spread constraints или affinity.

Пример NetworkPolicy

Следующая политика разрешает входящий трафик к API только от Pod с меткой app: ingress-controller в namespace ingress-system:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-system
          podSelector:
            matchLabels:
              app: ingress-controller
      ports:
        - protocol: TCP
          port: 8080

Для применения NetworkPolicy сетевой плагин кластера должен поддерживать их выполнение.

Стратегия deployment

Для обычного rolling update:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1

maxUnavailable: 0 не допускает планового уменьшения количества доступных реплик во время обновления, но временно требует дополнительной ёмкости.

Перед выпуском необходимо проверить:


Чек-лист перед запуском

Архитектура

Managed Kubernetes

База данных

Балансировка и сеть

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

Наблюдаемость

Стоимость


Cloud Production строится не вокруг одного конкретного сервиса, а вокруг набора проверяемых свойств: система должна выдерживать ожидаемые отказы, восстанавливаться в заданные сроки, безопасно работать с данными, масштабироваться под нагрузкой и сохранять предсказуемую стоимость. Managed Kubernetes, managed databases и облачные load balancers уменьшают объём ручного администрирования, но требуют корректной архитектуры, настройки и регулярных проверок.