Kafka в Kubernetes с чартом Bitnami
Published: 2026-02-23
Чарт kafka от Bitnami — один из самых полных вариантов для запуска Kafka в Kubernetes. Он включает ZooKeeper как зависимый sub-chart, JMX exporter в виде sidecar-контейнера и из коробки генерирует манифесты NetworkPolicy, ServiceMonitor и PrometheusRule. Рассмотрим ключевые настройки для продакшен-деплоя.
Настройка чарта
yaml# Chart.yaml (wrapper chart)
apiVersion: v2
name: kafka
version: 0.1.0
dependencies:
- name: kafka
version: "22.x.x"
repository: "oci://registry-1.docker.io/bitnamicharts"
- condition: zookeeper.enabled
name: zookeeper
version: "11.x.x"
repository: "oci://registry-1.docker.io/bitnamicharts"
Версию чарта стоит зафиксировать в Chart.lock и закоммитить его. Плавающая версия 22.x.x подходит для helm dependency update, но воспроизводимые деплои обеспечивает именно lock-файл.
Параметры StatefulSet
yamlreplicaCount: 3
heapOpts: "-Xmx2g -Xms2g"
persistence:
enabled: true
storageClass: "yc-network-ssd"
size: 50Gi
podManagementPolicy: Parallel
resources:
requests:
cpu: 500m
memory: 3Gi
limits:
cpu: 2
memory: 4Gi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: kafka
topologyKey: kubernetes.io/hostname
Политика управления подами Parallel безопасна для Kafka — брокеры не образуют кворум при запуске (это делает ZooKeeper). Она заметно ускоряет rolling-restart на кластерах с тремя и более брокерами.
Heap JVM — примерно 75 % от лимита памяти контейнера. При лимите 4Gi настройка -Xmx2g -Xms2g оставляет 2Gi под page cache ОС, который Kafka активно использует при чтении.
podAntiAffinity гарантирует, что каждый брокер попадёт на отдельный узел. Без этого два брокера на одном узле означают потерю кворума при отказе узла.
Listeners и аутентификация
Для внутрикластерного взаимодействия используем PLAINTEXT (шифруется на сетевом уровне Cilium). Для клиентов вне namespace принудительно SASL/SCRAM:
yamlauth:
clientProtocol: sasl
interBrokerProtocol: plaintext
sasl:
mechanisms: scram-sha-256
interBrokerMechanism: plain
jaas:
clientUsers:
- app-user
- monitoring-user
clientPasswords:
- "" # подставляется через ESO; оставляем пустым
- ""
Пароли монтируются из Kubernetes Secret, создаваемого External Secrets Operator из Vault. Чарт ищет Secret kafka-jaas в том же namespace — заполняем только секрет, не values-файл.
JMX exporter sidecar
Чарт поставляет sidecar bitnami/jmx-exporter и jmx-configmap.yaml. При включении метрики брокера публикуются на порту 5556 в формате Prometheus:
yamlmetrics:
jmx:
enabled: true
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
serviceMonitor:
enabled: true
namespace: monitoring
labels:
release: kube-prometheus-stack
Ключевые метрики для мониторинга:
kafka_server_replicamanager_underreplicatedpartitions— должно быть 0kafka_controller_kafkacontroller_activecontrollercount— ровно 1 в кластереkafka_network_requestmetrics_requestspersec— паттерны трафика по типу запросовkafka_server_brokertopicmetrics_messagesinpersec— пропускная способность по топикам
PrometheusRule
yamlmetrics:
prometheusRule:
enabled: true
rules:
- alert: KafkaUnderReplicatedPartitions
expr: kafka_server_replicamanager_underreplicatedpartitions > 0
for: 10m
labels:
severity: warning
annotations:
summary: "Under-replicated partitions on {{ $labels.pod }}"
- alert: KafkaOfflinePartitions
expr: kafka_controller_kafkacontroller_offlinepartitionscount > 0
for: 5m
labels:
severity: critical
- alert: KafkaActiveControllers
expr: sum(kafka_controller_kafkacontroller_activecontrollercount) != 1
for: 5m
labels:
severity: critical
annotations:
summary: "Неправильное количество активных контроллеров Kafka"
NetworkPolicy
Чарт генерирует NetworkPolicy при networkPolicy.enabled: true. Расширяем её через additionalRules — до порта 9092 могут достучаться только нужные неймспейсы:
yamlnetworkPolicy:
enabled: true
allowExternal: false
additionalRules:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: orders
ports:
- port: 9092
protocol: TCP
Создание топиков (provisioning)
Чарт содержит Job provisioning, который запускается после готовности брокеров:
yamlprovisioning:
enabled: true
numPartitions: 6
replicationFactor: 3
topics:
- name: orders.created
partitions: 6
replicationFactor: 3
config:
retention.ms: "604800000" # 7 дней
cleanup.policy: delete
- name: payments.completed
partitions: 3
replicationFactor: 3
config:
retention.ms: "2592000000" # 30 дней
Выбор количества партиций
| Нагрузка | Партиции |
|---|---|
| < 10 МБ/с | 3 |
| 10–50 МБ/с | 6 |
| > 50 МБ/с | 12–24 |
PodDisruptionBudget
yamlpdb:
create: true
minAvailable: 2
При трёх брокерах и minAvailable: 2 Kubernetes не позволит одновременно дрейнить больше одного узла с брокером. В сочетании с offsets.topic.replication.factor=3 это гарантирует сохранность офсетов consumer groups при последовательном дрейне узлов.
Sub-chart ZooKeeper
yamlzookeeper:
enabled: true
replicaCount: 3
persistence:
enabled: true
storageClass: "yc-network-ssd"
size: 8Gi
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
cpu: 500m
memory: 1Gi
ZooKeeper должен выбрать лидера до того, как брокеры Kafka начнут регистрироваться. Если брокеры при запуске падают в CrashLoopBackOff — сначала проверьте логи ZooKeeper.
Flux HelmRelease
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: kafka
namespace: kafka
spec:
interval: 10m
chart:
spec:
chart: ./kafka
sourceRef:
kind: GitRepository
name: infra-repo
valuesFrom:
- kind: Secret
name: kafka-jaas
valuesKey: jaasPasswords
targetPath: auth.sasl.jaas.clientPasswords
values:
replicaCount: 3
valuesFrom подставляет SASL-пароли из Secret во время реконсиляции. В values-файле реального пароля нет.
Отладка
bash# Логи брокера
kubectl logs -n kafka kafka-0 -f
# Список топиков
kubectl exec -n kafka kafka-0 -- \
kafka-topics.sh --bootstrap-server localhost:9092 --list
# Under-replicated партиции
kubectl exec -n kafka kafka-0 -- \
kafka-topics.sh --bootstrap-server localhost:9092 \
--describe --under-replicated-partitions
# Лаг consumer group
kubectl exec -n kafka kafka-0 -- \
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--describe --group orders-consumer
Kafka в Kubernetes работает хорошо, если относиться к ней как к stateful-зверю: зафиксированный storage class, PDB, консервативные resource limits, pod anti-affinity и JMX-мониторинг с первого дня.