1. Introduction

In Kubernetes, efficient and flexible service networking is crucial for managing complex, cloud-native applications. Enter the Kubernetes Gateway API – a game-changing approach to handling ingress traffic and routing in Kubernetes clusters. This powerful API addresses the limitations of traditional ingress controllers while providing a standardized, extensible, and role-oriented interface for service networking.

In this tutorial, we’ll discuss the Kubernetes Gateway API, a powerful tool for managing service networking in Kubernetes clusters. We’ll explore the evolution of external access mechanisms for Kubernetes pods, introduce the key components and concepts of the Gateway API, and examine its installation and configuration. Let’s get started!

2. Background and Evolution

To better understand the Gateway API’s significance, let’s briefly examine its predecessor, the Kubernetes ingress resource.

The ingress resource was introduced to manage external access to services within a Kubernetes cluster, offering a straightforward way to configure HTTP load balancing and SSL/TLS termination. However, as Kubernetes deployments grew in complexity, several limitations of the ingress resource became apparent:

  • Limited protocol support: Ingress design was primarily for HTTP traffic, making it challenging to handle other protocols.
  • Lack of expressiveness: Complex routing scenarios often required non-standard annotations, leading to vendor lock-in.
  • Insufficient role-based access control: It was challenging to separate concerns between cluster operators and application developers.

Notably, Kubernetes initially provided several methods to access pods from outside the cluster. Directly accessing a pod through its IP address was common but unreliable due to the pods’ transient nature. To address this, Kubernetes introduced the concept of services, which offer stable IPs and handle the dynamic mapping between services and their underlying pods.

However, despite these advancements, services alone were insufficient for complex routing requirements, leading to the development of the ingress resource. Ingress provided HTTP and HTTPS routing to services within the cluster, allowing for more sophisticated routing configurations. Yet, its limitations persisted, particularly its reliance on protocol-specific features and annotations.

3. Understanding the Kubernetes Gateway API

As organizations adopted Kubernetes at scale, the need for a more flexible and standardized approach to service networking became clear.

The Kubernetes Gateway API is an open-source project by the SIG-NETWORK community. It provides a collection of resources designed to model service networking in Kubernetes in a more expressive, extensible, and role-oriented manner.

Unlike ingress, the Gateway API introduces a clean separation between the standard objects and proprietary implementations, making migrating between providers and implementations easier. Therefore, the Gateway API represents a significant leap forward in Kubernetes service networking.

4. Setting Up the Gateway API

Let’s walk through setting up the Gateway API in our Kubernetes cluster. To start using the Kubernetes Gateway API, we need to install the necessary Custom Resource Definitions (CRDs) and choose an implementation.

4.1. Installing the Gateway CRDs

First, we need to install the Gateway API CRDs. We can do this by applying the YAML files provided by the Kubernetes SIG-NETWORK community.

On the one hand, we can use this YAML file to install the standard release channel, which includes the most stable resources:

$ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml

customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io created
...
customresourcedefinition.apiextensions.k8s.io/grpcroutes.gateway.networking.k8s.io created

This installs the Gateway API’s standard channel, which includes all resources that have graduated to GA or beta status.

On the other hand, if we want to use the experimental features, we can install the experimental channel instead:

$ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/experimental-install.yaml

customresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io created
...
customresourcedefinition.apiextensions.k8s.io/referencepolicies.gateway.networking.k8s.io created

This installs the experimental channel.

4.2. Choosing and Installing a Gateway Controller

After installing the CRDs, we need to choose and install a Gateway controller that implements the Gateway API. For this, we have several options available:

However, for this tutorial, we’ll proceed with Apache APISIX as our Gateway controller. This is due to its powerful traffic management capabilities, including advanced features like dynamic routing, load balancing, and a rich plugin ecosystem. It makes it an ideal choice for managing complex API traffic within Kubernetes environments.

Now, let’s install it using Helm, our trusted Kubernetes package manager:

$ helm install apisix apisix/apisix \
  --namespace ingress-apisix \
  --create-namespace \
  --devel \
  --set gateway.type=NodePort \
  --set gateway.http.nodePort=30800 \
  --set ingress-controller.enabled=true \
  --set ingress-controller.config.kubernetes.enableApiGateway=true \
  --set ingressPublishService="ingress-apisix/apisix-gateway"

NAME: apisix
LAST DEPLOYED: Tue Aug  7 12:00:00 2024
NAMESPACE: ingress-apisix
STATUS: deployed
REVISION: 1
NOTES:
Apache APISIX has been installed.

Here, we install Apache APISIX with the necessary configurations to work with the Gateway API.

After running the command and the installation completes, we can verify that all components are running correctly:

$ kubectl get all -n ingress-apisix

NAME                                           READY   STATUS    RESTARTS   AGE
pod/apisix-56c6c9b69b-x7k8f                    1/1     Running   0          1m
pod/apisix-etcd-0                              1/1     Running   0          1m
pod/apisix-ingress-controller-65d6c8f76c-jh8fw 1/1     Running   0          1m

...

NAME                    READY   AGE
statefulset.apps/apisix-etcd   1/1     1m

As we can see, the Apache APISIX pods and services are now running in the ingress-apisix namespace.

5. The Gateway API Resources

After installing the Gateway API, we can now deploy our resources. The Gateway API consists of several vital resources.

Let’s look at them in detail.

5.1. GatewayClass

The GatewayClass resource serves as a template for creating Gateway resources. It’s a cluster-scoped resource that defines a set of Gateways resources sharing common configuration and behavior. Like StorageClass abstracts storage configurations in Kubernetes, the GatewayClass abstracts the configuration for Gateway resources. Each GatewayClass specifies a controller that manages the Gateway resources of that class.

Here are some key points we should note about GatewayClass:

  • Controller association: It’s associated with a specific controller implementation.
  • Shared configuration: Defines the high-level configuration shared by all Gateways of each class.
  • Diverse gateways: Allows for different types of Gateways within the same cluster (e.g., public vs. private).

Let’s see a sample YAML configuration for a GatewayClass (e.g., example-gateway-class.yaml):

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: GatewayClass
metadata:
  name: example-gateway-class
spec:
  controllerName: example.com/gateway-controller

Here, we define a GatewayClass (example-gateway-class). The spec section indicates the controller responsible for managing the Gateways of this class. This configuration allows for the creation of multiple Gateways with shared characteristics defined by this GatewayClass.

5.2. Gateway

A Gateway resource represents the instantiation of a GatewayClass. It defines the actual listener configurations for accepting incoming traffic and acts as a load balancer to handle multiple routes. The Gateway resource specifies the management and routing of traffic at the cluster’s edge.

Here are some essential aspects of Gateway we should take note of:

  • Listener configurations: Specifies ports, protocols, and TLS settings for listeners.
  • Scoping: It can be scoped to a specific namespace or be cluster-wide.
  • Traffic management: Acts as an intermediary between external traffic and Routes.

Let’s see an example YAML configuration for a Gateway (e.g., example-gateway.yaml):

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
    - name: http
      protocol: HTTP
      port: 80

Here, we define a Gateway example-gateway. It references the previously defined GatewayClass example-gateway-class. The spec section includes a listener configuration for HTTP traffic on port 80. This Gateway acts as an entry point for incoming traffic and will use the configuration and behavior defined by its associated GatewayClass.

5.3. Routes

Routes are namespace-scoped resources that define rules for mapping incoming requests to Kubernetes services. The Gateway API supports various route types, each providing protocol-specific configuration options for fine-grained traffic routing control.

Here are the supported Route types, which we shall also discuss:

  • HTTPRoute: For HTTP and HTTPS traffic
  • TCPRoute: For TCP traffic
  • UDPRoute: For UDP traffic
  • TLSRoute: For TLS traffic
  • GRPCRoute: Specifically for gRPC traffic.

Each route type provides protocol-specific configuration options, allowing for fine-grained control over traffic routing.

5.4. HTTPRoute

The HTTPRoute resource defines rules for routing HTTP traffic. It specifies the traffic’s direction based on criteria such as path, header, and method.

Let’s see an example YAML configuration for an HTTPRoute (e.g., example-http-route.yaml):

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: example-http-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /example
      backendRefs:
        - name: example-service
          port: 80

In this YAML file, we define an HTTPRoute example-http-route. It references the example-gateway we previously defined as its parent, indicating which Gateway should implement this route. The rules section specifies that requests with a path prefix “*/example*” should be routed to the example-service on port 80. This configuration allows for fine-grained HTTP traffic routing based on the request path.

5.5. TCPRoute

The TCPRoute resource defines rules for routing TCP traffic. We use it for non-HTTP protocols because it provides routing capabilities similar to HTTPRoute.

Let’s see a sample YAML configuration for a TCPRoute:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: example-tcp-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - port: 8080
      backendRefs:
        - name: example-tcp-service
          port: 8080

Here, we define a TCPRoute example-tcp-route. It references our example-gateway as its parent. The rules section specifies that TCP traffic on port 8080 should be routed to the example-tcp-service on port 8080. This configuration allows for the routing of non-HTTP TCP traffic.

5.6. UDPRoute

The UDPRoute resource defines rules for services that require routing User Datagram Protocol (UDP) traffic.

Let’s see a sample YAML configuration for a UDPRoute:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: UDPRoute
metadata:
  name: example-udp-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - port: 53
      backendRefs:
        - name: example-udp-service
          port: 53

Here, we define a UDPRoute example-udp-route. It also references our example-gateway as its parent. The rules section specifies that UDP traffic on port 53 should be routed to the example-udp-service on port 53. This configuration is helpful for services that rely on UDP protocol, such as DNS services.

5.7. TLSRoute

The TLSRoute resource defines rules for services that require Transport Layer Security (TLS) termination and routing.

Let’s see a sample YAML configuration for a TLSRoute:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
  name: example-tls-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - sniHosts:
            - example.com
      backendRefs:
        - name: example-tls-service
          port: 443

In this similar YAML for TLSRoute, the rules section specifies that TLS traffic with SNI (Server Name Indication) host example.com should be routed to the example-tls-service on port 443. This configuration allows for routing of TLS traffic based on the SNI header.

5.8. GRPCRoute

The GRPCRoute resource defines rules for routing gRPC traffic. It’s explicitly designed for gRPC services and provides routing capabilities tailored to the gRPC protocol.

Let’s see a sample YAML configuration for a GRPCRoute (e.g., example-grpc-route.yaml):

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: GRPCRoute
metadata:
  name: example-grpc-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - method:
            service: example.Greeter
            method: SayHello
      backendRefs:
        - name: example-grpc-service
          port: 50051

Here, we define a YAML GRPCRoute example-grpc-route. The rules section specifies that gRPC requests for the SayHello method of the example.Greeter service should be routed to the example-grpc-service on port 50051. This configuration allows for specific routing of gRPC traffic based on the service and method being called.

Ultimately, the Gateway API aims to provide a more flexible and powerful way to manage networking in Kubernetes, with broad industry support and implementation by many vendors. By understanding these key components, we can effectively utilize the Kubernetes Gateway API to manage complex networking scenarios in our Kubernetes clusters.

6. Migrating From Ingress to Gateway API

If we currently use ingress to manage external access to our Kubernetes services, we may wonder how to migrate to the Gateway API. While the migration process can seem daunting, it’s pretty straightforward when we carefully understand the differences and similarities between ingress and the Gateway API.

The ingress resource is a monolithic object that handles both routing and load balancing through a single entity. It can be somewhat limiting in complex scenarios requiring more granular control.

On the other hand, the Gateway API breaks down the ingress functionality into multiple objects – GatewayClass, Gateway, and HTTPRoute, as we have discussed with each responsible for different routing and load-balancing aspects. This separation provides more flexibility and allows different roles to manage various parts of the networking stack.

Let’s consider a practical example of migrating from Ingress to Gateway API. Suppose we have an Ingress resource managing traffic for two services, app1, and app2, and we want to migrate to the Gateway API.

Here is what our original Ingress YAML looks like:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /app1
        pathType: Prefix
        backend:
          service:
            name: app1-service
            port:
              number: 80
      - path: /app2
        pathType: Prefix
        backend:
          service:
            name: app2-service
            port:
              number: 80

Here, the Ingress resource routes traffic to app1 and app2 services based on the path specified in the rules section. The ingress object handles everything from accepting external traffic to routing it to the appropriate service. Still, this approach is less flexible when dealing with more complex routing scenarios or managing large-scale deployments.

6.1. Creating a GatewayClass

The first step in the migration process is to define a GatewayClass that matches the behavior of our current ingress controller.

For example, if we’re using an NGINX-based ingress controller, we’ll find or create a GatewayCilass that uses NGINX as its underlying implementation:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: GatewayClass
metadata:
  name: nginx-gateway-class
spec:
  controllerName: nginx.org/gateway-controller

Here, we associate the nginx-gateway-class GatewayClass with an NGINX Gateway controller, identified by the controllerName. We can now use this GatewayClass to create Gateways that leverage NGINX for routing traffic within the cluster.

6.2. Replacing Ingress With Gateway and HTTPRoute Objects

After we have created a GatewayClass, the next step is to convert our existing ingress resources into Gateway and HTTPRoute resources. The Gateway resource will listen for incoming traffic, while the HTTPRoute resource defines how that traffic should be routed to the appropriate services.

Let’s now convert our original Ingress YAML into Gateway and HTTPRoute YAMLs:

# New Gateway YAML

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
  name: example-gateway
spec:
  gatewayClassName: nginx-gateway-class
  listeners:
    - name: http
      protocol: HTTP
      port: 80

-----
# New HTTPRoute YAML

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: example-http-route
spec:
  parentRefs:
    - name: example-gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /app1
      backendRefs:
        - name: app1-service
          port: 80
    - matches:
        - path:
            type: PathPrefix
            value: /app2
      backendRefs:
        - name: app2-service
          port: 80

In our new configuration, the Gateway resource (example-gateway) listens for HTTP traffic on port 80, much like the Ingress did. However, instead of specifying routing rules directly in the Gateway, those rules are now defined in an HTTPRoute resource (example-http-route). The HTTPRoute specifies how traffic should be routed based on the path prefix (/app1 and /app2), directing it to the appropriate backend services (app1-service and app2-service).

By separating these concerns, the Gateway API allows for more modular and flexible traffic management. Therefore, different teams can manage different routing and load-balancing aspects, and changes can be made to one component without affecting the others.

With these steps, we can smoothly transition from ingress to the more flexible and powerful Kubernetes Gateway API, taking advantage of its modular architecture and enhanced capabilities.

7. Conclusion

The Kubernetes Gateway API represents a significant evolution in how we manage service networking within Kubernetes clusters.

In this article, we’ve covered the essentials of the Gateway API, starting with its evolution, installation, and configuration. The Gateway API offers enhanced control, scalability, and extensibility by breaking down the monolithic ingress resource into more granular and flexible components like GatewayClass, Gateway, and HTTPRoute.

Finally, we discussed the process for migrating from ingress to the Gateway API, ensuring that our transition can be smooth and trouble-free.