K8s by Example: Ambassador Pattern

The ambassador pattern uses a proxy container to broker connections between your application and external services. The app connects to localhost; the ambassador handles service discovery, sharding, load balancing, or protocol translation. Use for: database sharding, service brokering, A/B testing, circuit breaking.

ambassador-redis-shard.yaml

A Redis sharding ambassador. The app connects to localhost:6379 thinking it’s a single Redis instance. The twemproxy ambassador distributes keys across multiple Redis shards automatically.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-redis
spec:
  containers:
    - name: app
      image: my-app:v1
      env:
        - name: REDIS_HOST
          value: "localhost"
        - name: REDIS_PORT
          value: "6379"

The twemproxy ambassador listens on localhost:6379 and routes requests to the appropriate Redis shard based on key hashing. The app code doesn’t need sharding logic.

    - name: redis-ambassador
      image: ganomede/twemproxy:latest
      ports:
        - containerPort: 6379
      volumeMounts:
        - name: twemproxy-config
          mountPath: /etc/nutcracker
  volumes:
    - name: twemproxy-config
      configMap:
        name: twemproxy-config
twemproxy-config.yaml

Twemproxy configuration defines the sharding strategy. ketama uses consistent hashing so adding/removing shards minimizes key redistribution. Each server gets traffic based on key hash.

apiVersion: v1
kind: ConfigMap
metadata:
  name: twemproxy-config
data:
  nutcracker.yaml: |
    redis:
      listen: 127.0.0.1:6379
      hash: fnv1a_64
      distribution: ketama
      auto_eject_hosts: true
      redis: true
      timeout: 400
      servers:
        - redis-shard-0.redis:6379:1
        - redis-shard-1.redis:6379:1
        - redis-shard-2.redis:6379:1
ambassador-service-broker.yaml

A service broker ambassador handles service discovery across environments. In dev, it connects to a local database; in prod, to a managed cloud service. The app always connects to localhost.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-db
spec:
  containers:
    - name: app
      image: my-app:v1
      env:
        - name: DATABASE_HOST
          value: "localhost"
        - name: DATABASE_PORT
          value: "5432"
    - name: db-ambassador
      image: haproxy:2.9
      volumeMounts:
        - name: haproxy-config
          mountPath: /usr/local/etc/haproxy
  volumes:
    - name: haproxy-config
      configMap:
        name: db-ambassador-config
ambassador-experiment.yaml

An A/B testing ambassador splits traffic between production and experimental backends. 90% goes to prod, 10% to experiment. IP hashing ensures user session consistency.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-experiment
data:
  nginx.conf: |
    upstream backend {
      ip_hash;
      server web-prod:80 weight=9;
      server web-experiment:80 weight=1;
    }
    server {
      listen 80;
      location / {
        proxy_pass http://backend;
      }
    }
---
apiVersion: v1
kind: Pod
metadata:
  name: app-with-experiment
spec:
  containers:
    - name: app
      image: my-frontend:v1
    - name: traffic-splitter
      image: nginx:alpine
      volumeMounts:
        - name: nginx-conf
          mountPath: /etc/nginx/conf.d
  volumes:
    - name: nginx-conf
      configMap:
        name: nginx-experiment
ambassador-circuit-breaker.yaml

A circuit breaker ambassador (Envoy) protects the app from cascading failures. If the backend fails repeatedly, the circuit opens and returns errors immediately without waiting.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-circuit-breaker
spec:
  containers:
    - name: app
      image: my-app:v1
      env:
        - name: BACKEND_URL
          value: "http://localhost:8001"
    - name: envoy-ambassador
      image: envoyproxy/envoy:v1.28-latest
      ports:
        - containerPort: 8001
      volumeMounts:
        - name: envoy-config
          mountPath: /etc/envoy
      command: ["envoy", "-c", "/etc/envoy/envoy.yaml"]
  volumes:
    - name: envoy-config
      configMap:
        name: envoy-circuit-breaker
terminal

Debug ambassadors by checking their logs and connectivity. The app sees only localhost; the ambassador handles the complexity of multiple backends, failover, and load distribution.

$ kubectl logs app-with-redis -c redis-ambassador
nutcracker: started on pid 1
nutcracker: listening on 127.0.0.1:6379

$ kubectl exec app-with-redis -c app -- redis-cli -h localhost ping
PONG

$ kubectl exec app-with-redis -c app -- redis-cli -h localhost set foo bar
OK

$ kubectl exec app-with-redis -c app -- redis-cli -h localhost get foo
bar

Index | GitHub | Use arrow keys to navigate |