[11/24] I is for Ingress: Managing External Access


This is Post #10 in the Kubernetes A-to-Z Series

Reading Order: Previous: ConfigMaps and Secrets | Next: Helm

Series Progress: 11/24 complete | Difficulty: Intermediate | Time: 25 min | Part 4/6: Advanced Concepts

Welcome to the tenth post in our Kubernetes A-to-Z Series! Now that you understand configuration management, let’s explore Ingress - the Kubernetes resource for managing external access to services. Ingress provides HTTP/HTTPS routing, load balancing, and TLS termination for your applications.

Why Ingress?

Without Ingress, exposing multiple services requires multiple LoadBalancers (expensive) or NodePorts (limited):

Without Ingress:
┌─────────────────────────────────────────────────┐
│  External Traffic                               │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ LB $$$  │ │ LB $$$  │ │ LB $$$  │           │
│  └────┬────┘ └────┬────┘ └────┬────┘           │
│       │           │           │                 │
│       ▼           ▼           ▼                 │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ Service │ │ Service │ │ Service │           │
│  │   API   │ │   Web   │ │  Admin  │           │
│  └─────────┘ └─────────┘ └─────────┘           │
└─────────────────────────────────────────────────┘
Multiple LoadBalancers = High Cost

With Ingress:
┌─────────────────────────────────────────────────┐
│  External Traffic                               │
│  ┌─────────────────────────────────────┐        │
│  │     Single LoadBalancer             │        │
│  └──────────────┬──────────────────────┘        │
│                 │                               │
│  ┌──────────────▼──────────────────────┐        │
│  │     Ingress Controller              │        │
│  │  /api → API  /web → Web  /admin →   │        │
│  └──────────────┬──────────────────────┘        │
│       │         │         │                     │
│       ▼         ▼         ▼                     │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ Service │ │ Service │ │ Service │           │
│  └─────────┘ └─────────┘ └─────────┘           │
└─────────────────────────────────────────────────┘
Single entry point = Cost effective

Ingress Benefits

  • Cost Efficiency: Single LoadBalancer for multiple services
  • Centralized Routing: Path and host-based routing rules
  • TLS Termination: Manage SSL certificates in one place
  • Advanced Features: Rate limiting, authentication, rewrites

Ingress Components

1. Ingress Controller

The controller implements the Ingress rules. Popular options:

  • NGINX Ingress Controller (most common)
  • Traefik
  • HAProxy
  • AWS ALB Ingress Controller
  • GCE Ingress Controller

2. Ingress Resource

The configuration that defines routing rules.

Installing NGINX Ingress Controller

# Using Helm
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

# Verify installation
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

Basic Ingress Configuration

Simple Path-Based Routing

# basic-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webapp-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Host-Based Routing

# host-based-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
  namespace: production
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

Path Types

TypeDescriptionExample Match
ExactExact URL match/api matches only /api
PrefixURL prefix match/api matches /api, /api/users
ImplementationSpecificController-dependentVaries
# path-types-example.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-types-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Exact
        backend:
          service:
            name: api-exact-service
            port:
              number: 8080
      - path: /api/
        pathType: Prefix
        backend:
          service:
            name: api-prefix-service
            port:
              number: 8080

TLS/SSL Configuration

Basic TLS Setup

# tls-ingress.yaml
apiVersion: v1
kind: Secret
metadata:
  name: webapp-tls
  namespace: production
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTi... # Base64 encoded certificate
  tls.key: LS0tLS1CRUdJTi... # Base64 encoded private key
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    - api.example.com
    secretName: webapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Automatic TLS with Cert-Manager

# cert-manager-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auto-tls-ingress
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls-auto
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 80

Advanced Annotations

NGINX Ingress Annotations

# advanced-annotations.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: advanced-ingress
  namespace: production
  annotations:
    # SSL/TLS
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

    # Timeouts
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"

    # Body size
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"

    # Rate limiting
    nginx.ingress.kubernetes.io/limit-rps: "100"
    nginx.ingress.kubernetes.io/limit-connections: "10"

    # CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"

    # Rewrites
    nginx.ingress.kubernetes.io/rewrite-target: /$2

    # Sticky sessions
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

URL Rewriting

# rewrite-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      # /api/users -> /users on backend
      - path: /api(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Basic Authentication

# basic-auth-ingress.yaml
apiVersion: v1
kind: Secret
metadata:
  name: basic-auth
  namespace: production
type: Opaque
data:
  # htpasswd -c auth admin
  auth: YWRtaW46JGFwcjEkSDZ... # base64 encoded htpasswd
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auth-ingress
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
spec:
  ingressClassName: nginx
  rules:
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

Complete Production Example

# production-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: production-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.example.com
    - api.example.com
    - admin.example.com
    secretName: production-tls
  rules:
  # Main website
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80
  # API
  - host: api.example.com
    http:
      paths:
      - path: /v1
        pathType: Prefix
        backend:
          service:
            name: api-v1-service
            port:
              number: 8080
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: api-v2-service
            port:
              number: 8080
  # Admin panel
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

Default Backend

Handle unmatched requests:

# default-backend-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-with-default
spec:
  ingressClassName: nginx
  defaultBackend:
    service:
      name: default-service
      port:
        number: 80
  rules:
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

Troubleshooting

# Check Ingress status
kubectl get ingress -A
kubectl describe ingress webapp-ingress -n production

# Check Ingress Controller logs
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx

# Check Ingress Controller service
kubectl get svc -n ingress-nginx

# Test DNS resolution
nslookup myapp.example.com

# Test connectivity
curl -v https://myapp.example.com

# Check TLS certificate
openssl s_client -connect myapp.example.com:443 -servername myapp.example.com

# Check backend service
kubectl get endpoints api-service -n production

Commands Reference

# Ingress Management
kubectl get ingress -A
kubectl describe ingress webapp-ingress -n production
kubectl delete ingress webapp-ingress -n production

# Ingress Controller
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx

# TLS Secrets
kubectl create secret tls webapp-tls --cert=tls.crt --key=tls.key -n production
kubectl get secrets -n production | grep tls

# Testing
curl -H "Host: myapp.example.com" http://INGRESS_IP/
curl -k https://myapp.example.com/

Key Takeaways

  • Ingress provides HTTP/HTTPS routing to services
  • Ingress Controller implements the routing rules
  • Path-based and host-based routing supported
  • TLS termination centralizes certificate management
  • Annotations enable advanced features (rate limiting, auth, rewrites)
  • Cert-manager automates TLS certificate provisioning

Next Steps

Now that you understand Ingress, you’re ready to explore Helm in the next post. We’ll learn how to package, deploy, and manage Kubernetes applications using Helm charts.

Resources for Further Learning


Series Navigation:

Complete Series: Kubernetes A-to-Z Series Overview