Advanced Event-Driven Microservices on Amazon EKS with Knative and Kafka
Introduction
Advanced Event-Driven Microservices on Amazon EKS with Knative and Kafka

Introduction
Event-driven architectures have become the backbone of modern distributed systems, but most tutorials stop at the “hello world” level. This post dives deep into production patterns, advanced configurations, and real-world challenges you’ll face when running event-driven microservices at scale.
We’ll cover:
- Advanced Knative Eventing patterns (Brokers, Triggers, Channels)
- Kafka optimization for high-throughput scenarios
- Error handling and resilience patterns
- Security hardening and multi-tenancy
- Performance tuning and resource optimization
- Production deployment strategies
Advanced Architecture Overview

Prerequisites
- Amazon EKS Cluster (v1.28+) with Fargate profiles
- Amazon MSK with SASL/SCRAM authentication
- AWS Load Balancer Controller
- External Secrets Operator
- Cert-Manager for TLS
- Container registry (ECR)
Step 1: Knative Installation
Instead of basic Helm installation, let’s use a production-ready configuration:
# knative-serving-values.yaml
config:
deployment:
progressDeadlineSeconds: 600
replicas: 3
autoscaler:
enable-scale-to-zero: "false"
scale-to-zero-grace-period: "30s"
stable-window: "60s"
panic-window: "6s"
max-scale-up-rate: "10"
max-scale-down-rate: "2"
network:
ingress-class: "kourier"
domain-template: "{{.Name}}.{{.Namespace}}.example.com"
# Install with custom configuration
helm install knative-serving knative/knative-serving \
--namespace knative-serving \
--create-namespace \
--values knative-serving-values.yaml
# Install Kourier as networking layer
kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.12.0/kourier.yaml
Step 2: Production Kafka Integration
Enhanced KafkaSource with Error Handling
apiVersion: sources.knative.dev/v1beta1
kind: KafkaSource
metadata:
name: orders-source
namespace: ecommerce
spec:
bootstrapServers:
- "b-1.orders-msk.kafka.us-east-1.amazonaws.com:9098"
topics:
- orders
- order-updates
consumerGroup: order-processing-group
net:
sasl:
enable: true
type:
secretKeyRef:
name: kafka-secret
key: sasl-type
user:
secretKeyRef:
name: kafka-secret
key: username
password:
secretKeyRef:
name: kafka-secret
key: password
tls:
enable: true
sink:
ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: order-broker
delivery:
retry: 3
backoffPolicy: exponential
backoffDelay: PT1S
deadLetterSink:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: dlq-handler
Broker Configuration
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
name: order-broker
namespace: ecommerce
annotations:
eventing.knative.dev/broker.class: MTChannelBasedBroker
spec:
config:
apiVersion: v1
kind: ConfigMap
name: broker-config
delivery:
retry: 5
backoffPolicy: exponential
backoffDelay: PT2S
---
apiVersion: v1
kind: ConfigMap
metadata:
name: broker-config
namespace: ecommerce
data:
channelTemplateSpec: |
apiVersion: messaging.knative.dev/v1
kind: KafkaChannel
spec:
numPartitions: 10
replicationFactor: 3
retentionDuration: PT168H # 7 days
Step 3: Service Patterns
High-Performance Order Processor
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: order-processor
namespace: ecommerce
annotations:
autoscaling.knative.dev/class: "kpa.autoscaling.knative.dev"
autoscaling.knative.dev/metric: "concurrency"
autoscaling.knative.dev/target: "100"
autoscaling.knative.dev/min-scale: "3"
autoscaling.knative.dev/max-scale: "50"
autoscaling.knative.dev/scale-down-delay: "30s"
autoscaling.knative.dev/window: "60s"
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/target-utilization-percentage: "70"
spec:
containerConcurrency: 1000
timeoutSeconds: 300
containers:
- name: processor
image: your-registry/order-processor:v2.1.0
ports:
- containerPort: 8080
protocol: TCP
env:
- name: KAFKA_BROKERS
valueFrom:
secretKeyRef:
name: kafka-config
key: brokers
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-config
key: url
- name: MAX_CONCURRENT_ORDERS
value: "50"
- name: PROCESSING_TIMEOUT
value: "30s"
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
Intelligent Trigger Configuration
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: payment-processing
namespace: ecommerce
spec:
broker: order-broker
filter:
attributes:
type: com.ecommerce.order.created
source: order-service
status: pending-payment
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: payment-processor
delivery:
retry: 3
backoffPolicy: exponential
backoffDelay: PT1S
deadLetterSink:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: payment-dlq-handler
---
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: inventory-check
namespace: ecommerce
spec:
broker: order-broker
filter:
attributes:
type: com.ecommerce.order.created
source: order-service
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: inventory-service
uri: /api/v1/check-inventory
Step 4: Producer Patterns

Circuit Breaker Pattern Implementation
import asyncio
import json
from kafka import KafkaProducer
from kafka.errors import KafkaError
import time
from enum import Enum
from dataclasses import dataclass
from typing import Optional
import logging
class CircuitState(Enum):
CLOSED = "closed"
OPEN = "open"
HALF_OPEN = "half_open"
@dataclass
class CircuitBreaker:
failure_threshold: int = 5
recovery_timeout: int = 60
expected_exception: tuple = (KafkaError,)
def __post_init__(self):
self.failure_count = 0
self.last_failure_time = None
self.state = CircuitState.CLOSED
class EventProducer:
def __init__(self, bootstrap_servers: str, security_config: dict):
self.producer = KafkaProducer(
bootstrap_servers=bootstrap_servers,
value_serializer=lambda v: json.dumps(v).encode('utf-8'),
key_serializer=lambda k: k.encode('utf-8') if k else None,
acks='all', # Wait for all replicas
retries=3,
batch_size=16384,
linger_ms=10,
buffer_memory=33554432,
compression_type='snappy',
max_in_flight_requests_per_connection=1, # Ensure ordering
enable_idempotence=True,
**security_config
)
self.circuit_breaker = CircuitBreaker()
self.logger = logging.getLogger(__name__)
async def send_event(self, topic: str, event: dict, key: Optional[str] = None):
if not self._can_execute():
raise Exception("Circuit breaker is OPEN")
try:
# Add CloudEvents headers
cloud_event = {
"specversion": "1.0",
"type": f"com.ecommerce.{event.get('event_type', 'unknown')}",
"source": "order-service",
"id": event.get('id'),
"time": event.get('timestamp'),
"datacontenttype": "application/json",
"data": event
}
future = self.producer.send(topic, value=cloud_event, key=key)
record_metadata = future.get(timeout=10)
self._on_success()
self.logger.info(f"Event sent to {record_metadata.topic}:{record_metadata.partition}:{record_metadata.offset}")
except Exception as e:
self._on_failure()
self.logger.error(f"Failed to send event: {e}")
raise
def _can_execute(self) -> bool:
if self.circuit_breaker.state == CircuitState.CLOSED:
return True
elif self.circuit_breaker.state == CircuitState.OPEN:
if time.time() - self.circuit_breaker.last_failure_time > self.circuit_breaker.recovery_timeout:
self.circuit_breaker.state = CircuitState.HALF_OPEN
return True
return False
else: # HALF_OPEN
return True
def _on_success(self):
self.circuit_breaker.failure_count = 0
self.circuit_breaker.state = CircuitState.CLOSED
def _on_failure(self):
self.circuit_breaker.failure_count += 1
self.circuit_breaker.last_failure_time = time.time()
if self.circuit_breaker.failure_count >= self.circuit_breaker.failure_threshold:
self.circuit_breaker.state = CircuitState.OPEN
Step 5: Security Hardening

RBAC Configuration
apiVersion: v1
kind: ServiceAccount
metadata:
name: knative-kafka-source
namespace: ecommerce
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: knative-kafka-source
namespace: ecommerce
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
- apiGroups: ["sources.knative.dev"]
resources: ["kafkasources"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: knative-kafka-source
namespace: ecommerce
subjects:
- kind: ServiceAccount
name: knative-kafka-source
namespace: ecommerce
roleRef:
kind: Role
name: knative-kafka-source
apiGroup: rbac.authorization.k8s.io
Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: knative-services-policy
namespace: ecommerce
spec:
podSelector:
matchLabels:
serving.knative.dev/service: order-processor
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: knative-serving
- namespaceSelector:
matchLabels:
name: knative-eventing
ports:
- protocol: TCP
port: 8080
egress:
- to: []
ports:
- protocol: TCP
port: 443 # HTTPS
- protocol: TCP
port: 9098 # Kafka SASL_SSL
Step 6: Performance Optimization
Resource Limits and Requests Tuning
apiVersion: v1
kind: ConfigMap
metadata:
name: config-deployment
namespace: knative-serving
data:
# Global defaults for all services
requests-cpu: "100m"
requests-memory: "128Mi"
limits-cpu: "1000m"
limits-memory: "1Gi"
# Progress deadline for deployments
progress-deadline: "600s"
# Resource quota enforcement
queue-sidecar-cpu-request: "25m"
queue-sidecar-memory-request: "50Mi"
JVM Tuning for Java Services
FROM openjdk:17-jre-slim
# JVM optimizations for containerized environments
ENV JAVA_OPTS="-XX:+UseContainerSupport \
-XX:InitialRAMPercentage=25.0 \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-XX:+UseStringDeduplication \
-XX:+OptimizeStringConcat \
-Djava.security.egd=file:/dev/./urandom"
COPY target/order-processor.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
Step 7: Advanced Error Handling

Dead Letter Queue Handler
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: dlq-handler
namespace: ecommerce
spec:
template:
spec:
containers:
- name: dlq-processor
image: your-registry/dlq-handler:latest
env:
- name: RETRY_ATTEMPTS
value: "3"
- name: BACKOFF_MULTIPLIER
value: "2"
- name: MAX_BACKOFF_SECONDS
value: "300"
ports:
- containerPort: 8080
Retry Strategy Implementation
package main
import (
"context"
"fmt"
"math"
"time"
)
type RetryConfig struct {
MaxAttempts int
BaseDelay time.Duration
MaxDelay time.Duration
BackoffExponent float64
}
func ExponentialBackoffRetry(ctx context.Context, config RetryConfig, operation func() error) error {
var lastErr error
for attempt := 0; attempt < config.MaxAttempts; attempt++ {
if attempt > 0 {
delay := time.Duration(float64(config.BaseDelay) * math.Pow(config.BackoffExponent, float64(attempt-1)))
if delay > config.MaxDelay {
delay = config.MaxDelay
}
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
}
}
if err := operation(); err != nil {
lastErr = err
fmt.Printf("Attempt %d failed: %v\n", attempt+1, err)
continue
}
return nil
}
return fmt.Errorf("operation failed after %d attempts, last error: %w", config.MaxAttempts, lastErr)
}
Conclusion
This advanced setup provides a production-ready foundation for event-driven microservices that can handle:
- High throughput: Optimized Kafka configurations and efficient resource usage
- Fault tolerance: Circuit breakers, retries, and dead letter queues
- Security: RBAC, network policies, and encrypted communication
- Scalability: Advanced autoscaling and resource optimization
- Maintainability: Clear separation of concerns and standardized patterns
The architecture supports complex event flows while maintaining loose coupling and high availability. Each component is independently scalable and can handle failures gracefully.
Key takeaways for production deployments:
- Always use structured logging and correlation IDs
- Implement proper backpressure mechanisms
- Monitor queue depths and processing latencies
- Use feature flags for gradual rollouts
- Implement comprehensive health checks
- Plan for capacity and cost optimization
This setup forms the backbone for sophisticated event-driven systems that can grow with your business needs while maintaining operational excellence.
메타데이터
- post_id
- 7d4bcf6dfeff
- slug
- advanced-event-driven-microservices-on-amazon-eks-with-knative-and-kafka-7d4bcf6dfeff
- url
- https://medium.com/@tolghn/advanced-event-driven-microservices-on-amazon-eks-with-knative-and-kafka-7d4bcf6dfeff
- canonical_url
- https://medium.com/@tolghn/advanced-event-driven-microservices-on-amazon-eks-with-knative-and-kafka-7d4bcf6dfeff
- author_url
- https://medium.com/@tolghn
- status
- ok
- fetched_at
- 2026-06-25 07:00:49