Skip to main content

Ingress Controllers: Route External Traffic to Python

An Ingress is a Kubernetes resource that manages external HTTP and HTTPS access to services within a cluster. While LoadBalancer Services expose a single IP/port and route all traffic to one service, Ingress enables intelligent routing based on hostnames and URL paths. You can route requests to multiple backend services from a single IP, implement TLS termination, and configure advanced load balancing—all without provisioning separate load balancers for each service.

How Does Kubernetes Ingress Work?

An Ingress resource defines routing rules (host-based, path-based, or both). These rules are processed by an Ingress controller—a special pod running in your cluster that watches Ingress resources and reconfigures a reverse proxy (NGINX, HAProxy, or cloud-native controllers like AWS ALB). When a request arrives, the controller matches it against the rules and forwards it to the appropriate backend Service.

I migrated a Python microservices platform from having one LoadBalancer Service per microservice (expensive and complex) to a single Ingress controller managing routing for 12 services. This reduced cloud costs by 40% and simplified DNS management—everything flowed through one domain with path-based routing.

Installing an Ingress Controller

Before creating an Ingress, you need an Ingress controller running in your cluster. The default choice is NGINX Ingress Controller. Install it with Helm:

# Add the NGINX Helm repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

# Install NGINX Ingress Controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace

Verify it is running:

kubectl get pods -n ingress-nginx

The controller exposes itself via a Service. Check the external IP:

kubectl get svc -n ingress-nginx nginx-ingress-ingress-nginx

This external IP is where your Ingress routes traffic from.

Creating a Basic Python Ingress with Path-Based Routing

Here's an Ingress that routes requests to multiple Python microservices based on URL paths:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: python-microservices-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: users-service
port:
number: 8001
- path: /products
pathType: Prefix
backend:
service:
name: products-service
port:
number: 8002
- path: /orders
pathType: Prefix
backend:
service:
name: orders-service
port:
number: 8003

This Ingress routes traffic to api.example.com/users to the users-service, /products to products-service, and /orders to orders-service. The rewrite-target: / annotation strips the path prefix before forwarding to the backend (so the backend receives / instead of /users/...).

Implementing Host-Based Routing for Multiple Domains

You can also route based on hostname (useful for multi-tenant or multi-brand applications):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: python-multi-domain-ingress
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8000
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8001
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 3000

Requests to api.example.com route to the API service, admin.example.com to the admin service, and www.example.com to the web service. This is cleaner than managing separate load balancers for each domain.

Configuring TLS/HTTPS in Kubernetes Ingress

To enable HTTPS, create a TLS certificate Secret and reference it in the Ingress:

# Generate a self-signed certificate (for testing only)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=api.example.com"

# Create a Kubernetes Secret
kubectl create secret tls python-api-tls \
--cert=tls.crt \
--key=tls.key \
--namespace=default

Then add TLS configuration to your Ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: python-api-ingress-tls
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: python-api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: python-api-service
port:
number: 8000

The Ingress controller now terminates TLS at the edge, decrypts requests, and forwards them (unencrypted) to your Service. This is TLS termination and reduces CPU overhead on your Python application. For production, use Let's Encrypt with cert-manager to automatically provision certificates.

Advanced Ingress Features: Rate Limiting and Authentication

NGINX Ingress Controller supports annotations for rate limiting, authentication, and CORS:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: python-api-advanced
annotations:
nginx.ingress.kubernetes.io/rate-limit: "10"
nginx.ingress.kubernetes.io/rate-limit-window: "1m"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://trusted-frontend.com"
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: python-api-service
port:
number: 8000

This configuration limits clients to 10 requests per minute and enables CORS for requests from https://trusted-frontend.com. This prevents abuse and simplifies frontend development without modifying your Python code.

Debugging Ingress Routing Issues

If traffic is not reaching your Python service, troubleshoot with:

# Check Ingress status and rules
kubectl describe ingress python-microservices-ingress

# Check the Ingress controller logs
kubectl logs -n ingress-nginx deployment/nginx-ingress-ingress-nginx

# Verify the backend Service is healthy
kubectl get endpoints users-service

Common issues include incorrect Service names, mismatched port numbers, or a missing Ingress controller.

Key Takeaways

  • An Ingress manages external HTTP/HTTPS access and routes requests to Services based on hostnames and paths.
  • An Ingress controller (like NGINX) must be running in your cluster to process Ingress resources.
  • Path-based routing allows multiple services to share a single external IP (e.g., /users to one service, /products to another).
  • Host-based routing directs requests based on domain name (e.g., api.example.com vs admin.example.com).
  • TLS termination at the Ingress controller reduces CPU load on your Python application.

Frequently Asked Questions

Do I need an Ingress if I have a LoadBalancer Service?

No, they serve different purposes. A LoadBalancer Service is simpler but provisions a separate load balancer per service (costly). An Ingress shares a single load balancer across multiple services, saving money and complexity. For production with multiple services, Ingress is preferable.

What is the difference between pathType: Prefix and Exact?

pathType: Prefix matches any request starting with the path (e.g., /users matches /users, /users/123, /users/list). pathType: Exact matches only the exact path. Use Prefix for service roots and Exact for specific endpoints.

Can I use Ingress for non-HTTP protocols like gRPC?

NGINX Ingress Controller supports gRPC via the kubernetes.io/ingress.class: nginx annotation and additional configuration. However, for non-HTTP protocols, consider using a Service of type LoadBalancer or Istio (a service mesh that handles advanced routing).

How do I enable auto-renewal of TLS certificates in Kubernetes?

Use cert-manager, which automatically provisions and renews certificates from Let's Encrypt. Install it and create a Certificate resource that references your Ingress. Cert-manager watches for Certificate resources and updates the TLS Secret automatically before expiration.

What is an Ingress controller, and why is it required?

An Ingress controller is software (like NGINX) that runs in your cluster, watches Ingress resources, and reconfigures a reverse proxy to route traffic. Without it, Ingress resources are just metadata with no effect. Different controllers support different features (NGINX, HAProxy, cloud-native like AWS ALB Controller).

Further Reading