ingress2gateway is a Kubernetes SIG-Network tool that helps you migrate from Ingress resources and provider-specific Custom Resource Definitions (CRDs) to the Gateway API. This tool is essential for organizations looking to adopt the next generation of Kubernetes traffic management.
What Does It Do?
ingress2gateway reads your existing:
- Standard Kubernetes Ingress resources
- Provider-specific annotations and CRDs (like ingress-nginx, Istio, Kong, etc.)
And converts them to:
- Gateway API resources (Gateways and HTTPRoutes)
- Standard, portable configuration that works across different implementations
Why Migrate to Gateway API?
The Gateway API is the evolution of Ingress and offers several advantages:
1. Role-Oriented Design
- Separates concerns between infrastructure providers and application developers
Gateway: Managed by infrastructure/platform teamsHTTPRoute: Managed by application teams
2. Expressiveness
- Support for advanced traffic routing (header-based, weighted routing)
- First-class support for protocols beyond HTTP/HTTPS
- Better support for TCP, UDP, and gRPC
3. Extensibility
- Policy attachment mechanism for custom behavior
- Vendor-specific features can be added without breaking compatibility
4. Portability
- Standard API that works across different ingress controllers
- Easier to switch between providers
Prerequisites
Before using ingress2gateway, ensure you have:
- Kubernetes Cluster: v1.19+ running with Ingress resources
- kubectl: Configured to access your cluster
- Go (optional): v1.21+ if building from source
- Existing Ingress Resources: Already deployed in your cluster
Installation
Option 1: Using Go Install
# Install latest version
go install github.com/kubernetes-sigs/ingress2gateway@latest
# Or install specific version
go install github.com/kubernetes-sigs/ingress2gateway@v0.4.0
# The binary will be in $(go env GOPATH)/bin
export PATH=$PATH:$(go env GOPATH)/bin
Option 2: Using Homebrew (macOS/Linux)
brew install ingress2gateway
Option 3: Download Binary from Releases
# For Linux
curl -LO https://github.com/kubernetes-sigs/ingress2gateway/releases/download/v0.4.0/ingress2gateway_0.4.0_linux_amd64.tar.gz
tar -xzf ingress2gateway_0.4.0_linux_amd64.tar.gz
sudo mv ingress2gateway /usr/local/bin/
# For macOS
curl -LO https://github.com/kubernetes-sigs/ingress2gateway/releases/download/v0.4.0/ingress2gateway_0.4.0_darwin_amd64.tar.gz
tar -xzf ingress2gateway_0.4.0_darwin_amd64.tar.gz
sudo mv ingress2gateway /usr/local/bin/
Option 4: Build from Source
# Clone the repository
git clone https://github.com/kubernetes-sigs/ingress2gateway.git
cd ingress2gateway
# Build
make build
# The binary will be in the current directory
./ingress2gateway version
Verify Installation
ingress2gateway --help
Basic Usage
Converting All Ingresses from a Provider
The simplest use case is converting all ingresses from a specific provider:
# Convert all ingress-nginx resources in current namespace
ingress2gateway print --providers=ingress-nginx
# Convert from multiple providers
ingress2gateway print --providers=ingress-nginx,istio
Using Different Namespaces
# Convert from specific namespace
ingress2gateway print --providers=ingress-nginx --namespace=production
# Convert from all namespaces
ingress2gateway print --providers=ingress-nginx --all-namespaces
Output to File
# Save output to YAML file
ingress2gateway print --providers=ingress-nginx > gateway-resources.yaml
# JSON output
ingress2gateway print --providers=ingress-nginx --output=json > gateway-resources.json
Converting from File
# Read from file instead of cluster
ingress2gateway print --providers=ingress-nginx --input-file=ingress-resources.yaml
# This is useful for:
# - Testing conversions without cluster access
# - CI/CD pipelines
# - Reviewing changes before applying
Understanding the Conversion
How Ingress Maps to Gateway API
ingress2gateway follows these conversion rules:
1. IngressClass โ GatewayClass
# Before (Ingress)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx # โ This becomes gatewayClassName
# After (Gateway)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: my-gateway
spec:
gatewayClassName: nginx # โ Transferred here
2. Host-based Routing โ Listeners and HTTPRoutes
# Before (Ingress)
spec:
rules:
- host: api.example.com # โ Creates a listener
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
# After (Gateway + HTTPRoute)
# Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: example-gateway
spec:
listeners:
- name: http
port: 80
protocol: HTTP
hostname: api.example.com # โ From Ingress host
---
# HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: api-routes
spec:
parentRefs:
- name: example-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /users
backendRefs:
- name: user-service
port: 80
3. TLS Configuration โ HTTPS Listeners
# Before (Ingress)
spec:
tls:
- hosts:
- secure.example.com
secretName: tls-secret
# After (Gateway)
spec:
listeners:
- name: https
port: 443
protocol: HTTPS
hostname: secure.example.com
tls:
mode: Terminate
certificateRefs:
- name: tls-secret
4. Default Backend โ Catch-all Route
# Before (Ingress)
spec:
defaultBackend:
service:
name: default-backend
port:
number: 80
# After (HTTPRoute)
spec:
rules:
- backendRefs:
- name: default-backend
port: 80
# No matches = catch-all
Provider-Specific Migrations
Supported Providers

Example: ingress-nginx with Canary
ingress-nginx’s canary annotations are preserved and converted to weighted routing:
# Original Ingress with canary annotations
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: production
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-v1
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-v2
port:
number: 80
Convert it:
ingress2gateway print --providers=ingress-nginx --input-file=canary-ingress.yaml
Result includes weighted backend refs:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: app-routes
spec:
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-v1
port: 80
weight: 80 # 80% traffic
- name: app-v2
port: 80
weight: 20 # 20% traffic (canary)
Example: Header-based Routing (ingress-nginx)
# Original Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "X-Version"
nginx.ingress.kubernetes.io/canary-by-header-value: "beta"
# Converts to HTTPRoute with header matching
spec:
rules:
- matches:
- headers:
- name: X-Version
value: beta
type: Exact
backendRefs:
- name: app-beta
port: 80
Advanced Examples
Example 1: Multi-Host Application
Let’s say you have an application with multiple domains:
# Original structure
kubectl get ingress -n myapp
# NAME CLASS HOSTS ADDRESS PORTS
# app-ingress nginx app.example.com ... 80, 443
# api-ingress nginx api.example.com ... 80, 443
# admin-ingress nginx admin.example.com ... 80, 443
Convert all at once:
ingress2gateway print --providers=ingress-nginx --namespace=myapp > gateway-conversion.yaml
This creates:
- One Gateway with multiple listeners (one per host)
- Multiple HTTPRoutes (one per domain)
- Proper parent references linking routes to gateway
Example 2: Migration Workflow
Here’s a safe migration workflow:
# Step 1: Generate Gateway API resources (don't apply yet)
ingress2gateway print --providers=ingress-nginx \
--namespace=production \
> production-gateway.yaml
# Step 2: Review the output
cat production-gateway.yaml
# Step 3: Test in staging first
kubectl create namespace staging-migration
kubectl apply -f production-gateway.yaml -n staging-migration
# Step 4: Install Gateway API controller (e.g., NGINX Gateway Fabric)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
# Step 5: Apply to production (run alongside existing Ingress)
kubectl apply -f production-gateway.yaml -n production
# Step 6: Verify traffic routing
curl -H "Host: app.example.com" http://your-gateway-ip/
# Step 7: Update DNS to point to Gateway
# (Implementation depends on your setup)
# Step 8: Monitor for a period
# Step 9: Remove old Ingress resources
kubectl delete ingress --all -n production
Example 3: Complex Path-Based Routing
# Original Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
spec:
rules:
- host: api.example.com
http:
paths:
- path: /v1/users
pathType: Prefix
backend:
service:
name: users-v1
port:
number: 8080
- path: /v2/users
pathType: Prefix
backend:
service:
name: users-v2
port:
number: 8080
- path: /v1/orders
pathType: Prefix
backend:
service:
name: orders-v1
port:
number: 8080
- path: /health
pathType: Exact
backend:
service:
name: health-check
port:
number: 8080
Convert with:
ingress2gateway print --providers=ingress-nginx --input-file=api-ingress.yaml
Results in HTTPRoute with multiple rules, proper path matching, and separate backends.
Example 4: Using OpenAPI Provider
The OpenAPI provider is unique – it converts OpenAPI 3.0 specifications to Gateway API:
# Convert OpenAPI spec to Gateway API
ingress2gateway print \
--providers=openapi \
--input-file=api-spec.yaml \
--openapi3-backend=api-backend \
--openapi3-gateway-class-name=nginx \
--openapi3-gateway-tls-secret=api-tls
This is useful for:
- API-first development
- Generating infrastructure from API specs
- Ensuring API definition and routing stay in sync
Best Practices
1. Start Small
Don’t convert your entire production infrastructure at once:
# Convert one namespace first
ingress2gateway print --providers=ingress-nginx --namespace=dev
# Then staging
ingress2gateway print --providers=ingress-nginx --namespace=staging
# Finally production
ingress2gateway print --providers=ingress-nginx --namespace=production
2. Review Before Applying
Always review generated resources:
ingress2gateway print --providers=ingress-nginx | less
Check for:
- Correct gateway class names
- Proper TLS configuration
- Expected host names and paths
- Backend service references
3. Test in Non-Production First
bash
# Convert and apply to test namespace
ingress2gateway print --providers=ingress-nginx \
--namespace=production \
| sed 's/namespace: production/namespace: test/' \
| kubectl apply -f -
4. Preserve Original Ingress During Migration
Run Gateway API alongside existing Ingress:
# Don't delete Ingress resources immediately
# Apply Gateway API resources
kubectl apply -f gateway-resources.yaml
# Test thoroughly
# Only delete Ingress after validation
# kubectl delete ingress <name>
5. Use Version Control
# Always version control your conversions
git add gateway-resources.yaml
git commit -m "Add Gateway API resources converted from Ingress"
6. Document Provider-Specific Features
If you use provider-specific annotations, document which ones are converted and which need manual attention:
# Create a report
ingress2gateway print --providers=ingress-nginx > converted.yaml
grep -i "nginx.ingress.kubernetes.io" original-ingress.yaml > annotations-used.txt
# Compare to see what was handled
7. Consider Resource Names
# Generated resource names might be long or unclear
# You may want to rename them for clarity
kubectl get gateways
kubectl get httproutes
# Use meaningful names in production
8. Conflict Resolution
ingress2gateway handles conflicts by sorting resources by:
- Creation timestamp (oldest first)
- Namespace/name (alphabetically)
Understand this when multiple Ingresses might conflict:
# Check creation timestamps
kubectl get ingress --sort-by=.metadata.creationTimestamp
# The oldest takes precedence
9. Handle Limitations
Some features don’t translate directly:
- Custom annotations may need manual conversion
- Some provider-specific features might not have Gateway API equivalents
- Review the conversion output for warnings
10. Performance Testing
After migration, run load tests:
# Example with Apache Bench
ab -n 1000 -c 10 http://your-gateway-endpoint/
# Compare results to Ingress baseline
Troubleshooting
Issue 1: “No ingress resources found”
Problem: The tool can’t find any Ingress resources.
Solutions:
# Check if Ingresses exist
kubectl get ingress --all-namespaces
# Verify namespace
kubectl get ingress -n <namespace>
# Check kubeconfig context
kubectl config current-context
# Specify kubeconfig explicitly
ingress2gateway print --providers=ingress-nginx --kubeconfig=/path/to/config
Issue 2: Gateway Class Not Found
Problem: Generated Gateway references a class that doesn’t exist.
Solution:
# Check available gateway classes
kubectl get gatewayclasses
# Install Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
# Install a Gateway controller (e.g., NGINX Gateway Fabric)
kubectl apply -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.0.0/deploy.yaml
Issue 3: TLS Certificate Issues
Problem: HTTPS listeners not working.
Solutions:
# Verify secret exists in correct namespace
kubectl get secret <tls-secret-name> -n <namespace>
# Check secret type
kubectl get secret <tls-secret-name> -o yaml | grep type
# Should be: kubernetes.io/tls
# Verify certificate contents
kubectl get secret <tls-secret-name> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout
Issue 4: Routes Not Matching Traffic
Problem: HTTPRoutes created but traffic doesn’t route correctly.
Debug:
# Check HTTPRoute status
kubectl describe httproute <name>
# Verify parent refs
kubectl get httproute <name> -o yaml | grep -A 5 parentRefs
# Check Gateway status
kubectl describe gateway <name>
# Verify listener configurations
kubectl get gateway <name> -o yaml | grep -A 10 listeners
Issue 5: Provider-Specific Annotations Lost
Problem: Some annotations didn’t convert.
Solution:
# Check supported annotations in provider README
cat pkg/i2gw/providers/ingress-nginx/README.md
# For unsupported features:
# 1. Open an issue on GitHub
# 2. Manually implement equivalent in Gateway API
# 3. Use policy attachments if available
Issue 6: Multiple Ingresses to Single Gateway
Problem: Unexpected consolidation of resources.
Explanation: ingress2gateway intelligently merges Ingresses that can share a Gateway:
# This is expected behavior
# Multiple Ingresses with same class โ One Gateway with multiple listeners
# Each Ingress rule โ Separate HTTPRoute
# To verify:
kubectl get gateways
kubectl get httproutes
Issue 7: Output Format Issues
Problem: YAML/JSON output is malformed.
Solutions:
# Try different output format
ingress2gateway print --providers=ingress-nginx --output=json
# Validate YAML
ingress2gateway print --providers=ingress-nginx | yamllint -
# Check for resource conflicts
ingress2gateway print --providers=ingress-nginx 2>&1 | grep -i error
Getting Help
If you encounter issues not covered here:
- Check the GitHub Issues: https://github.com/kubernetes-sigs/ingress2gateway/issues
- Gateway API Slack: Join #sig-network-gateway-api channel
- Community Meetings: Gateway API community meets regularly
- Documentation: https://gateway-api.sigs.k8s.io/
Additional Resources
Official Documentation
Example Implementations
Migration Guides
Conclusion
ingress2gateway is a powerful tool for organizations adopting the Gateway API. By following this tutorial, you should be able to:
- โ Install ingress2gateway
- โ Convert Ingress resources to Gateway API
- โ Handle provider-specific features
- โ Safely migrate production workloads
- โ Troubleshoot common issues
Remember:
- Start small and test thoroughly
- The Gateway API is the future of Kubernetes traffic management
- Community support is available and active
Happy migrating! ๐
Quick Reference Card
# Basic conversion
ingress2gateway print --providers=ingress-nginx
# Specific namespace
ingress2gateway print --providers=ingress-nginx --namespace=prod
# From file
ingress2gateway print --providers=ingress-nginx --input-file=ingress.yaml
# Multiple providers
ingress2gateway print --providers=ingress-nginx,istio
# JSON output
ingress2gateway print --providers=ingress-nginx --output=json
# Save to file
ingress2gateway print --providers=ingress-nginx > gateway.yaml
# All namespaces
ingress2gateway print --providers=ingress-nginx --all-namespaces