← Назад к вопросам

Сколько контейнеров может быть в Pod?

1.0 Junior🔥 191 комментариев
#ORM и Hibernate#Spring Boot и Spring Data#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Количество контейнеров в Pod'е Kubernetes

Ответ: Pod может содержать один или несколько контейнеров, обычно это 1-3 контейнера, но технически может быть больше.

Основной принцип

Pod — это наименьшая развёртываемая единица в Kubernetes. Он может содержать:

  • 1 контейнер (основной случай: 95% Pod'ов имеют 1 контейнер)
  • 2+ контейнера (специальные случаи: sidecar, init контейнеры)
# Пример Pod'а с 1 контейнером (типичный случай)
apiVersion: v1
kind: Pod
metadata:
  name: java-app-pod
spec:
  containers:
  - name: java-app
    image: myregistry/java-app:1.0.0
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "256Mi"
        cpu: "100m"

Когда используют несколько контейнеров в одном Pod'е

1. Sidecar pattern (logging, monitoring)

# Pod с основным приложением + logging sidecar
apiVersion: v1
kind: Pod
metadata:
  name: java-app-with-logging
spec:
  containers:
  # Основной контейнер
  - name: java-app
    image: myregistry/java-app:1.0.0
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: logs
      mountPath: /app/logs
  
  # Sidecar контейнер для отправки логов
  - name: log-shipper
    image: fluent/fluent-bit:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log
    env:
    - name: ELASTICSEARCH_URL
      value: "http://elasticsearch:9200"
  
  volumes:
  - name: logs
    emptyDir: {}

Этот Pod содержит 2 контейнера:

  • java-app — основное приложение
  • log-shipper — отправляет логи в Elasticsearch

2. Init контейнеры (инициализация)

apiVersion: v1
kind: Pod
metadata:
  name: java-app-with-init
spec:
  # Init контейнеры выполняются ДО основных контейнеров
  initContainers:
  - name: db-migrator
    image: myregistry/db-migration:1.0.0
    env:
    - name: DATABASE_URL
      value: "postgresql://db:5432/mydb"
    # Выполнит миграции БД и выйдет
  
  # Основные контейнеры
  containers:
  - name: java-app
    image: myregistry/java-app:1.0.0
    ports:
    - containerPort: 8080
    # Стартует только после init контейнера

Здесь 1 основной контейнер + 1 init контейнер. Init контейнеры выполняются в последовательном порядке перед основными.

3. Monitoring + Application

apiVersion: v1
kind: Pod
metadata:
  name: java-app-with-monitoring
spec:
  containers:
  # Основное приложение
  - name: java-app
    image: myregistry/java-app:1.0.0
    ports:
    - containerPort: 8080
    - containerPort: 9090  # Metrics endpoint
  
  # Prometheus exporter
  - name: prometheus-exporter
    image: prom/jmx-exporter:latest
    ports:
    - containerPort: 9100
    volumeMounts:
    - name: jmx-config
      mountPath: /etc/jmx-exporter
  
  volumes:
  - name: jmx-config
    configMap:
      name: jmx-exporter-config

4. Proxy + Application

apiVersion: v1
kind: Pod
metadata:
  name: java-app-with-proxy
spec:
  containers:
  # Основное приложение
  - name: java-app
    image: myregistry/java-app:1.0.0
    ports:
    - containerPort: 8080
  
  # Envoy proxy для service mesh (Istio)
  - name: istio-proxy
    image: istio/proxyv2:latest
    ports:
    - containerPort: 15000
    - containerPort: 15001

Реальный пример из моего опыта

На прошлой работе для основного микросервиса я использовал такой Pod:

apiVersion: v1
kind: Pod
metadata:
  name: orders-service-pod
spec:
  # Init контейнер: миграция БД
  initContainers:
  - name: db-migration
    image: myregistry/orders-service:1.0.0
    command: ["./migrate.sh"]
    env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: url
  
  containers:
  # Основное приложение: Java Spring Boot
  - name: orders-service
    image: myregistry/orders-service:1.0.0
    ports:
    - containerPort: 8080
      name: http
    - containerPort: 9090
      name: metrics
    resources:
      requests:
        memory: "512Mi"
        cpu: "250m"
      limits:
        memory: "1Gi"
        cpu: "500m"
    livenessProbe:
      httpGet:
        path: /actuator/health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      initialDelaySeconds: 20
      periodSeconds: 5
    env:
    - name: SPRING_PROFILES_ACTIVE
      value: "kubernetes"
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: url
    volumeMounts:
    - name: config
      mountPath: /etc/config
  
  # Sidecar 1: Logging
  - name: log-shipper
    image: fluent/fluent-bit:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log
    - name: fluent-config
      mountPath: /etc/fluent-bit
  
  # Sidecar 2: Monitoring (JMX exporter)
  - name: jmx-exporter
    image: sscaling/jmx-exporter:latest
    ports:
    - containerPort: 5556
    volumeMounts:
    - name: jmx-config
      mountPath: /etc/jmx-exporter
  
  volumes:
  - name: config
    configMap:
      name: orders-service-config
  - name: logs
    emptyDir: {}
  - name: fluent-config
    configMap:
      name: fluent-bit-config
  - name: jmx-config
    configMap:
      name: jmx-exporter-config

Этот Pod содержит 4 контейнера:

  1. db-migration (init контейнер)
  2. orders-service (основное приложение)
  3. log-shipper (sidecar для логирования)
  4. jmx-exporter (sidecar для мониторинга)

Best Practices

1. Один контейнер — основной случай

# ПРАВИЛЬНО: 95% случаев
apiVersion: v1
kind: Pod
metadata:
  name: simple-app
spec:
  containers:
  - name: app
    image: myapp:1.0

2. Используй sidecar только когда нужно

# ПЛОХО: Слишком много контейнеров (5+)
# Это усложняет deployment и debugging

# ХОРОШО: Максимум 2-3 sidecar'а
- name: app
- name: logging-sidecar
- name: monitoring-sidecar

3. Shared volumes для communication

// Java приложение пишет логи
public class OrderService {
    private static final String LOG_DIR = "/shared/logs";
    
    public void processOrder(Order order) {
        // Пишем логи
        Files.write(
            Paths.get(LOG_DIR + "/orders.log"),
            ("Order: " + order.getId()).getBytes(),
            StandardOpenOption.APPEND
        );
    }
}

// Sidecar контейнер читает из /shared/logs
// и отправляет в Elasticsearch

Ограничения

1. Network namespace

Все контейнеры в одном Pod'е делят одно IP адреса и network namespace:

# Все контейнеры видят друг друга на localhost
# Контейнер 1 (orders-service:8080)
# Контейнер 2 (jmx-exporter:5556)

# Из java-app:
curl http://localhost:5556/metrics  # Доступен!

2. Resource limits

# Лимиты считаются на весь Pod
resources:
  requests:
    memory: "512Mi"  # Всем контейнерам
    cpu: "250m"     # на двоих!
  limits:
    memory: "1Gi"
    cpu: "500m"

Если в Pod'е несколько контейнеров, они делят один пул ресурсов.

3. Lifecycle

Pod создан
  ↓
Init контейнеры выполняются в порядке
  ↓
Основные контейнеры стартуют ПАРАЛЛЕЛЬНО
  ↓
Под становится Ready когда все ready probes pass
  ↓
Под удален → все контейнеры останавливаются

Когда NOT использовать multiple containers

ПЛОХО:

# Две разные версии приложения
containers:
- name: old-app
  image: myapp:0.9
- name: new-app
  image: myapp:1.0

# Это не работает! Используй Deployment с replicas вместо этого

ПРАВИЛЬНО:

# Deployment с rolling update
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    spec:
      containers:
      - name: app
        image: myapp:1.0

Docker Compose аналогия

Pod похож на docker-compose, но для Kubernetes:

# docker-compose.yml
version: '3'
services:
  app:
    image: myapp:1.0
  logging:
    image: fluent/fluent-bit

# Аналог в Kubernetes Pod'е
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    image: myapp:1.0
  - name: logging
    image: fluent/fluent-bit

Типичные количества контейнеров

СлучайКонтейнеровПримеры
Простое приложение1REST API, Worker
С логированием2App + fluent-bit
С мониторингом2-3App + exporter + logger
Service mesh2App + istio-proxy
Init + App1+Migration + app

Заключение

Коротко:

  • 95% случаев: 1 контейнер в Pod'е
  • 5% случаев: 2-3 контейнера с sidecar'ами
  • Максимум обычно 3-4 контейнера
  • Более 5 контейнеров — признак неправильного проектирования

В моей практике я использовал:

  • Pod'ы с 1 контейнером для основных сервисов (95%)
  • Pod'ы с 2 контейнерами для сервисов с логированием (4%)
  • Pod'ы с 3 контейнерами для сложных сервисов с мониторингом (1%)

Никогда не использовал более 4 контейнеров в одном Pod'е, так как это усложняет debugging и deployment.

Сколько контейнеров может быть в Pod? | PrepBro