Learning Platform
Глоссарий Troubleshooting
Урок 12.04 · 18 мин
Средний
adapterPrometheus exporterlog adaptervendor integrationobservability

Adapter pattern: transform output для внешних систем

Adapter — это контейнер, задача которого преобразовывать output main приложения в формат, который ожидает внешняя система. Канонические сценарии: app пишет логи в proprietary формате → adapter трансформирует в JSON; app expose внутренние метрики через файл/socket → adapter конвертирует в Prometheus exposition format на HTTP endpoint. Adapter не добавляет новой функциональности — он «адаптирует» существующий output. Современно adapter реализуется как native sidecar (initContainer + restartPolicy: Always, GA v1.33), но концептуально это отдельный паттерн.


Monitoring Stack: JMX exporter + Prometheus + Grafana

Зачем нужен adapter

Сценарий: у вас есть vendor binary (closed-source приложение, legacy продукт, custom binary без исходников), который пишет в stdout custom формат логов:

2026-01-15 10:30:01 [INFO] (component=worker) [tid=42] Job 12345 completed in 234ms

Ваш централизованный logging stack (Loki, ELK, Datadog) ожидает JSON:

{"ts":"2026-01-15T10:30:01Z","level":"info","component":"worker","tid":42,"msg":"Job 12345 completed","duration_ms":234}

Вы не можете поменять источник логов (vendor binary). Вариантов два:

  1. Парсить на стороне log collector (Logstash filter, Fluent Bit lua parser) — но это сложно поддерживать и распределяет логику.
  2. Adapter container в том же Pod — читает raw output, делает transform, выдаёт в нужном формате. Логика парсинга живёт рядом с app.

YAML пример: adapter для метрик

Самый частый реальный adapter — Prometheus exporter для приложения, которое не умеет говорить prometheus exposition format напрямую.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-prometheus-adapter
spec:
  initContainers:
  - name: metrics-adapter             # native sidecar, реализует adapter паттерн
    image: prom/redis_exporter:v1.55
    restartPolicy: Always
    args: ['--redis.addr=localhost:6379']
    ports:
    - name: metrics
      containerPort: 9121
  containers:
  - name: redis
    image: redis:7
    ports:
    - name: redis
      containerPort: 6379

Что происходит:

  • redis exposes свой бинарный protocol на localhost:6379;
  • metrics-adapter (redis_exporter) подключается к localhost:6379, опрашивает Redis через его native protocol (INFO, CONFIG GET);
  • adapter выдаёт результат в Prometheus exposition format на localhost:9121/metrics;
  • Prometheus scrape Pod_IP:9121/metrics — и получает метрики Redis в стандартном формате.

Redis сам не знает про Prometheus, не имеет prometheus endpoint. Adapter эту интеграцию делает.

Adapter: преобразование протокола
externalВнешняя система (Prometheus) ожидает определённый формат — exposition format на HTTP endpoint. Это контракт стандарта.
ожидает HTTP /metrics
adapterredis_exporter: подключается к Redis через native RESP protocol, переводит ответы в Prometheus format. Сам — Prometheus client server: bind на 9121, отвечает on scrape.
native protocol
mainRedis: сам не знает про Prometheus. Просто слушает на 6379, отвечает на INFO, CONFIG GET. Никаких модификаций app code не требуется.

Канонические adapter use cases

СценарийMain app даётAdapter преобразует в
Prometheus metricsproprietary metrics endpoint, log file, native protocolexposition format на /metrics
JSON logscustom text format в stdout/filestructured JSON
HealthcheckTCP check, custom protocolHTTP /healthz для probe
Tracingapplication-specific spansOTLP формат
Audit eventslocal filesyslog или Kafka

Adapter vs Sidecar: где граница

Часто их путают, и часто их грань размыта. Разница концептуальная:

  • Sidecarдобавляет функциональность, которой у main app нет. Log shipper «забирает логи и отправляет наружу» — это новая функция (доставка).
  • Adapterпреобразует существующий output в новый формат, не добавляя новой смысловой функциональности. Prometheus exporter «берёт метрики, которые app уже отдаёт, и переводит в format» — никакой новой информации.

На практике один контейнер часто делает оба: fluent-bit и забирает логи (sidecar), и парсит из text в JSON (adapter). Поэтому в YAML вы видите только initContainers + restartPolicy: Always — название паттерна в манифесте отсутствует.

NOTE

Деление на adapter/sidecar — методологическое, для проектирования. В Kubernetes API оба механизма — один и тот же native sidecar (initContainer + restartPolicy: Always, GA v1.33). Имя паттерна влияет только на то, как вы думаете о проблеме, не на YAML.


Когда adapter — правильный выбор

  • Vendor binary без возможности модификации. Closed-source, у вас только бинарь.
  • Legacy app, которое нельзя релизить часто. Изменение adapter — это отдельный rolling update без релиза основного app.
  • Полифонные приложения: app пишет логи в десяти форматах для разных consumers. Один adapter под каждый формат лучше, чем добавлять 10 endpoints в app.
  • Адаптация под стандарт мониторинга, который app не поддерживает: prometheus, OpenTelemetry, syslog RFC5424.

Когда adapter — антипаттерн

Если вы можете изменить main app code — почти всегда лучше изменить там:

  • Добавьте Prometheus client library и /metrics endpoint в app. Никакого adapter не нужно.
  • Включите structured JSON logging в app config. Никакого парсинга не нужно.
  • Добавьте OTLP exporter в app. Не нужен sidecar collector.

Adapter — это escape hatch для случаев, когда модификация app невозможна или дорога. Если код в ваших руках — модифицируйте app.

WARNING

Anti-pattern: добавить sidecar adapter, потому что «парсить логи в Python проще, чем добавлять JSON logger в Go-приложение». Это создаёт два процесса там, где был один; добавляет CPU/memory; усложняет debug (логи в Pod в двух местах: app stdout и adapter stdout). Если можно модифицировать app — это всегда правильнее.


Killer момент: shared volume для files-based adapter

Часть adapter паттернов работает через shared file, а не через localhost socket. Например, app пишет метрики в файл (vendor binary сделал так), adapter этот файл читает и выдаёт на HTTP.

spec:
  initContainers:
  - name: file-to-prometheus
    image: my-org/file-metrics-adapter:v1
    restartPolicy: Always
    args: ['--path=/var/metrics/app.json', '--port=9090']
    volumeMounts:
    - mountPath: /var/metrics
      name: metrics
    ports:
    - containerPort: 9090
  containers:
  - name: app
    image: vendor/legacy-app:v1
    volumeMounts:
    - mountPath: /var/metrics
      name: metrics                  # app пишет сюда
  volumes:
  - name: metrics
    emptyDir: {}                     # обмен через локальный emptyDir

Adapter tail -f файл, парсит, expose на /metrics. Это типовая схема для legacy интеграций.


CKAD: что знать про adapter

На CKAD adapter спрашивают концептуально, не глубоко:

  • понимать, что это transform output, не добавление функциональности;
  • уметь привести пример (Prometheus exporter, log JSON adapter);
  • знать, что современно реализуется как native sidecar (initContainer + restartPolicy: Always, GA v1.33);
  • понимать, что adapter — это для случаев, когда app модифицировать нельзя.

Чисто практически в CKAD задачах adapter появляется редко — гораздо чаще sidecar и init.


Проверка знанийKnowledge check
Чем adapter отличается от sidecar концептуально?
ОтветAnswer
Sidecar добавляет НОВУЮ функциональность к main app (логирование, отправка метрик наружу, mTLS proxy). Adapter ПРЕОБРАЗУЕТ существующий output main в формат, который ожидает внешняя система (custom logs → JSON, native metrics → Prometheus). Adapter не добавляет смысловой нагрузки, только формат. На практике один контейнер часто играет обе роли, и в YAML они не различаются — обоих реализуются как initContainer + restartPolicy: Always.
Проверка знанийKnowledge check
Когда adapter — антипаттерн, а лучше модифицировать main app?
ОтветAnswer
Когда код приложения в ваших руках. Если можно добавить Prometheus client library и /metrics endpoint в app — это всегда правильнее, чем тащить exporter рядом. Adapter создаёт два процесса, CPU/memory overhead, усложняет debug. Adapter — escape hatch для vendor binaries, closed-source legacy, и случаев, когда модификация app слишком дорога/невозможна.
Проверка знанийKnowledge check
Vendor binary (closed source) пишет метрики в /var/metrics/app.json. Вы хотите Prometheus scrape. Как организовать через adapter?
ОтветAnswer
Sidecar GA initContainer (restartPolicy: Always) с image типа file-to-prometheus exporter, mount-ит emptyDir /var/metrics общий с main, читает app.json, парсит, expose на :9090/metrics. Pod-level emptyDir shared между app и adapter. Prometheus scrape Pod_IP:9090. App не знает про Prometheus, adapter делает трансляцию формата.
Проверка знанийKnowledge check
Redis_exporter sidecar для Redis Pod: какой механизм связи между ними?
ОтветAnswer
Localhost через shared network namespace Pod. Redis bind на localhost:6379 (RESP protocol). redis_exporter подключается на localhost:6379 как обычный Redis client, периодически опрашивает INFO/CONFIG, переводит результат в Prometheus exposition format и expose на localhost:9121/metrics. Prometheus scrape Pod_IP:9121.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 4. Чем adapter pattern концептуально отличается от sidecar?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5