KubernetesSeniorSystem design
Как ты делаешь production-grade observability в Kubernetes: метрики, логи, трейсы? Какой стек?
Стек: kube-prometheus-stack (Prometheus + Grafana + Alertmanager) для метрик, Loki + Promtail для логов, Tempo + OpenTelemetry Collector для трейсов. Всё интегрируется в Grafana с cross-linking трейсов и логов через trace_id.
Production-grade observability в Kubernetes: метрики, логи, трейсы
Observability строится на трёх столпах: метрики (Prometheus + Grafana), логи (Loki или Elasticsearch) и распределённые трейсы (Tempo или Jaeger). Все три компонента разворачиваются через Helm и интегрируются в единый дашборд Grafana.
Метрики: kube-prometheus-stack
# Устанавливаем kube-prometheus-stack (Prometheus Operator + Grafana + alertmanager)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
--set grafana.adminPassword=secretpassword \
--set prometheus.prometheusSpec.retention=30d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi
# ServiceMonitor для своего приложения
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: monitoring
labels:
release: kube-prometheus-stack # должен совпадать с selector в Prometheus CR
spec:
selector:
matchLabels:
app: my-app
namespaceSelector:
matchNames:
- production
endpoints:
- port: http
path: /metrics
interval: 30s
Логи: Grafana Loki + Promtail
# Loki в режиме single binary (для кластеров до ~50 ГБ/сут)
helm install loki grafana/loki \
--namespace monitoring \
--set loki.commonConfig.replication_factor=1 \
--set loki.storage.type=filesystem
# Promtail как DaemonSet — собирает логи со всех нод
helm install promtail grafana/promtail \
--namespace monitoring \
--set config.lokiAddress=http://loki:3100/loki/api/v1/push
# Promtail автоматически добавляет k8s-метки через pipeline_stages
# Структурированные JSON-логи парсятся через stage.json:
pipelineStages:
- json:
expressions:
level: level
msg: message
trace_id: trace_id
- labels:
level:
trace_id:
Трейсы: Grafana Tempo + OpenTelemetry
# Tempo
helm install tempo grafana/tempo \
--namespace monitoring \
--set tempo.storage.trace.backend=local
# OpenTelemetry Collector как DaemonSet
helm install otel-collector open-telemetry/opentelemetry-collector \
--namespace monitoring \
--values otel-values.yaml
# otel-values.yaml — collector получает трейсы от приложений и шлёт в Tempo
mode: daemonset
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
otlp:
endpoint: tempo.monitoring.svc.cluster.local:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlp]
Инструментирование приложения (Python пример)
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="http://otel-collector:4317")
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("process-order") as span:
span.set_attribute("order.id", order_id)
span.set_attribute("user.id", user_id)
# бизнес-логика...
Alerting
# PrometheusRule — alertmanager правило
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: my-app-alerts
namespace: monitoring
spec:
groups:
- name: my-app
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 0.01
for: 2m
labels:
severity: critical
annotations:
summary: "Error rate > 1% for 2 minutes"
Связь логов и трейсов через Grafana
В Grafana источник данных Loki настраивается с derivedFields, которые превращают trace_id в кликабельную ссылку в Tempo. Источник Tempo настраивается с traceToLogs, чтобы из трейса открывался связанный лог. Это даёт сквозную навигацию: метрика → лог → трейс.
Подводные камни
- Cardinality взрывается — метки с высокой уникальностью (user_id, request_id в label) уничтожают Prometheus; такие значения должны быть в exemplars или логах, не в метках.
- Promtail пропускает логи при ротации файлов — нужно настроить
fileGlobbingи убедиться, чтоhostPathмонтирует/var/log/pods. - Tempo без объектного хранилища не масштабируется — для production нужен S3/GCS бэкенд, иначе при перезапуске трейсы теряются.
- kube-state-metrics и node-exporter уже включены в kube-prometheus-stack — не надо их ставить отдельно, иначе будет дублирование метрик и конфликты портов.
- Retention Prometheus vs. Thanos/Cortex — нативный Prometheus не масштабируется горизонтально; для долгосрочного хранения нужен Thanos sidecar или VictoriaMetrics.
- OTel Collector bottleneck — при высокой нагрузке один DaemonSet-экземпляр может стать узким местом; надо настраивать
batchprocessor и limits по памяти. - Алерты без runbook бесполезны — каждый alert должен иметь аннотацию
runbook_url, иначе on-call инженер не знает что делать.
Common mistakes
- Сводить observability к logs
- Не упоминать SLO
- Игнорировать cardinality и retention
What the interviewer is testing
- Покрывает metrics/logs/traces
- Знает Kubernetes sources
- Говорит про alerts и runbooks