Skip to main content

Strimzi Kafka Backup: How to Back Up Kafka on Kubernetes

· 11 min read
OSO Engineering
The team behind OSO Kafka Backup

Strimzi Kafka backup is the piece Strimzi deliberately leaves to you. Strimzi manages the lifecycle of Kafka on Kubernetes — brokers, topics, users, certificates — but it does not back up the message data inside your topics. Re-applying your Kafka and KafkaTopic resources rebuilds an empty cluster, not your data.

This guide maps what Strimzi protects and what it does not, explains why volume snapshots are not a substitute, and walks through the declarative alternative: a Strimzi-native operator that runs backups and restores as custom resources next to your Kafka CR.

Key takeaway

Strimzi's custom resources are a recoverable definition of your cluster, not of your data. Topic messages and consumer group offsets need their own backup path. The Strimzi Backup Operator declares that path as KafkaBackup and KafkaRestore resources, resolved directly from your Strimzi configuration.

What Strimzi protects — and what it doesn't

Strimzi's operators reconcile the definition of your cluster. The Kafka, KafkaTopic, and KafkaUser custom resources live in Git, and re-applying them recreates brokers, topic configurations, and users exactly as declared. For the control plane, GitOps really is your recovery story.

The data plane is different. No custom resource contains your messages. If a topic is deleted, corrupted by a bad deploy, or purged by a misconfigured retention policy, re-applying YAML brings back the topic — empty. Consumer group offsets disappear with it, so even applications that could reprocess data no longer know where to start.

Replication does not close this gap. A replication factor of 3 keeps the cluster available when a broker dies, but it also copies every bad write, bad delete, and application bug to all three replicas within milliseconds. Replication is availability; backup is the ability to go back.

AssetRecovered by re-applying CRs?Needs a backup?
Cluster definition (Kafka CR)YesKeep it in Git
Topic configurations (KafkaTopic)YesKeep them in Git
Users and ACLs (KafkaUser)Yes (credentials are re-issued)Keep them in Git
Topic message dataNoYes
Consumer group offsetsNoYes

If you use Schema Registry alongside Strimzi, its schemas are a further asset with the same problem. Schema Registry sync is an Enterprise capability of OSO Kafka Backup.

Why PV snapshots are not a Kafka backup

The first idea most teams reach for on Kubernetes is snapshotting the broker PersistentVolumes. It feels natural — it works for databases with a single writer. For Kafka it fails in ways that only show up during a restore.

Each volume snapshot is taken independently and is, at best, crash-consistent for that one broker. Kafka's state is distributed: partitions have replicas on several brokers, and each broker's snapshot captures a slightly different instant. Restore the set and the replicas disagree with each other about offsets and high watermarks — a state no healthy cluster ever passes through.

Granularity is the other problem. A volume snapshot is all-or-nothing per broker. There is no way to restore one deleted topic, one consumer group, or the state as of 14:03 yesterday without rolling every partition on that volume back with it.

CapabilityPV snapshotsMirrorMaker 2Connect S3 sinkStrimzi Backup Operator
Restore a single topicNoNoNo first-class pathYes (topics.include)
Consumer group offsetsEntangled with volume stateTranslated, not restorableNot capturedBacked up and restored
Point-in-time recoverySnapshot instants onlyNoNoYes
Protects against bad deletesWhole-volume rollback onlyNo — deletes replicateArchive only, no replayYes
Declared as Kubernetes resourcesVia CSI, per volumeVia KafkaMirrorMaker2 CRConnector JSONKafkaBackup / KafkaRestore CRs

MirrorMaker 2 and S3 sink archives each solve a different problem — replication and analytics archiving respectively. The Kafka backup strategies pillar covers those boundaries in depth, and the S3 sink guide explains why an archive has no path back into Kafka.

The Strimzi Backup Operator: strimzi kafka backup as a custom resource

The Strimzi Backup Operator is a Strimzi-native Kubernetes operator for exactly this job. It adds two CRDs in the kafkabackup.com/v1alpha1 API group: KafkaBackup backs up topics from a Strimzi cluster to S3, Azure Blob, GCS, or filesystem storage, one-shot or on a cron schedule. KafkaRestore restores a backup with topic selection, renaming, and point-in-time recovery. The current release is v0.2.17, and its default Job image is osodevops/kafka-backup:v0.15.11.

The Strimzi-native part is what removes the usual wiring. You point the resource at your Strimzi cluster with strimziClusterRef, and the operator resolves bootstrap servers, the cluster CA certificate, and KafkaUser credentials directly from your Strimzi custom resources. No bootstrap addresses or TLS material configured by hand, and no credentials copied into a second place that can drift.

Every backup and restore runs as a Kubernetes Job executing the open source kafka-backup CLI, so runs are inspectable with standard tooling — kubectl get jobs,pods shows exactly what executed and when.

One boundary to get right: this operator is purpose-built for Strimzi-managed clusters. If your Kafka runs outside Strimzi — MSK, Confluent, or self-managed — use the generic OSO Kafka Backup Operator (kafka.oso.sh/v1alpha1) instead. The Kubernetes backup solution page covers that pattern.

Install and schedule your first backup

Install the operator from the OSO DevOps Helm repository:

helm repo add oso-devops https://osodevops.github.io/helm-charts/
helm repo update

helm install strimzi-backup-operator oso-devops/strimzi-backup-operator \
--namespace kafka \
--create-namespace \
--version 0.2.17

When upgrading, apply the release CRDs before upgrading the chart. Helm installs CRDs from a chart's crds/ directory but never upgrades existing ones:

kubectl apply -f https://github.com/osodevops/strimzi-backup-operator/releases/download/v0.2.17/crds.yaml

helm upgrade strimzi-backup-operator oso-devops/strimzi-backup-operator \
--namespace kafka \
--version 0.2.17

Then declare a scheduled backup that references your Strimzi Kafka resource:

apiVersion: kafkabackup.com/v1alpha1
kind: KafkaBackup
metadata:
name: daily-backup
namespace: kafka
spec:
strimziClusterRef:
name: my-cluster # your Strimzi Kafka CR
schedule:
cron: "0 2 * * *"
storage:
type: s3
s3:
bucket: my-kafka-backups
region: eu-west-1
accessKeySecret:
name: aws-credentials
key: access-key-id
secretKeySecret:
name: aws-credentials
key: secret-access-key
backup:
stopAtCurrentOffsets: true
metrics:
enabled: true
keepAliveSeconds: 60

The schedule.cron field turns the backup into a recurring CronJob; omit it for a one-shot run. stopAtCurrentOffsets: true makes each run a bounded snapshot: it captures the current high watermarks, backs up to that point, and exits. Storage credentials come from Kubernetes Secrets referenced by name — nothing sensitive lives in the manifest itself.

Restoring: one shot, on purpose

A restore is declared the same way, referencing the backup and selecting what to bring back:

apiVersion: kafkabackup.com/v1alpha1
kind: KafkaRestore
metadata:
name: restore-orders
namespace: kafka
spec:
strimziClusterRef:
name: my-cluster
backupRef:
name: daily-backup
backupId: backup-20260610-020000
topics:
include:
- orders-*

The semantics here are deliberately conservative. A KafkaRestore runs exactly once: the operator creates a single Job for it and never creates another, whether that Job succeeds or fails. A restore appends to the target topics, so silently re-running a partial restore could duplicate records. To run a restore again, you delete the resource and create a new one — an intentional act, visible in your Git history. This one-shot behavior is available from operator 0.2.9.

Within its single Job, pod-level retries are governed by spec.backoffLimit (available from 0.2.10), and the defaults differ for a reason:

CRDDefault backoffLimitRationale
KafkaRestore0 — exactly one attemptA retried pod re-applies a partial restore, which can duplicate records. Enable retries only when the restore is idempotent (e.g. dryRun).
KafkaBackup3Re-running a backup is safe; transient broker restarts and network blips retry automatically.

The CR status reflects the Job outcome within seconds. Restores report RestoreRunning, RestoreCompleted, or RestoreFailed; backups report the analogous BackupRunning / BackupCompleted / BackupFailed, plus status.lastBackup and status.backupHistory for completed runs:

kubectl get kafkarestore restore-orders -n kafka \
-o jsonpath='{range .status.conditions[*]}{.type}={.status} ({.reason}){"\n"}{end}'

Deleting a KafkaBackup or KafkaRestore removes everything the operator created for it — Jobs, CronJobs, generated ConfigMaps, and the Jobs' pods (from 0.2.10). To pause reconciliation temporarily, annotate the resource with Strimzi's standard strimzi.io/pause-reconciliation="true" (from 0.2.15). The restore Jobs and retry behavior reference covers all of this in detail.

Monitoring and verifying backups

The operator exposes two independent classes of metrics, and they must be scraped separately: the operator controller on :9090/metrics (via ServiceMonitor) and each backup or restore Job pod on :8080/metrics (via PodMonitor). Enabling only the ServiceMonitor does not collect backup progress — a common gap that leaves dashboards green while backups quietly stall.

The Job endpoint publishes the kafka-backup runtime metrics. The families worth alerting on:

  • kafka_backup_records_total — records backed up
  • kafka_backup_lag_records_sum — current lag summed across all partitions
  • kafka_backup_snapshot_records_remaining — records left before a bounded backup completes
  • kafka_restore_progress_percent — restore completion percentage

Use CR status for durable success and failure history. A completed one-shot Job's in-process metrics disappear when its pod exits, even when Prometheus scraped the final sample. The metrics reference documents the scrape setup, and the backup monitoring guide turns these families into alert rules.

Finally, schedule restore tests. A backup you have never restored is a hope, not a backup — the backup verification guide covers proving recoverability on a cadence, and one-shot KafkaRestore resources into a scratch namespace are a natural fit for it.

Backup that speaks Strimzi

The Strimzi Backup Operator resolves your cluster, CA certificates, and KafkaUser credentials straight from Strimzi resources — scheduled backups, point-in-time restores, and consumer group offsets included, declared in the same Git repository as your cluster. Get started with Kafka Backup.

Frequently asked questions

Does Strimzi include a backup feature for Kafka topic data?

No. Strimzi manages the cluster lifecycle — brokers, topics, users, and certificates — as Kubernetes resources, but it does not back up the message data inside topics or consumer group offsets. Re-applying your custom resources rebuilds an empty cluster. Topic data needs a separate backup tool such as the Strimzi Backup Operator.

Can I back up a Strimzi Kafka cluster with volume snapshots?

Volume snapshots are a poor fit for Kafka. Each broker volume is snapshotted independently, so the snapshots are never coordinated across brokers and restored replicas disagree about offsets. Snapshots are also all-or-nothing per volume: you cannot restore a single topic or a specific point in time.

How does the Strimzi Backup Operator authenticate to my cluster?

You reference your Strimzi Kafka resource with strimziClusterRef. The operator resolves bootstrap servers, the cluster CA certificate, and KafkaUser credentials directly from your Strimzi custom resources, so no connection or TLS material is configured by hand.

What happens if a Strimzi Kafka restore fails partway through?

A KafkaRestore runs exactly once and is not retried automatically, because re-applying a partial restore could duplicate records. The resource reports RestoreFailed in its status conditions. To try again, delete the KafkaRestore and create a new one. Pod retries can be enabled deliberately with spec.backoffLimit when the restore is idempotent.

Where can the Strimzi Backup Operator store backups?

Backups can be written to Amazon S3 and S3-compatible object stores, Azure Blob Storage, Google Cloud Storage, or filesystem storage, configured under spec.storage on the KafkaBackup resource. Credentials are referenced from Kubernetes Secrets rather than embedded in the manifest.

Wrapping up

Strimzi gives you a cluster whose definition is fully recoverable from Git — and deliberately leaves the data plane to you. Volume snapshots cannot fill that gap, because Kafka's state is distributed across brokers and a real recovery needs per-topic, point-in-time selection. The Strimzi Backup Operator closes it in the model you already run: a KafkaBackup resource next to your Kafka CR for scheduled backups, a one-shot KafkaRestore when it matters, and two Prometheus endpoints to prove both are working. Backup becomes one more resource in the repository, reviewed and versioned like everything else in the cluster.