Ingress Controllers Compared: NGINX vs Traefik vs HAProxy
Intermediate · 7 min read
Key takeaways
- NGINX, Traefik, and HAProxy are popular Ingress controllers in Kubernetes, each with its own strengths and use cases.
- Understanding the core concepts and mechanics of Ingress controllers is crucial for effective traffic management.
- Common mistakes include incorrect annotations, misconfigured DNS, overlapping paths, and insufficient resources.
- Advanced topics like scaling, security, and performance tuning are essential for production environments.
The Problem
“>
In a modern, microservices-based architecture, managing incoming traffic to your applications can be a complex and challenging task. Imagine you are part of a DevOps team at a rapidly growing e-commerce platform. As the number of services and microservices increases, so does the complexity of routing incoming HTTP requests to the correct backend service. This is where Ingress controllers come into play. An Ingress controller acts as a reverse proxy, handling incoming traffic and directing it to the appropriate service. However, with multiple options available, such as NGINX, Traefik, and HAProxy, choosing the right one for your specific use case can be overwhelming. This tutorial will help you understand the key differences, trade-offs, and when to use each Ingress controller.
Core Concepts
Before diving into the comparison, let’s define some core concepts:
- Kubernetes: An open-source container orchestration system that automates the deployment, scaling, and management of containerized applications.
- Ingress: An API object in Kubernetes that manages access to cluster services. It provides a way to route incoming traffic to different services based on rules defined in the Ingress resource.
- Ingress Controller: A component that implements the Ingress API by providing an implementation for a network load balancer. It watches the Kubernetes API for Ingress resources and configures the underlying load balancer (e.g., NGINX, Traefik, HAProxy) to route traffic according to the rules specified in the Ingress resources.
How It Works
An Ingress controller works by watching the Kubernetes API for Ingress resources and updating the configuration of the underlying load balancer. Here’s a high-level overview of the process:
- A developer or DevOps engineer creates an Ingress resource in the Kubernetes cluster, specifying the routing rules.
- The Ingress controller, which is running as a pod in the cluster, detects the new Ingress resource.
- The Ingress controller updates the configuration of the load balancer (e.g., NGINX, Traefik, HAProxy) to reflect the new routing rules.
- Incoming traffic is directed to the load balancer, which then routes the traffic to the appropriate backend service based on the rules defined in the Ingress resource.
Prerequisites
Before you start, ensure you have the following:
- A Kubernetes cluster up and running. You can use Minikube, Kind, or any other Kubernetes distribution.
- kubectl installed and configured to interact with your Kubernetes cluster.
- Basic understanding of Kubernetes concepts such as pods, services, and deployments.
Hands-On Walkthrough
Let’s go through a step-by-step walkthrough of setting up and comparing NGINX, Traefik, and HAProxy Ingress controllers.
1. Install NGINX Ingress Controller
Create a namespace for the NGINX Ingress controller:
kubectl create namespace nginx-ingress
Deploy the NGINX Ingress controller using the official Helm chart:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx --namespace nginx-ingress
Create a simple web application and expose it via an Ingress resource:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-nginx
spec:
replicas: 1
selector:
matchLabels:
app: webapp-nginx
template:
metadata:
labels:
app: webapp-nginx
spec:
containers:
- name: webapp-nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webapp-nginx
spec:
selector:
app: webapp-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: webapp-nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-nginx
port:
number: 80
EOF
2. Install Traefik Ingress Controller
Create a namespace for the Traefik Ingress controller:
kubectl create namespace traefik-ingress
Deploy the Traefik Ingress controller using the official Helm chart:
helm repo add traefik https://traefik.io/helm-charts
helm repo update
helm install traefik traefik/traefik --namespace traefik-ingress
Create a simple web application and expose it via an Ingress resource:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-traefik
spec:
replicas: 1
selector:
matchLabels:
app: webapp-traefik
template:
metadata:
labels:
app: webapp-traefik
spec:
containers:
- name: webapp-traefik
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webapp-traefik
spec:
selector:
app: webapp-traefik
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-traefik
annotations:
traefik.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: webapp-traefik.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-traefik
port:
number: 80
EOF
3. Install HAProxy Ingress Controller
Create a namespace for the HAProxy Ingress controller:
kubectl create namespace haproxy-ingress
Deploy the HAProxy Ingress controller using the official Helm chart:
helm repo add haproxy-ingress https://haproxy-ingress.github.io/charts
helm repo update
helm install haproxy haproxy-ingress/haproxy-ingress --namespace haproxy-ingress
Create a simple web application and expose it via an Ingress resource:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-haproxy
spec:
replicas: 1
selector:
matchLabels:
app: webapp-haproxy
template:
metadata:
labels:
app: webapp-haproxy
spec:
containers:
- name: webapp-haproxy
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webapp-haproxy
spec:
selector:
app: webapp-haproxy
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-haproxy
annotations:
haproxy.org/rewrite-target: /
spec:
rules:
- host: webapp-haproxy.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-haproxy
port:
number: 80
EOF
Verifying It Works
To verify that the Ingress controllers are working correctly, you can use the following commands:
For NGINX Ingress:
kubectl get ingress -n nginx-ingress
kubectl exec -it -n nginx-ingress $(kubectl get pods -n nginx-ingress -l app.kubernetes.io/name=ingress-nginx -o jsonpath='{.items[0].metadata.name}') -- curl -I http://webapp-nginx.example.com
For Traefik Ingress:
kubectl get ingress -n traefik-ingress
kubectl exec -it -n traefik-ingress $(kubectl get pods -n traefik-ingress -l app.kubernetes.io/name=traefik -o jsonpath='{.items[0].metadata.name}') -- curl -I http://webapp-traefik.example.com
For HAProxy Ingress:
kubectl get ingress -n haproxy-ingress
kubectl exec -it -n haproxy-ingress $(kubectl get pods -n haproxy-ingress -l app.kubernetes.io/name=haproxy-ingress -o jsonpath='{.items[0].metadata.name}') -- curl -I http://webapp-haproxy.example.com
You should see a 200 OK response, indicating that the Ingress controller is correctly routing traffic to the backend service.
Common Mistakes
Here are some common mistakes to avoid when setting up and using Ingress controllers:
- Incorrect Annotations: Each Ingress controller has its own set of annotations. Using the wrong annotations can lead to unexpected behavior. Always refer to the documentation for the specific Ingress controller you are using.
- Misconfigured DNS: The Ingress controller relies on DNS to resolve the hostnames specified in the Ingress rules. Ensure that your DNS is correctly configured to point to the Ingress controller’s IP address.
- Overlapping Paths: If multiple Ingress rules specify overlapping paths, it can lead to conflicts. Make sure that the paths in your Ingress rules are unique and do not overlap.
- Insufficient Resources: The Ingress controller runs as a pod in the Kubernetes cluster. If the pod does not have enough resources (CPU, memory), it may become unresponsive. Monitor the resource usage and scale the Ingress controller as needed.
Going Further
Once you have a basic setup and understanding of Ingress controllers, you can explore more advanced topics:
- Scaling: In a production environment, you may need to scale the Ingress controller to handle a large volume of incoming traffic. This can be done by increasing the number of replicas or by using a more powerful node for the Ingress controller.
- Security: Consider enabling TLS/SSL for secure communication. Most Ingress controllers support Let’s Encrypt for automatic certificate management. Additionally, you can configure authentication and authorization to restrict access to certain services.
- Performance Tuning: Each Ingress controller has its own set of performance tuning options. For example, NGINX allows you to tune the worker processes and connections, while Traefik offers dynamic configuration and hot-reloading. Refer to the documentation for the specific Ingress controller for performance optimization tips.
- Alternative Approaches: While NGINX, Traefik, and HAProxy are popular choices, there are other Ingress controllers available, such as Envoy and Ambassador. Each has its own strengths and weaknesses. For example, Envoy is known for its advanced features and integration with Istio, while Ambassador is designed for ease of use and developer experience. Evaluate these alternatives based on your specific requirements and constraints.
Cleanup
To remove the Ingress controllers and the associated resources, use the following commands:
For NGINX Ingress:
kubectl delete -n nginx-ingress ingress webapp-nginx
kubectl delete -n nginx-ingress service webapp-nginx
kubectl delete -n nginx-ingress deployment webapp-nginx
helm uninstall nginx-ingress -n nginx-ingress
kubectl delete namespace nginx-ingress
For Traefik Ingress:
kubectl delete -n traefik-ingress ingress webapp-traefik
kubectl delete -n traefik-ingress service webapp-traefik
kubectl delete -n traefik-ingress deployment webapp-traefik
helm uninstall traefik -n traefik-ingress
kubectl delete namespace traefik-ingress
For HAProxy Ingress:
kubectl delete -n haproxy-ingress ingress webapp-haproxy
kubectl delete -n haproxy-ingress service webapp-haproxy
kubectl delete -n haproxy-ingress deployment webapp-haproxy
helm uninstall haproxy -n haproxy-ingress
kubectl delete namespace haproxy-ingress
Architecture

References
This article was written with AI assistance.
