Pavan Rangani

HomeBlogKubernetes 1.32: Gateway API and Sidecar Containers in Production

Kubernetes 1.32: Gateway API and Sidecar Containers in Production

By Pavan Rangani · February 19, 2026 · DevOps & Cloud

Kubernetes 1.32: Gateway API and Sidecar Containers in Production

Kubernetes Gateway API: The Modern Replacement for Ingress

Kubernetes Ingress has been the standard for routing external traffic to services for years, but it has fundamental limitations — no support for TCP/UDP routing, no standard way to split traffic, and vendor-specific annotations for anything beyond basic HTTP routing. Kubernetes Gateway API replaces Ingress with an expressive, role-oriented, and portable API for traffic management. Therefore, this guide covers the Gateway API, sidecar containers GA in Kubernetes 1.32, and how they integrate with service mesh architectures.

Why Ingress Needed Replacing

Ingress resources in Kubernetes are deceptively simple. A basic Ingress routes HTTP traffic by hostname and path. The moment you need anything more — header-based routing, request mirroring, canary deployments, rate limiting, or mutual TLS — you reach for vendor-specific annotations. An Ingress for NGINX looks completely different from one for Traefik or AWS ALB. Moreover, there is no standard way to configure TCP/UDP routing, gRPC load balancing, or traffic splitting.

The result: infrastructure teams create Ingress templates with 20+ annotations, each specific to their controller. Migrating from one controller to another means rewriting every Ingress resource. The Gateway API solves this by making advanced routing features part of the standard API instead of relegating them to annotations.

Consider what an annotation-driven canary actually costs you in operational terms. The routing intent lives in free-form strings that the API server never validates, so a typo in nginx.ingress.kubernetes.io/canary-weight silently does nothing until someone notices traffic isn’t splitting. There is no schema, no kubectl explain, and no portability. Because the behavior is implemented entirely inside the controller, two clusters running different controller versions can interpret the same manifest differently. The Gateway API moves all of this into typed, versioned fields that the API server validates at admission time, which turns silent misconfiguration into an immediate rejection.

Gateway API Architecture: Roles and Resources

The Gateway API introduces three resource types that separate concerns by role:

# 1. GatewayClass — Infrastructure provider (managed by cluster operator)
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: production-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  description: "Production traffic gateway using Envoy"
---

# 2. Gateway — Infrastructure instance (managed by cluster operator)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production
  namespace: gateway-system
spec:
  gatewayClassName: production-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-cert
            kind: Secret
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"
    - name: http
      protocol: HTTP
      port: 80
---

# 3. HTTPRoute — Traffic rules (managed by application teams)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: order-service
  namespace: orders
spec:
  parentRefs:
    - name: production
      namespace: gateway-system
  hostnames:
    - "api.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/orders
          headers:
            - name: x-api-version
              value: "v2"
      backendRefs:
        - name: order-service-v2
          port: 8080
          weight: 90
        - name: order-service-v3
          port: 8080
          weight: 10   # 10% canary traffic to v3
    - matches:
        - path:
            type: PathPrefix
            value: /api/orders
      backendRefs:
        - name: order-service-v2
          port: 8080

This separation is powerful. The infrastructure team manages GatewayClass and Gateway resources — they control which ports are open, which TLS certificates are used, and which namespaces can attach routes. Application teams manage HTTPRoute resources in their own namespaces — they control routing rules, traffic splitting, and backend selection. Neither team needs to understand the other’s domain. Additionally, no vendor-specific annotations are needed; traffic splitting, header-based routing, and path matching are all part of the standard API.

The allowedRoutes field is the security boundary that makes this delegation safe. Without it, any namespace could attach a route to your production listener and hijack a hostname. By gating attachment behind a label selector, the platform team decides exactly which workloads are permitted to receive internet traffic. The relationship is reciprocal: a route declares its intended parent through parentRefs, and the Gateway only accepts it if its own policy allows that namespace. You can observe the negotiated state on each route’s status.parents conditions, where an Accepted: False condition tells you precisely why a binding was rejected — a far better debugging experience than staring at an Ingress controller log.

Kubernetes Gateway API traffic management
Gateway API separates infrastructure concerns from application routing through role-based resource ownership

Advanced Routing: What Gateway API Enables

Gateway API supports routing patterns that required custom annotations or CRDs with Ingress:

# Traffic mirroring: send a copy of traffic to a test service
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: order-service-mirror
spec:
  parentRefs:
    - name: production
      namespace: gateway-system
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/orders
      backendRefs:
        - name: order-service
          port: 8080
      filters:
        - type: RequestMirror
          requestMirror:
            backendRef:
              name: order-service-canary
              port: 8080

---
# gRPC routing (GRPCRoute resource)
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-services
spec:
  parentRefs:
    - name: production
      namespace: gateway-system
  rules:
    - matches:
        - method:
            service: orders.OrderService
            method: CreateOrder
      backendRefs:
        - name: order-grpc-service
          port: 9090
    - matches:
        - method:
            service: payments.PaymentService
      backendRefs:
        - name: payment-grpc-service
          port: 9090

---
# TCP routing (TCPRoute for non-HTTP protocols)
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: postgres-route
spec:
  parentRefs:
    - name: internal-gateway
      sectionName: postgres
  rules:
    - backendRefs:
        - name: postgres-primary
          port: 5432

Request mirroring, gRPC routing, TCP/UDP routing, and weighted traffic splitting are all standard resources with the Gateway API. Consequently, you can switch from Envoy Gateway to Istio Gateway to Contour without rewriting your routing rules — they all implement the same API.

Filters, Timeouts, and Header Manipulation

Beyond splitting traffic, real production routes need to reshape requests on the way through. The Gateway API expresses this with a typed list of filters attached to each rule, rather than the opaque snippet annotations Ingress relied on. The most common filters rewrite paths, inject or strip headers, redirect clients, and apply per-rule timeouts — all without touching the application code behind the route.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: orders-v2-rewrite
  namespace: orders
spec:
  parentRefs:
    - name: production
      namespace: gateway-system
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v2/orders
      filters:
        # Strip the /v2 prefix before forwarding to the backend
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /orders
        # Add a header so the backend knows it came through the gateway
        - type: RequestHeaderModifier
          requestHeaderModifier:
            set:
              - name: X-Forwarded-Gateway
                value: production
            remove:
              - X-Debug-Token
      timeouts:
        request: 2s          # fail fast instead of holding connections
        backendRequest: 1500ms
      backendRefs:
        - name: order-service-v2
          port: 8080

Two details matter here. First, the timeouts stanza is a portable, first-class field — every conformant implementation must honor it, so you are no longer depending on an NGINX-specific proxy-read-timeout annotation. Second, filters execute in the order they are declared, which means a redirect filter placed before a backend reference short-circuits the request entirely. Validating filter ordering in code review prevents subtle bugs where a header you set is immediately overwritten by a later mirror or rewrite.

Sidecar Containers GA in Kubernetes 1.32

Kubernetes 1.32 promotes native sidecar containers to GA. Previously, sidecar containers (like Envoy proxies, log collectors, or secret injectors) were regular containers that happened to run alongside your application. The problem: Kubernetes treated all containers equally, so sidecars sometimes started after the application or shut down before it, causing startup failures and connection errors during shutdown.

# Native sidecar container (Kubernetes 1.32+)
apiVersion: v1
kind: Pod
metadata:
  name: order-service
spec:
  initContainers:
    # restartPolicy: Always makes this a sidecar
    - name: envoy-proxy
      image: envoyproxy/envoy:v1.31
      restartPolicy: Always    # This is the sidecar magic
      ports:
        - containerPort: 15001
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 200m
          memory: 256Mi

    - name: log-collector
      image: fluent/fluent-bit:3.0
      restartPolicy: Always
      volumeMounts:
        - name: app-logs
          mountPath: /var/log/app

  containers:
    - name: order-service
      image: myapp/order-service:v3.2
      ports:
        - containerPort: 8080
      volumeMounts:
        - name: app-logs
          mountPath: /var/log/app

With native sidecars, Kubernetes guarantees: sidecars start before application containers and stop after them, sidecar crashes trigger a restart without killing the main container, and sidecar resource usage is properly accounted for in scheduling. This matters for service mesh proxies (Envoy, Linkerd) which must be ready before the application sends traffic.

The Job case is where the old behavior hurt most. Before native sidecars, a Job pod with an Envoy sidecar would never terminate, because the proxy kept running after the main container exited and the pod stayed in Running forever. Native sidecars fix this precisely: when the last regular container finishes, the kubelet sends termination signals to the sidecars in reverse start order, so the Job completes cleanly. Pair this with a startup probe on the proxy and a preStop hook that drains in-flight connections, and you get deterministic ordering on both ends of the pod lifecycle.

Kubernetes cluster management and orchestration
Native sidecar containers guarantee startup and shutdown ordering — critical for service mesh proxies

Service Mesh Integration

The Gateway API and native sidecars converge in service mesh architectures. Istio, Linkerd, and Cilium all support Gateway API as their ingress layer. With native sidecars for proxy injection and Gateway API for routing, you get a complete traffic management stack built on Kubernetes standards rather than custom CRDs.

Istio’s ambient mode goes further by removing sidecar proxies entirely, replacing them with a per-node ztunnel proxy for L4 (mTLS, authorization) and optional waypoint proxies for L7 (HTTP routing, retries). This reduces resource overhead from ~128MB per pod to shared node-level proxies. However, ambient mode is newer and does not support all Istio features yet.

The Gateway API project also ships GAMMA, a set of conventions that let the same HTTPRoute resource describe east-west mesh traffic, not just north-south ingress. In practice this means a platform team can standardize on one routing vocabulary for both the cluster edge and service-to-service calls, with the mesh implementation deciding whether to enforce a rule at a sidecar or a node-level proxy. For teams already invested in eBPF dataplanes, the same patterns apply — see the companion piece on Cilium eBPF networking for how the dataplane changes underneath these abstractions.

When NOT to Adopt It Yet — Trade-offs

This is not a free upgrade, and a few teams genuinely should wait. If your routing needs are limited to host-and-path HTTP with one well-supported controller, migrating buys you portability you may never exercise while adding three resource kinds, RBAC rules, and status conditions your on-call must learn. The cognitive surface area is real, and a small team running a handful of services often gets more value from a stable Ingress than from a richer API they barely use.

The experimental channel is another caveat. Several useful resources — TCPRoute, UDPRoute, and many policy attachments — remain in v1alpha2, which means their schemas can still change between releases and not every controller implements them. Before standardizing on a feature, check your controller’s conformance report; relying on an alpha field that your vendor only partially supports is a fast route to surprise behavior during an upgrade. Likewise, native sidecars require every node to run Kubernetes 1.29+ (where the feature went beta) and ideally 1.32 for the GA guarantees, so mixed-version clusters mid-migration can exhibit the old ordering bugs on older nodes. Adopt deliberately, gate features behind conformance, and keep Ingress as a fallback until the new path is proven for your workloads.

Migrating from Ingress to Gateway API

You do not need to migrate all at once. Gateway API and Ingress can coexist in the same cluster. Start by creating a Gateway resource, migrate one service’s routing to an HTTPRoute, verify it works, then migrate the next. Most Gateway API controllers (including NGINX Gateway Fabric and Envoy Gateway) support both Ingress and Gateway API simultaneously during migration.

A safe migration sequence keeps the old path live until the new one is proven. Stand up the Gateway on a separate hostname or a weighted DNS record, shift a small percentage of real traffic to the HTTPRoute, and watch the route’s status conditions and your error budgets before increasing the weight. Tools like ingress2gateway can mechanically translate existing Ingress objects into draft HTTPRoutes, which removes most of the tedious transcription while still leaving you to review the generated filters and timeouts. Treat the generated output as a starting point, not a finished migration. If you are weighing this work against broader spend, the trade-offs connect directly to Kubernetes cost optimization, since consolidating ingress controllers and right-sizing sidecars both move the bill.

Kubernetes networking and service mesh
Gateway API and Ingress coexist — migrate incrementally, one service at a time

Related Reading:

Resources:

In conclusion, the Kubernetes Gateway API brings standardized, role-oriented traffic management that replaces Ingress’s annotation-driven approach. Combined with native sidecar containers in Kubernetes 1.32, the platform now has proper lifecycle management for proxy containers. Migrate incrementally — start with one HTTPRoute, verify it works, and expand from there.

← Back to all articles