Traditional NodePort services in Kubernetes face critical limitations: each service requires a dedicated port, leading to port exhaustion, and they operate only at Layer 4 (TCP/UDP), lacking HTTP-aware routing capabilities. Ingress addresses these gaps by providing a Layer 7 HTTP(S) routing layer that abstracts external access through domain-based rules and centralized control.
Ingress resources themself are declarative configurations—they define routing rules but require an Ingress Controller to enforce them. The controller acts as a reverse proxy and load balancer, typically based on NGINX, Traefik, or Istio. For this guide, we use the official Kubernetes-maintained NGINX Ingress Controller.
To deploy the controller:
- Use a container image hosted in a domestic registry (e.g.,
lizhenliang/nginx-ingress-controller:0.20.0) to avoid pull failures. - Enable
hostNetwork: trueso the controller binds directly to the host’s network interfaces on ports 80 and 443.
kubectl apply -f ingress-controller.yaml
kubectl get pods -n ingress-nginx
After deployment, verify the controller is listening:
netstat -natp | grep -E ":80|:443"
# Output shows nginx listening on 0.0.0.0:80 and 0.0.0.0:443
These ports now serve as the entry point for all HTTP/HTTPS traffic destined for cluster services.
Configuring Ingress Rules
An Ingress resource maps hostnames and paths to backend services. Core components include:
host: The domain name used to access the serviceserviceName: The Kubernetes Service nameservicePort: The port exposed by the Service
HTTP Routing
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: http-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: web-app
servicePort: 80
In production, point the domain’s A record to a Node with the Ingress Controller. For testing, override DNS locally via /etc/hosts:
192.168.31.62 app.example.com
HTTPS with TLS Termination
First, generate a certificate using CFSSL:
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
chmod +x cfssl* && mv cfssl* /usr/bin/
cat > ca-config.json <<eof auth="" cat="" encipherment="" eof=""> ca-csr.json <<eof ca="" ca-csr.json="" cat="" cfssl="" cfssljson="" eof="" gencert=""> app.example.com-csr.json <<eof app-tls="" app.example.com="" app.example.com-csr.json="" cfssl="" cfssljson="" create="" eof="" gencert="" kubectl="" secret="" tls=""></eof></eof></eof>
Then reference the secret in the Ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-ingress
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: web-app
servicePort: 80
Path-Based Routing
Route different URL paths to seperate services:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: path-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: api.example.com
http:
paths:
- path: /v1
backend:
serviceName: service-v1
servicePort: 80
- path: /v2
backend:
serviceName: service-v2
servicePort: 80
Name-Based Virtual Hosts
Host multiple domains on the same IP:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: vhost-ingress
spec:
rules:
- host: site1.example.com
http:
paths:
- backend:
serviceName: service-a
servicePort: 80
- host: site2.example.com
http:
paths:
- backend:
serviceName: service-b
servicePort: 80
Customizing Behavior with Annotations
NGINX Ingress supports fine-grained tuning via annotations:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tuned-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/ssl-redirect: "false" # Disable HTTP→HTTPS redirect
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
backend:
serviceName: web-app
servicePort: 80
High Availability Strategies
Runing a single Ingress Controller creates a single point of failure. Two common solutions:
- Active-Passive with Keepalived: Deploy two controllers on dedicated nodes, assign a Virtual IP (VIP) that floats between them.
- Load-Balanced Cluster (Recommended): Place a cloud or hardware load balancer (e.g., HAProxy, MetalLB) in front of multiple Ingress Controller replicas. This scales horizontally and eliminates single-node dependencies.
For production environments, always deploy at least two replicas of the Ingress Controller across separate nodes and configure external load balancing to distribute traffic.