Gateway API with kgateway in Thalassa Cloud Kubernetes
kgateway is a CNCF project that implements the Kubernetes Gateway API using Envoy as the data plane. It provides a modern, role-oriented alternative to traditional Ingress controllers, with clearer separation between infrastructure operators (who manage Gateways) and application developers (who attach HTTPRoutes).
On Thalassa Cloud Kubernetes, kgateway provisions a LoadBalancer Service for each Gateway, which integrates with Thalassa Cloud VPC Load Balancers. This guide walks you through installing kgateway, configuring a Gateway with Thalassa-specific load balancer settings, and routing traffic to a sample application.
Prerequisites
Before you begin, ensure you have:
- A running Kubernetes cluster in Thalassa Cloud (Kubernetes 1.24 or later)
kubectlconfigured to access your cluster (tcloud kubernetes connector a kubeconfig)helm3.x installed- Cluster administrator permissions to install CRDs and cluster-scoped resources
Overview
Exposing an application with kgateway involves:
- Installing the Gateway API CRDs and kgateway control plane
- Configuring a Gateway (optionally with Thalassa Cloud load balancer annotations)
- Deploying your application
- Creating an HTTPRoute to connect the Gateway to your Service
flowchart LR
Client[Client] -->|HTTPS| LB[Thalassa VPC Load Balancer]
LB --> GW[kgateway Envoy proxy]
GW -->|HTTPRoute| SVC[Application Service]
SVC --> POD[Application Pods]
Step 1: Install Gateway API CRDs
Install standard Gateway API CRDs
Install the standard Gateway API CRDs. These provide the core Gateway, HTTPRoute, and GatewayClass resources:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yamlVerify the CRDs are installed:
kubectl get crd gateways.gateway.networking.k8s.io
kubectl get crd httproutes.gateway.networking.k8s.ioStep 2: Install kgateway
Install kgateway CRDs
Deploy the kgateway-specific CRDs using Helm:
helm upgrade -i kgateway-crds oci://cr.kgateway.dev/kgateway-dev/charts/kgateway-crds \
--create-namespace \
--namespace kgateway-system \
--version v2.3.1Install the kgateway control plane
Install the kgateway controller:
helm upgrade -i kgateway oci://cr.kgateway.dev/kgateway-dev/charts/kgateway \
--namespace kgateway-system \
--version v2.3.1Verify the installation
Confirm the control plane is running and the default GatewayClass is available:
kubectl get pods -n kgateway-system
kubectl get gatewayclass kgatewayYou should see the kgateway pod in Running state and the kgateway GatewayClass with Accepted=True.
Step 3: Configure a Gateway
When you create a Gateway resource, kgateway automatically provisions an Envoy proxy Deployment and a LoadBalancer Service. On Thalassa Cloud, this Service is backed by a VPC Load Balancer.
Basic Gateway
Create a Gateway with an HTTP listener on port 80:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http
namespace: kgateway-system
spec:
gatewayClassName: kgateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: AllApply the Gateway:
kubectl apply -f gateway.yamlVerify the Gateway is programmed and has an external address:
kubectl get gateway http -n kgateway-system
kubectl get svc -n kgateway-systemIt may take a minute or two for the Thalassa Cloud Load Balancer to receive an external IP address.
Gateway with Thalassa Cloud Load Balancer settings
Use a GatewayParameters resource to apply Thalassa-specific annotations to the generated LoadBalancer Service. This lets you configure ACLs, security groups, internal load balancers, and other VPC load balancer features.
Create gateway-parameters.yaml:
apiVersion: gateway.kgateway.dev/v1alpha1
kind: GatewayParameters
metadata:
name: thalassa-lb
namespace: kgateway-system
spec:
kube:
serviceOverlay:
metadata:
annotations:
loadbalancer.k8s.thalassa.cloud/create-security-group: "true"
loadbalancer.k8s.thalassa.cloud/acl-allowed-sources: "0.0.0.0/0"Then reference it in your Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: http
namespace: kgateway-system
spec:
gatewayClassName: kgateway
infrastructure:
parametersRef:
group: gateway.kgateway.dev
kind: GatewayParameters
name: thalassa-lb
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: AllLoad Balancer annotations
All Thalassa Cloud load balancer annotations can be applied via GatewayParameters serviceOverlay. Common options include loadbalancer.k8s.thalassa.cloud/internal for internal-only load balancers, loadbalancer.k8s.thalassa.cloud/enable-proxy-protocol for passing client IP, and per-port ACLs with loadbalancer.k8s.thalassa.cloud/acl-port-{port}.
Step 4: Deploy a sample application
Deploy the httpbin sample app to test routing:
kubectl apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway/refs/heads/main/examples/httpbin.yamlVerify the app is running:
kubectl get pods -n httpbinStep 5: Create an HTTPRoute
An HTTPRoute attaches your application to a Gateway listener. Create the route in the same namespace as the backend Service:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
spec:
parentRefs:
- name: http
namespace: kgateway-system
sectionName: http
hostnames:
- "www.example.com"
rules:
- backendRefs:
- name: httpbin
port: 8000Apply the HTTPRoute:
kubectl apply -f httproute.yamlVerify the route is accepted:
kubectl get httproute httpbin -n httpbin -o yamlLook for Accepted=True and ResolvedRefs=True in the status conditions.
Step 6: Verify traffic routing
Get the external address of the Gateway load balancer:
export GATEWAY_ADDRESS=$(kubectl get svc -n kgateway-system http \
-o=jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
echo $GATEWAY_ADDRESSPoint your DNS record for www.example.com to this address, then send a test request:
curl -i http://$GATEWAY_ADDRESS/headers -H "host: www.example.com"You should receive a 200 OK response from httpbin with the request headers echoed back.
TLS with Cert Manager
For HTTPS, install Cert Manager and configure a ClusterIssuer. Cert Manager supports the Gateway API through the gatewayHTTPRoute solver.
Create a ClusterIssuer with Gateway API support:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: http
namespace: kgateway-system
kind: GatewayThen reference the TLS secret in your Gateway listener (as shown in Step 3) or annotate the HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
parentRefs:
- name: http
namespace: kgateway-system
sectionName: https
hostnames:
- "www.example.com"
rules:
- backendRefs:
- name: httpbin
port: 8000Cert Manager automatically provisions and renews the certificate, storing it in the referenced Secret.
Troubleshooting
Gateway not getting an external address
Check the LoadBalancer Service status and events:
kubectl describe svc -n kgateway-system http
kubectl get events -n kgateway-system --sort-by='.lastTimestamp'Ensure your cluster has a working Cloud Controller Manager and that the subnet has available IP addresses for load balancers.
HTTPRoute not accepted
Inspect the HTTPRoute status and kgateway controller logs:
kubectl describe httproute <route-name> -n <namespace>
kubectl logs -n kgateway-system -l app.kubernetes.io/name=kgatewayCommon causes:
- Parent Gateway not ready: Wait for the Gateway to show
Programmed=True - Namespace mismatch: HTTPRoutes must be in the same namespace as the backend Service, or use a
ReferenceGrant - Listener mismatch: Ensure
sectionNameinparentRefsmatches a listener name on the Gateway
Gateway proxy pod in CrashLoopBackOff
Check the proxy pod logs:
kubectl logs -n kgateway-system -l gateway.networking.k8s.io/gateway-name=httpVerify that Gateway API CRDs and kgateway CRDs are both installed and that no conflicting ingress controllers are binding the same ports.
Cleanup
Remove the resources created in this guide:
kubectl delete httproute httpbin -n httpbin
kubectl delete gateway http -n kgateway-system
kubectl delete gatewayparameters thalassa-lb -n kgateway-system
kubectl delete -f https://raw.githubusercontent.com/kgateway-dev/kgateway/refs/heads/main/examples/httpbin.yaml
helm uninstall kgateway -n kgateway-system
helm uninstall kgateway-crds -n kgateway-systemNext steps
- Cert Manager and Let’s Encrypt — Automate TLS certificate provisioning
- Service Load Balancers — Configure Thalassa Cloud load balancer annotations and ACLs
- Working with Cilium Network Policies — Restrict traffic between gateway proxies and backends
- kgateway documentation — Traffic management, resiliency, and security policies
- Kubernetes Gateway API — Official Gateway API specification