Comparing Kubernetes Ingress Controllers: Nginx, Traefik, and Envoy Features & Performance
This article provides a detailed comparison of the three leading Kubernetes Ingress Controllers—Nginx, Traefik, and Envoy—covering their architecture, configuration methods, feature sets, performance benchmarks, and practical selection guidance for various deployment scenarios.
Introduction
Kubernetes uses Ingress as the standard way to expose services externally. An Ingress resource defines HTTP/HTTPS routing rules, while an Ingress Controller implements those rules by translating them into reverse‑proxy configurations and updating them dynamically.
The three mainstream Ingress Controllers are Nginx Ingress Controller, Traefik, and Envoy (via Contour). Each has distinct characteristics that affect cluster stability, performance, and maintainability.
Chapter 1 – Ingress Basics
1.1 Kubernetes Network Model
Pods receive unique IP addresses and can communicate directly without NAT. Services abstract a group of Pods and provide load‑balancing and discovery. ClusterIP is the default Service type, accessible only inside the cluster. To expose services externally you can use NodePort, LoadBalancer, or Ingress (layer‑7 routing).
1.2 Ingress Resource Definition
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
spec:
ingressClassName: nginx
rules:
- host: demo.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 8080
tls:
- hosts:
- demo.example.com
secretName: demo-tls-secretThe ingressClassName field (supported from Kubernetes 1.18) selects the controller that will handle the resource.
Chapter 2 – Nginx Ingress Controller
2.1 Architecture & Principles
Nginx Ingress runs either as a Deployment (suitable for large clusters with HPA) or as a DaemonSet (one pod per node for low‑latency use cases).
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
spec:
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.9.4
args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/nginx-configuration
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
httpGet:
path: /healthz
port: 10254
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 10254
periodSeconds: 5
resources:
requests:
cpu: 100m
memory: 90Mi
limits:
cpu: 1
memory: 1Gi2.2 Configuration Methods
Configuration can be done via Ingress annotations or a global ConfigMap. Common annotations include SSL redirect, rate limiting, request body size, timeouts, and canary deployment flags.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: cafe-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
spec:
ingressClassName: nginx
rules:
- host: cafe.example.com
http:
paths:
- path: /tea
pathType: Exact
backend:
service:
name: tea-svc
port:
number: 80
- path: /coffee
pathType: Prefix
backend:
service:
name: coffee-svc
port:
number: 802.3 Global ConfigMap Example
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configuration
namespace: ingress-nginx
data:
proxy-body-size: "50m"
proxy-connect-timeout: "30"
proxy-read-timeout: "60"
enable-brotli: "true"
enable-gzip: "true"
gzip-level: "6"2.4 TLS Configuration
Both simple TLS (single secret) and self‑signed certificate creation are demonstrated.
2.5 Canary Release
Canary can be weight‑based or header‑based using annotations nginx.ingress.kubernetes.io/canary and related keys.
Chapter 3 – Traefik
3.1 Architecture & Principles
Traefik is a cloud‑native reverse proxy that watches the Kubernetes API (or other providers) and updates routing without process reloads. It separates Provider, Router, Middleware, and Service components.
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: ingress
spec:
replicas: 2
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
containers:
- name: traefik
image: traefik:v3.0.4
args:
- --api.insecure
- --accesslog
- --entrypoints.http.address=:80
- --entrypoints.https.address=:443
- --providers.kubernetesingress
- --log.level=INFO
- --metrics.prometheus
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: admin
containerPort: 8080
livenessProbe:
httpGet:
path: /ping
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ping
port: 8080
periodSeconds: 5
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi3.2 IngressRoute CRD
Traefik introduces its own IngressRoute CRD, which offers richer routing options.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: demo-ingressroute
namespace: default
spec:
entryPoints:
- web
- websecure
routes:
- match: Host(`demo.example.com`) && PathPrefix(`/api`)
kind: Rule
services:
- name: api-service
port: 80
middlewares:
- name: strip-api-prefix
- name: rate-limit
- match: Host(`demo.example.com`) && PathPrefix(`/`)
kind: Rule
services:
- name: frontend-service
port: 803.3 Middleware
Traefik uses Middleware objects for authentication, rate limiting, retries, redirects, and more.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: basic-auth
namespace: default
spec:
basicAuth:
secret: basic-auth-secret
---
apiVersion: v1
kind: Secret
metadata:
name: basic-auth-secret
namespace: default
type: Opaque
stringData:
users: |
admin:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/3.4 Dynamic Service Discovery
Traefik can pull services from Consul, Etcd, ZooKeeper, etc., in addition to Kubernetes.
3.5 TCP/UDP Support
Traefik also supports TCP and UDP entry points via dedicated CRDs.
Chapter 4 – Envoy (via Contour)
4.1 Architecture & Principles
Envoy is a high‑performance edge and service proxy written in C++. It uses the xDS API for dynamic configuration. Core concepts include Listeners, Routes, Clusters, Endpoints, Filters, and Health Checks.
4.2 Contour Deployment
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: contour
namespace: projectcontour
spec:
replicas: 2
selector:
matchLabels:
app: contour
template:
metadata:
labels:
app: contour
spec:
containers:
- name: contour
image: ghcr.io/projectcontour/contour:v1.28.2
command:
- contour
- serve
- --xds-address=0.0.0.0
- --xds-port=8001
- --envoy-http-port=8080
- --envoy-https-port=8443
- --config-path=/config/contour.yaml
ports:
- name: xds
containerPort: 8001
- name: http
containerPort: 8080
- name: https
containerPort: 8443
livenessProbe:
httpGet:
path: /healthz
port: 8001
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: 8001
periodSeconds: 5
- name: envoy
image: ghcr.io/projectcontour/contour:v1.28.2
command:
- envoy
- -c
- /config/envoy.json
- --service-cluster
- projectcontour
- --service-node
- $(NODE_NAME)
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 84434.3 HTTPProxy CRD
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: demo-proxy
namespace: default
spec:
virtualhost:
fqdn: demo.example.com
cors:
allow-credentials: true
allow-headers:
- X-Custom-Header
allow-methods:
- GET
- POST
- PUT
- DELETE
allow-origin:
- "https://allowed.example.com"
max-age: "86400"
routes:
- conditions:
- prefix: /api
services:
- name: api-service
port: 80
healthcheck:
path: /health
interval: 10s
timeout: 5s
unhealthyThreshold: 3
healthyThreshold: 2
loadBalancerPolicy:
strategy: WeightedLeastRequest
retryPolicy:
retryOn: gateway-error,connect-failure,reset
numRetries: 3
perTryTimeout: 10s
- conditions:
- prefix: /
services:
- name: frontend-service
port: 80
rateLimit:
global:
descriptors:
- entries:
- key: remote_addr
rateLimitValue:
requests: 100
unit: minute
tcpproxy:
services:
- name: tcp-service
port: 9000
weight: 14.4 Rate Limiting
Envoy supports global token‑bucket rate limiting via TLSPolicy resources and per‑service annotations.
apiVersion: projectcontour.io/v1
kind: TLSPolicy
metadata:
name: ratelimit-policy
namespace: default
spec:
limits:
- units: second
requests: 100
condition:
- requestHeader:
headerName: X-Forwarded-For
count: 14.5 Health Checks & Load Balancing
Envoy provides active and passive health checks and supports multiple load‑balancing strategies (RoundRobin, WeightedLeastRequest, Random, Cookie, Header).
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: healthcheck-proxy
namespace: default
spec:
virtualhost:
fqdn: api.example.com
routes:
- services:
- name: api-service
port: 80
healthcheck:
path: /healthz
interval: 10s
timeout: 5s
expectedStatus: "200-299"
unhealthyThreshold: 3
healthyThreshold: 2Chapter 5 – Comprehensive Comparison
5.1 Performance
Solution QPS P99 Latency Memory
Nginx Ingress 50,000+ 5ms 150MB
Traefik v3 35,000+ 8ms 200MB
Envoy (Contour)40,000+ 6ms 300MB5.2 Feature Matrix
Feature Nginx Traefik Envoy (Contour)
Layer‑7 routing ✔ ✔ ✔
Layer‑4 proxy ✔ ✔ ✔
WebSocket ✔ ✔ ✔
gRPC ✔ ✔ ✔
TLS termination ✔ ✔ ✔
Auto‑HTTPS Cert‑Mgr ✔ Cert‑Mgr
Rate limiting Annotations/ConfigMap Middleware Global
Authentication Annotations Middleware CRD
Retry/Timeout Annotations Middleware CRD
Canary release Annotations – HTTPProxy
Circuit breaking – – ✔
Dynamic config reload hot‑reload hot‑reload
Metrics Prometheus Prometheus/Datadog Prometheus
Tracing Zipkin/Jaeger OpenTelemetry Zipkin/OTel5.3 Configuration Complexity
Nginx offers a familiar, annotation‑driven approach for engineers experienced with Nginx. Traefik provides the most concise declarative syntax via CRDs and Middleware. Envoy delivers the richest feature set but requires deeper understanding; Contour mitigates some complexity.
5.4 Ecosystem & Community
Nginx has the most mature enterprise ecosystem and commercial support. Traefik is backed by an active open‑source community and offers an enterprise edition. Envoy is a CNCF project, integral to service‑mesh solutions like Istio and Linkerd.
Chapter 6 – Selection Guidance & Best Practices
6.1 Scenario‑Based Selection
Small‑to‑medium clusters (<1000 Pods): Nginx or Traefik – simple config, strong docs.
Large, high‑traffic clusters: Nginx for raw performance or Envoy for fine‑grained traffic control.
Fine‑grained traffic management (canary, fault injection, circuit breaking): Envoy (Contour).
Service‑mesh integration: Envoy.
6.2 Deployment Architecture
For production, deploy the controller as a DaemonSet to guarantee an ingress point on every node.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ingress
namespace: ingress-nginx
spec:
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.9.4
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --report-node-internal-ip-address
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
hostPort: 80
containerPort: 80
- name: https
hostPort: 443
containerPort: 443Scale the controller with a HorizontalPodAutoscaler based on CPU and memory utilization.
6.3 Security Hardening
Example TLS configuration with HSTS and security headers for Nginx.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts-max-age: "31536000"
nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
nginx.ingress.kubernetes.io/server-snippet: |
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 806.4 Monitoring
Expose Prometheus metrics and use community dashboards.
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress-controller-metrics
namespace: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
ports:
- name: metrics
port: 10254
selector:
app: nginx-ingress
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nginx-ingress
namespace: monitoring
spec:
selector:
matchLabels:
app: nginx-ingress
endpoints:
- port: metrics
interval: 15s
namespaceSelector:
matchNames:
- ingress-nginxChapter 7 – Troubleshooting Guide
7.1 Checking Controller Status
# View controller logs
kubectl logs -n ingress-nginx -l app=nginx-ingress -f
# Recent events
kubectl get events -n ingress-nginx --sort-by='.lastTimestamp'
# Show current controller configuration
kubectl exec -n ingress-nginx deploy/nginx-ingress-controller -- nginx-ingress-controller --show-config7.2 Common Issues
Ingress returns 404 : Verify Ingress existence, host rules, Service endpoints, and Pod readiness.
TLS not working : Ensure the TLS Secret exists, contains valid cert/key, and is referenced correctly. Check Cert‑Manager status if used.
Rate limiting ineffective : Confirm annotation values or ConfigMap entries, and inspect controller logs for rate‑limit processing.
7.3 Performance Diagnosis
# Resource usage
kubectl top pods -n ingress-nginx
# Active connections (Nginx)
kubectl exec -it nginx-ingress-controller-xxx -n ingress-nginx -- wget -qO- http://localhost:10254/status
# Upstream status inspection
kubectl exec -it nginx-ingress-controller-xxx -n ingress-nginx -- cat /etc/nginx/nginx.conf | grep -A 50 "upstream"7.4 Log Analysis
# Extract slow requests (response time > 1s)
kubectl logs -n ingress-nginx -l app=nginx-ingress | \
awk '{if($NF > 1) print}' | sort -k9 -nr | head -20Conclusion
Nginx Ingress Controller, Traefik, and Envoy each excel in different areas: Nginx offers the highest raw performance and a mature ecosystem; Traefik provides the simplest configuration and hot‑reload capabilities; Envoy delivers the richest feature set and seamless integration with service‑mesh platforms. Selecting the right controller should consider team expertise, performance requirements, feature needs, and operational maturity. Regardless of the choice, implement robust monitoring, alerting, and disaster‑recovery procedures to ensure reliable production operation.
References
Kubernetes Ingress documentation: https://kubernetes.io/docs/concepts/services-networking/ingress/
Nginx Ingress Controller docs: https://kubernetes.github.io/ingress-nginx/
Traefik documentation: https://doc.traefik.io/traefik/
Contour (Envoy) documentation: https://projectcontour.io/docs/
Envoy documentation: https://www.envoyproxy.io/docs/envoy/latest/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Raymond Ops
Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
