Skip to content

Kubernetes

Run Smart Router as a horizontally-scaled Deployment with a single StatefulSet (or Deployment) backing the shared cache. Router replicas are stateless and can be scaled independently.

Topology

┌──────────────────────────────────────────────────┐
│  Service: smartrouter (ClusterIP / LoadBalancer) │
└────────────────────┬─────────────────────────────┘
   ┌─────────────────┼─────────────────┐
   ▼                 ▼                 ▼
┌────────┐       ┌────────┐       ┌────────┐
│ router │       │ router │  ...  │ router │   ← Deployment, replicas: N
└────┬───┘       └────┬───┘       └────┬───┘
     └──────────┬─────┴──────┬──────────┘
                ▼            ▼
         ┌─────────────────────────┐
         │  Service: smartrouter-  │
         │     cache (ClusterIP)   │
         └────────────┬────────────┘
                  ┌────────┐
                  │ cache  │   ← StatefulSet or Deployment, replicas: 1
                  └────────┘

Cache StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: smartrouter-cache
spec:
  serviceName: smartrouter-cache
  replicas: 1
  selector: { matchLabels: { app: smartrouter-cache } }
  template:
    metadata: { labels: { app: smartrouter-cache } }
    spec:
      containers:
        - name: cache
          image: ghcr.io/magma-devs/smart-router:latest
          args: ["cache", "--port", "7778"]
          ports:
            - { name: cache, containerPort: 7778 }
          resources:
            requests: { cpu: 250m, memory: 256Mi }
            limits:   { cpu: "1",   memory: 1Gi }
---
apiVersion: v1
kind: Service
metadata:
  name: smartrouter-cache
spec:
  selector: { app: smartrouter-cache }
  ports:
    - { name: cache, port: 7778, targetPort: 7778 }
  clusterIP: None  # headless

Router Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: smartrouter
spec:
  replicas: 3
  selector: { matchLabels: { app: smartrouter } }
  template:
    metadata: { labels: { app: smartrouter } }
    spec:
      containers:
        - name: router
          image: ghcr.io/magma-devs/smart-router:latest
          args:
            - rpcsmartrouter
            - /etc/smartrouter/config.yml
            - --geolocation=1
            - --use-static-spec=/etc/smartrouter/specs/
            - --cache-be=smartrouter-cache:7778
            - --log_level=info
          ports:
            - { name: rpc,     containerPort: 3360 }
            - { name: metrics, containerPort: 7779 }
          volumeMounts:
            - { name: config, mountPath: /etc/smartrouter, readOnly: true }
          resources:
            requests: { cpu: 500m, memory: 512Mi }
            limits:   { cpu: "2",  memory: 2Gi }
          readinessProbe:
            tcpSocket: { port: rpc }
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            tcpSocket: { port: rpc }
            initialDelaySeconds: 30
            periodSeconds: 30
      volumes:
        - name: config
          projected:
            sources:
              - configMap: { name: smartrouter-config }
              - configMap: { name: smartrouter-specs }
---
apiVersion: v1
kind: Service
metadata:
  name: smartrouter
spec:
  selector: { app: smartrouter }
  ports:
    - { name: rpc,     port: 80,   targetPort: 3360 }
    - { name: metrics, port: 7779, targetPort: 7779 }

ConfigMaps

Treat the router YAML and the specs/ directory as configuration:

kubectl create configmap smartrouter-config \
  --from-file=config.yml=./config/smartrouter_examples/smartrouter_eth.yml

kubectl create configmap smartrouter-specs \
  --from-file=specs=./specs/

Secrets

If your upstream URLs include API keys, put them in Secrets and reference them via env-var substitution in the YAML, or use a secret-aware config-rendering step in your pipeline.

Horizontal autoscaling

Router replicas are stateless — HorizontalPodAutoscaler works:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: smartrouter }
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: smartrouter
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } }

The cache is not autoscaled — it's a single replica. If you outgrow one cache instance, see Cache → Shared state.

Observability

Annotate the router pods so Prometheus scrapes them:

metadata:
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "7779"
    prometheus.io/path: "/metrics"

For OpenTelemetry tracing, set the standard OTel env vars (OTEL_EXPORTER_OTLP_ENDPOINT, etc.) on the router container.

Rollouts

The router supports zero-downtime rolling updates. Default RollingUpdate strategy with maxUnavailable: 0 and a generous terminationGracePeriodSeconds (60s) lets in-flight relays drain before the pod exits.