Skip to content

Gateway on Kubernetes — Deploying API Gateways in Container Orchestration

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you'll learn about Gateway Kubernetes. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Deploying an API Gateway on Kubernetes provides automatic scaling, self-healing, rolling updates, and service discovery, making it the ideal platform for production gateway deployments.

What You'll Learn

By the end of this lesson, you will create Kubernetes Deployment and Service manifests for the gateway, configure ConfigMaps and Secrets, set up Horizontal Pod Autoscaler, and implement zero-downtime rolling updates.

Why It Matters

Kubernetes automates the operational overhead of running gateway instances, allowing you to focus on configuration and optimization rather than infrastructure management.

Real-World Use

Durga Antivirus Pro runs its gateway on Kubernetes with 5 replicas, auto-scaling to 20 during peak hours, and rolling updates that replace instances without dropping connections.

Kubernetes Gateway Architecture

flowchart TD
    Internet-->Ingress[Kubernetes Ingress]
    Ingress-->Service[Gateway Service]
    Service-->Pod1[Gateway Pod 1]
    Service-->Pod2[Gateway Pod 2]
    Service-->Pod3[Gateway Pod 3]
    Pod1-->Config[ConfigMap]
    Pod2-->Config
    Pod3-->Config
    Pod1-->HPA[Horizontal Pod Autoscaler]
    Pod2-->HPA
    Pod3-->HPA

Deployment Manifest

Create a Kubernetes Deployment for the gateway.

from typing import Dict, List, Optional
import json

class K8sDeployment:
    def __init__(self, name: str, image: str,
                 replicas: int = 3,
                 namespace: str = "default"):
        self.name = name
        self.image = image
        self.replicas = replicas
        self.namespace = namespace
        self.env_vars: Dict[str, str] = {}
        self.ports: List[Dict] = []
        self.resources: Dict = {}
        self.probes: Dict = {}
        self.config_maps: List[str] = []
        self.secrets: List[str] = []

    def add_env(self, key: str, value: str):
        self.env_vars[key] = value

    def add_port(self, container_port: int,
                 name: str = "http"):
        self.ports.append({
            "containerPort": container_port,
            "name": name
        })

    def set_resources(self, requests: Dict,
                      limits: Dict):
        self.resources = {
            "requests": requests,
            "limits": limits
        }

    def set_health_probe(self, path: str,
                         port: int = 8080,
                         delay: int = 5):
        self.probes = {
            "livenessProbe": {
                "httpGet": {"path": path, "port": port},
                "initialDelaySeconds": delay,
            },
            "readinessProbe": {
                "httpGet": {"path": path, "port": port},
                "initialDelaySeconds": delay,
            }
        }

    def use_config_map(self, name: str):
        self.config_maps.append(name)

    def use_secret(self, name: str):
        self.secrets.append(name)

    def to_yaml(self) -> str:
        spec = {
            "apiVersion": "apps/v1",
            "kind": "Deployment",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace,
                "labels": {"app": self.name}
            },
            "spec": {
                "replicas": self.replicas,
                "selector": {
                    "matchLabels": {"app": self.name}
                },
                "template": {
                    "metadata": {
                        "labels": {"app": self.name}
                    },
                    "spec": {
                        "containers": [{
                            "name": self.name,
                            "image": self.image,
                            "ports": self.ports,
                        }]
                    }
                }
            }
        }
        container = spec["spec"]["template"][
            "spec"]["containers"][0]
        if self.env_vars:
            container["env"] = [
                {"name": k, "value": v}
                for k, v in self.env_vars.items()
            ]
        if self.resources:
            container["resources"] = self.resources
        if self.probes:
            container.update(self.probes)
        if self.config_maps:
            container["envFrom"] = [
                {"configMapRef": {"name": cm}}
                for cm in self.config_maps
            ]
        if self.secrets:
            container["envFrom"].extend([
                {"secretRef": {"name": sec}}
                for sec in self.secrets
            ])
        import yaml
        return yaml.dump(spec, default_flow_style=False)

dep = K8sDeployment("api-gateway",
                    "dodatech/gateway:1.0.0",
                    replicas=3)
dep.add_port(8080)
dep.set_resources(
    {"cpu": "500m", "memory": "512Mi"},
    {"cpu": "2000m", "memory": "2Gi"}
)
dep.set_health_probe("/health")
dep.add_env("REDIS_URL", "redis://redis-svc:6379")
dep.use_config_map("gateway-config")
print(dep.to_yaml())

Horizontal Pod Autoscaler

Configure auto-scaling based on CPU and memory.

from typing import Dict, Optional

class K8sHPA:
    def __init__(self, name: str,
                 deployment: str,
                 min_replicas: int = 3,
                 max_replicas: int = 50,
                 namespace: str = "default"):
        self.name = name
        self.deployment = deployment
        self.min_replicas = min_replicas
        self.max_replicas = max_replicas
        self.namespace = namespace
        self.metrics: list = []

    def add_cpu_metric(self,
                       target_utilization: int = 70):
        self.metrics.append({
            "type": "Resource",
            "resource": {
                "name": "cpu",
                "target": {
                    "type": "Utilization",
                    "averageUtilization": target_utilization
                }
            }
        })

    def add_memory_metric(self,
                          target_utilization: int = 80):
        self.metrics.append({
            "type": "Resource",
            "resource": {
                "name": "memory",
                "target": {
                    "type": "Utilization",
                    "averageUtilization": target_utilization
                }
            }
        })

    def to_yaml(self) -> str:
        spec = {
            "apiVersion": "autoscaling/v2",
            "kind": "HorizontalPodAutoscaler",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "spec": {
                "scaleTargetRef": {
                    "apiVersion": "apps/v1",
                    "kind": "Deployment",
                    "name": self.deployment
                },
                "minReplicas": self.min_replicas,
                "maxReplicas": self.max_replicas,
                "metrics": self.metrics,
            }
        }
        import yaml
        return yaml.dump(spec, default_flow_style=False)

hpa = K8sHPA("gateway-hpa", "api-gateway",
             min_replicas=3, max_replicas=20)
hpa.add_cpu_metric(70)
hpa.add_memory_metric(80)
print(hpa.to_yaml())

ConfigMap and Secret Management

Store gateway configuration in Kubernetes-native resources.

from typing import Dict, Optional
import base64

class K8sConfigMap:
    def __init__(self, name: str,
                 namespace: str = "default"):
        self.name = name
        self.namespace = namespace
        self.data: Dict[str, str] = {}

    def add(self, key: str, value: str):
        self.data[key] = value

    def load_from_file(self, key: str,
                       filepath: str):
        with open(filepath) as f:
            self.data[key] = f.read()

    def to_yaml(self) -> str:
        spec = {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "data": self.data
        }
        import yaml
        return yaml.dump(spec, default_flow_style=False)

class K8sSecret:
    def __init__(self, name: str,
                 namespace: str = "default"):
        self.name = name
        self.namespace = namespace
        self.data: Dict[str, str] = {}

    def add(self, key: str, value: str):
        self.data[key] = base64.b64encode(
            value.encode()
        ).decode()

    def to_yaml(self) -> str:
        spec = {
            "apiVersion": "v1",
            "kind": "Secret",
            "metadata": {
                "name": self.name,
                "namespace": self.namespace
            },
            "type": "Opaque",
            "data": self.data
        }
        import yaml
        return yaml.dump(spec, default_flow_style=False)

cm = K8sConfigMap("gateway-config")
cm.add("RATE_LIMIT", "100")
cm.add("LOG_LEVEL", "info")
secret = K8sSecret("gateway-secret")
secret.add("JWT_SECRET", "my-super-secret-key")
print("ConfigMap and Secret created")

Common Mistakes

Mistake 1: Not Setting Resource Limits

Without resource limits, a single gateway pod can starve other pods on the same node.

Mistake 2: Missing Health Probes

Without liveness and readiness probes, Kubernetes cannot detect and restart unhealthy pods.

Mistake 3: Ingress Routing Conflicts

Multiple Ingress resources with overlapping paths cause routing issues. Keep Ingress rules simple.

Mistake 4: ConfigMap Updates Without Restart

ConfigMap changes are not automatically picked up. Use a reloader or restart pods on config change.

Mistake 5: No Pod Anti-Affinity

Without anti-affinity, pods may all run on the same node, defeating high availability.

Practice Questions

  1. Why use a Kubernetes Service in front of the gateway Deployment?
  2. How do liveness and readiness probes differ?
  3. What is the role of the Horizontal Pod Autoscaler?
  4. How do you update gateway configuration without downtime?
  5. What is pod anti-affinity and why is it important?

Challenge

Build a complete Kubernetes deployment for the gateway that includes a Deployment with 3 replicas, a Service of type ClusterIP, a ConfigMap for rate limit and log level configuration, a Secret for JWT signing keys, a HorizontalPodAutoscaler scaling on CPU at 70 percent, and liveness and readiness probes on /health.

FAQ

Why deploy the gateway on Kubernetes?

Kubernetes provides automatic scaling, self-healing, rolling updates, service discovery, and centralized configuration management for gateway instances.

Should the gateway be behind a Kubernetes Ingress?

Typically yes. The Ingress handles TLS termination and domain routing before traffic reaches the gateway. The gateway then handles API-specific concerns.

How do you scale the gateway on Kubernetes?

Use HorizontalPodAutoscaler based on CPU and memory utilization. The gateway is stateless (with Redis for shared state), making it ideal for horizontal scaling.

How do you handle rolling updates for the gateway?

Kubernetes rolling updates gradually replace pods, keeping the gateway available throughout. Configure maxSurge and maxUnavailable for zero-downtime updates.

What is the recommended resource allocation per gateway pod?

Start with 500m CPU and 512MB memory per pod. Monitor usage and adjust. Typical production gateways run with 1-2 CPU and 1-2GB memory.

Mini Project

Build a complete Kubernetes deployment for the gateway consisting of a Deployment (3 replicas, resource limits, health probes), a Service (ClusterIP, port 8080), a ConfigMap for configuration, a Secret for secrets, and a HorizontalPodAutoscaler (3-20 replicas, CPU at 70 percent).

What's Next

Learn about Gateway Service Mesh for advanced traffic management, or explore Gateway Scaling for scaling strategies.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro