TL;DR
With the retirement of Ingress Nginx migration from Ingress-Nginx to Gateway API using Cilium with a shared gateway approach, trading some complexity for cleaner, more efficient, and standardized ingress management is one way of solving the question of ingress to your cluster.
Why explore Gateway API:
- Annotation Sprawl: Managing dozens of ingress-nginx-specific annotations across ingress resources.
- Limited Future-Proofing: Alignment with where the Kubernetes is heading.
Gateway API address these concerns by offering:
- Standardization: Is an official Kubernetes project.
- Enhanced Security: Built-in RBAC controls and namespace-based access restrictions.
- Better Resource Management: The alternative of useingshared gateways means reduced resource overhead.
Gateway API on Cilium, managed for you
Spin up Talos-based clusters with Cilium and Gateway API ready on day one. Get a managed control plane and flexible block storage, so you focus on your workloads instead of the plumbing.
Discover on-demand Kubernetes
Lets start
Prerequisites
Gateway API CRDs Installation
Before beginning the migration, you need to install the Gateway API crds. We’re using the latest Gateway API v1.4.0:
# Install standard Gateway API CRDs
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/standard/gateway.networking.k8s.io_gatewayclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/standard/gateway.networking.k8s.io_gateways.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml
# Install experimental CRDs (optional, for TLS routes)
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.4.0/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml
Required Cilium Configuration
To enable Gateway API support in Cilium, several key features must be configured:
Essential Cilium Features
# Cilium configuration for Gateway API
gatewayAPI:
enabled: true # Enable Gateway API support
kubeProxyReplacement: true # Required for Gateway API
l2announcements:
enabled: true # Enable L2 announcements for LoadBalancer services
externalIPs:
enabled: true # Allow external IP assignment
# Important for clusters with many services
k8sClientRateLimit:
burst: 40 # Adjust based on cluster size
qps: 20 # Adjust based on cluster size
Load Balancer IP Pool Configuration
Define an IP pool for LoadBalancer services:
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: "ipv4-pool"
spec:
blocks:
- start: "Start Address"
stop: "Stop Address"
L2 Announcement Policy
Configure L2 announcements for your network interface:
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
name: l2-announcement
spec:
interfaces:
- eth0 # Replace with your network interface name
externalIPs: true
loadBalancerIPs: true
Shared vs Non-Shared Gateway
Using the non-shared gateway will replicate the same pattern as ingress-nginx. Basically one gateway, httproute and a grant for the tls certificate. And a gateway means also using a IP out of the pool. While there are usecases for using a seperate Gateway for your workload we will focus on the Shared Gateway in this blog post.
Non-Shared Gateway
In the traditional approach, each service or application has its own Gateway resource:
| Pros | Cons |
|---|---|
| Complete isolation between services | Higher resource consumption (multiple Gateway instances) |
| Individual configuration per service | Duplicated TLS certificate management |
| Simpler troubleshooting (one gateway per service) | More complex certificate distribution |
| No cross-namespace dependencies | Increased operational overhead |
| IP consumption |
Example
# Individual gateway per service
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: podinfo-gateway
namespace: podinfo
spec:
gatewayClassName: cilium
listeners:
- hostname: podinfo.fdqn
name: http
port: 80
protocol: HTTP
Shared Gateway
So let’s explore the Shared Gateway.
| Pros | Cons |
|---|---|
| Reduced resource consumption (single Gateway instance) | Cross-namespace dependencies |
| Centralized TLS certificate management | Requires additional RBAC configuration |
| Consistent security policies | More complex initial setup |
| Simplified operations and monitoring | Potential single point of failure |
| Enhanced security through namespace selection | |
| IP consumption |
Example
# Shared gateway serving multiple services
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: gateway-system
spec:
gatewayClassName: cilium
listeners:
- name: https
port: 443
protocol: HTTPS
tls:
certificateRefs:
- kind: Secret
name: domain-wildcard-tls
namespace: cert-manager
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway.networking.k8s.io/allowed: "true"
Migration Steps
Step 1: Prepare the Shared Gateway Infrastructure
Create the gateway-system namespace and deploy the shared gateway:
# Namespace with proper labeling
apiVersion: v1
kind: Namespace
metadata:
name: gateway-system
labels:
app.kubernetes.io/name: shared-gateway
app.kubernetes.io/component: networking
Step 2: Configure Certificate Access
Set up ReferenceGrant to allow the gateway to access TLS certificates:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: shared-gateway-cert-access
namespace: cert-manager
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: gateway-system
to:
- group: ""
kind: Secret
name: domain-wildcard-tls
Step 3: Migrate Individual Services
For each service, follow this migration pattern:
Before (nginx-ingress):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: podinfo
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
rules:
- host: podinfo.fqdn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: podinfo
port:
number: 9898
After (Gateway API with shared gateway):
- Label the namespace:
apiVersion: v1 kind: Namespace metadata: name: podinfo labels: gateway.networking.k8s.io/allowed: "true" # Enable shared gateway access - Create HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: podinfo namespace: podinfo spec: hostnames: - podinfo.fqdn parentRefs: - name: shared-gateway namespace: gateway-system rules: - backendRefs: - name: podinfo port: 9898 - Create ReferenceGrant for cross-namespace access:
apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: podinfo-to-shared-gateway namespace: gateway-system spec: from: - group: gateway.networking.k8s.io kind: HTTPRoute namespace: podinfo to: - group: gateway.networking.k8s.io kind: Gateway name: shared-gateway - Remove the Nginx Ingress
kubectl delete your_ingress -n your_namespace
Security Enhancements
The shared gateway approach introduces several security improvements:
Namespace-Based Access Control
Only namespaces explicitly labeled with gateway.networking.k8s.io/allowed: "true" can create HTTPRoutes that reference the shared gateway.
Direct Certificate Management
The gateway directly accesses certificates from the cert-manager namespace.
RBAC Integration
Proper ServiceAccount and RBAC policies ensure that only authorized components can manage gateway resources.
What are the goodies?
- Resource Efficiency: Leveraging Cilium’s capabilities and minimizing resource overhead is always a good thing. More ebpf to the people!
- Enhanced Security: Namespace-based access controls and direct cert-manager integration
- Operational Simplicity: Fewer resources to monitor and maintain
- Standards Compliance: Alignment with Kubernetes community direction
Performance Thoughts
The shared gateway approach shows improved performance by:
- Lower Memory Usage: Single gateway instance vs. multiple gateways
- Reduced Network Latency: Direct traffic handling without additional proxy layers
- Better Resource Utilization: More efficient load balancing through Cilium’s eBPF implementation.
Links
Ready to try this in a real cluster?
Safespring on-demand Kubernetes lets you test-drive Gateway API and Cilium in a managed environment with Talos, observability, and storage already prepared. Perfect for piloting your Ingress-Nginx migration before rolling it into production.
Discover on-demand Kubernetes
