deploying-kafka-k8s
Deploys Apache Kafka on Kubernetes using the Strimzi operator with KRaft mode. Use when setting up Kafka for event-driven microservices, message queuing, or pub/sub patterns. Covers operator installation, cluster creation, topic management, and producer/consumer testing. NOT when using managed Kafka (Confluent Cloud, MSK) or local development without K8s.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/deploying-kafka-k8s/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How deploying-kafka-k8s Compares
| Feature / Agent | deploying-kafka-k8s | Standard Approach |
|---|---|---|
| Platform Support | multi | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Deploys Apache Kafka on Kubernetes using the Strimzi operator with KRaft mode. Use when setting up Kafka for event-driven microservices, message queuing, or pub/sub patterns. Covers operator installation, cluster creation, topic management, and producer/consumer testing. NOT when using managed Kafka (Confluent Cloud, MSK) or local development without K8s.
Which AI agents support this skill?
This skill is compatible with multi.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Deploying Kafka on Kubernetes
Deploy production-ready Apache Kafka clusters using Strimzi operator (v0.49.1+) with KRaft mode.
## Quick Start
```bash
# 1. Create namespace
kubectl create namespace kafka
# 2. Install Strimzi operator
kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka
# 3. Wait for operator
kubectl wait deployment/strimzi-cluster-operator --for=condition=Available -n kafka --timeout=300s
# 4. Deploy Kafka cluster
kubectl apply -f https://strimzi.io/examples/latest/kafka/kraft/kafka-single-node.yaml -n kafka
# 5. Wait for ready
kubectl wait kafka/my-cluster --for=condition=Ready --timeout=300s -n kafka
```
## Strimzi Operator Installation
### Standard Install (Cluster-wide)
```bash
kubectl create namespace kafka
kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka
kubectl get pods -n kafka -w
```
### Namespace-scoped Install
```bash
# Download and modify for single namespace
curl -L https://strimzi.io/install/latest?namespace=kafka > strimzi-install.yaml
# Edit RoleBindings and ClusterRoles as needed
kubectl apply -f strimzi-install.yaml -n kafka
```
## Kafka Cluster Configurations
### Single Node (Development)
```yaml
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: my-cluster
namespace: kafka
spec:
kafka:
version: 3.9.0
replicas: 1
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9093
type: internal
tls: true
config:
offsets.topic.replication.factor: 1
transaction.state.log.replication.factor: 1
transaction.state.log.min.isr: 1
default.replication.factor: 1
min.insync.replicas: 1
storage:
type: ephemeral
entityOperator:
topicOperator: {}
userOperator: {}
```
### Production Cluster (3 Nodes + KRaft)
```yaml
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-production
namespace: kafka
spec:
kafka:
version: 3.9.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9093
type: internal
tls: true
- name: external
port: 9094
type: nodeport
tls: false
config:
offsets.topic.replication.factor: 3
transaction.state.log.replication.factor: 3
transaction.state.log.min.isr: 2
default.replication.factor: 3
min.insync.replicas: 2
inter.broker.protocol.version: "3.9"
storage:
type: jbod
volumes:
- id: 0
type: persistent-claim
size: 100Gi
deleteClaim: false
resources:
requests:
memory: 2Gi
cpu: "500m"
limits:
memory: 4Gi
cpu: "2"
entityOperator:
topicOperator: {}
userOperator: {}
```
## Topic Management
### Create Topic via CRD
```yaml
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaTopic
metadata:
name: task-events
namespace: kafka
labels:
strimzi.io/cluster: my-cluster
spec:
partitions: 3
replicas: 1
config:
retention.ms: 604800000 # 7 days
segment.bytes: 1073741824 # 1GB
```
### List and Describe Topics
```bash
# List topics
kubectl -n kafka run kafka-topics -ti --rm --restart=Never \
--image=quay.io/strimzi/kafka:0.49.1-kafka-3.9.0 -- \
bin/kafka-topics.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 --list
# Describe topic
kubectl -n kafka run kafka-topics -ti --rm --restart=Never \
--image=quay.io/strimzi/kafka:0.49.1-kafka-3.9.0 -- \
bin/kafka-topics.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 \
--describe --topic task-events
```
## Producer/Consumer Testing
### Console Producer
```bash
kubectl -n kafka run kafka-producer -ti --rm --restart=Never \
--image=quay.io/strimzi/kafka:0.49.1-kafka-3.9.0 -- \
bin/kafka-console-producer.sh \
--bootstrap-server my-cluster-kafka-bootstrap:9092 \
--topic my-topic
```
### Console Consumer
```bash
kubectl -n kafka run kafka-consumer -ti --rm --restart=Never \
--image=quay.io/strimzi/kafka:0.49.1-kafka-3.9.0 -- \
bin/kafka-console-consumer.sh \
--bootstrap-server my-cluster-kafka-bootstrap:9092 \
--topic my-topic --from-beginning
```
## Service Discovery
Kafka bootstrap services for client connections:
| Service | Port | Use |
|---------|------|-----|
| `my-cluster-kafka-bootstrap:9092` | Plain | Internal cluster apps |
| `my-cluster-kafka-bootstrap:9093` | TLS | Secure internal apps |
| `my-cluster-kafka-0.my-cluster-kafka-brokers:9092` | Plain | Direct broker access |
### Connect from Another Namespace
```yaml
# In your app deployment
env:
- name: KAFKA_BOOTSTRAP_SERVERS
value: "my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092"
```
## Monitoring
### Enable Prometheus Metrics
```yaml
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: my-cluster
spec:
kafka:
metricsConfig:
type: jmxPrometheusExporter
valueFrom:
configMapKeyRef:
name: kafka-metrics
key: kafka-metrics-config.yml
```
### Check Cluster Status
```bash
kubectl get kafka -n kafka
kubectl describe kafka my-cluster -n kafka
kubectl get pods -n kafka -l strimzi.io/cluster=my-cluster
```
## Troubleshooting
### Operator Not Starting
```bash
kubectl logs deployment/strimzi-cluster-operator -n kafka
kubectl describe pod -l name=strimzi-cluster-operator -n kafka
```
### Kafka Pods Not Ready
```bash
kubectl describe pod my-cluster-kafka-0 -n kafka
kubectl logs my-cluster-kafka-0 -n kafka
kubectl get events -n kafka --sort-by='.lastTimestamp'
```
### Common Issues
| Error | Cause | Fix |
|-------|-------|-----|
| PVC pending | No storage class | Add `storageClassName` or use ephemeral |
| Pods OOMKilled | Insufficient memory | Increase resource limits |
| Connection refused | Wrong bootstrap URL | Use `cluster-kafka-bootstrap:9092` |
## Cleanup
```bash
# Delete cluster
kubectl -n kafka delete kafka my-cluster
# Delete PVCs (data)
kubectl delete pvc -l strimzi.io/name=my-cluster-kafka -n kafka
# Remove operator
kubectl -n kafka delete -f 'https://strimzi.io/install/latest?namespace=kafka'
# Delete namespace
kubectl delete namespace kafka
```
## Integration with Dapr
For Dapr pub/sub integration, see `configuring-dapr-pubsub` skill:
```yaml
# Dapr component pointing to Strimzi Kafka
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: kafka-pubsub
spec:
type: pubsub.kafka
metadata:
- name: brokers
value: "my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092"
- name: authType
value: "none"
```
## Verification
Run: `python scripts/verify.py`
## Related Skills
- `operating-k8s-local` - Local Minikube cluster setup
- `configuring-dapr-pubsub` - Dapr Kafka pub/sub integration
- `scaffolding-fastapi-dapr` - FastAPI services with Kafka events