Skip to main content

Command Palette

Search for a command to run...

Gateway API: The better way to Ingress

Updated
4 min read
Gateway API: The better way to Ingress
S

I am a Kubernetes Engineer passionate about leveraging Cloud Native ecosystem to run secure, efficient and effective workloads.

Introduction

While all our existing workloads work well with Ingress and we don’t want to touch what is working just fine. Everyone have to migrate from Ingress to Gateway API at some point. I always felt that ingress is too rigid and complex with a lot of nesting YAML and bulky annotation section. Gateway API splits the responsibilities of different people in a team and dedicates a YAML component for them like “GatewayClass“, “Gateway“ and “HTTPRoute“ etc.

Why Ingress sucks?

Ingress is an initial solution to the problem where majority did not have a clarity on where the Kubernetes project is going to endup. It became GA in 1.18 which is very early into Kubernetes and also lacked lot of features natively. There are many other drawbacks with Ingress that we can discuss later

GatewayAPI

Gateway API is truly non opinionated and loosely coupled way of routing outside traffic to your services. Developer, Cluster Administrator and Infrastructure Engineer have their own tasks to do and YAMLs to manage. This enables a great support for multi-tenancy and portability from one vendor to other. Here is an example on how Envoy Gateway API can be tested.

First you need to helm install envoy gateway and CRDs

helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.5.0 -n envoy-gateway-system --create-namespace

This deploys envoy gateway deployment with following config

  ~ k get cm envoy-gateway-config -n envoy-gateway-system -o yaml 
apiVersion: v1
data:
  envoy-gateway.yaml: |
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: EnvoyGateway
    extensionApis: {}
    gateway:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
    logging:
      level:
        default: info
    provider:
      kubernetes:
        rateLimitDeployment:
          container:
            image: docker.io/envoyproxy/ratelimit:3e085e5b
          patch:
            type: StrategicMerge
            value:
              spec:
                template:
                  spec:
                    containers:
                    - imagePullPolicy: IfNotPresent
                      name: envoy-ratelimit
        shutdownManager:
          image: docker.io/envoyproxy/gateway:v1.5.0
      type: Kubernetes
kind: ConfigMap

This configuration essentially defines controllerName and images that needs to be used to for purposes of shutdown and rate limiting.

Following this, you need to install quickstart.yaml to get all the necessary components for the Gateway and application. Practically speaking, GatewayClass and Gateway will already be installed as bootstrap before applications get installed. Here is the GatewayClass and Gateway YAML files.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 80

Here in the GatewayClass, the controllerName must match with the one we have provided to EnvoyGateway. In that way, you can use different controllers for different GatewayClasses in the same cluster. The gatewayClassName in Gateway must match with the GatewayClass.

Next, installing application related components. After installing the entire quickstart.yaml, it creates below components

  ~ kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/v1.5.0/quickstart.yaml -n default

gatewayclass.gateway.networking.k8s.io/eg created
gateway.gateway.networking.k8s.io/eg created
serviceaccount/backend created
service/backend created
deployment.apps/backend created
httproute.gateway.networking.k8s.io/backend created

You can see that the Gateway has spun up new pod(deployment) and service in envoy namespace

  ~ k get pods,svc -n envoy-gateway-system
NAME                                             READY   STATUS    RESTARTS   AGE
pod/envoy-default-eg-e41e7b31-55bf69f99d-pl6dl   2/2     Running   0          2m37s
pod/envoy-gateway-667545bc7d-dpmmz               1/1     Running   0          45m

NAME                                TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                            AGE
service/envoy-default-eg-e41e7b31   LoadBalancer   10.96.222.26    172.18.0.7    80:30823/TCP                                       2m37s
service/envoy-gateway               ClusterIP      10.96.174.248   <none>        18000/TCP,18001/TCP,18002/TCP,19001/TCP,9443/TCP   45m

In the default namespace

  ~ k get pods,svc -n default             
NAME                           READY   STATUS    RESTARTS   AGE
pod/backend-869c8646c5-vrrtl   1/1     Running   0          5m2s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/backend      ClusterIP   10.96.220.59   <none>        3000/TCP   5m2s
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP    48m

Here is the httpRoute for this backend app

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - group: ""
          kind: Service
          name: backend
          port: 3000
          weight: 1
      matches:
        - path:
            type: PathPrefix
            value: /

To test the traffic, we can port-forward the gateway service and curl it

  ~ curl --verbose --header "Host: www.example.com" http://localhost:8888/get

* Host localhost:8888 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:8888...
* Connected to localhost (::1) port 8888
> GET /get HTTP/1.1
> Host: www.example.com
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
Handling connection for 8888
< HTTP/1.1 200 OK
< content-type: application/json
< x-content-type-options: nosniff
< date: Wed, 03 Sep 2025 15:34:15 GMT
< content-length: 467
<

So, in order to present a mental map on how the traffic is flowing, here is a diagram

Conclusion

GatewayAPI is maturing with more vendors offering it as a solution. There are good migration guides as well. GatewayAPI is a key step towards easier, superior and de-coupled networking solution.