Deploying and Configuring Ingress-Nginx in Kubernetes

Ingress Overview

Layer 7 Load Balancing Requirements

When clients access Kubernetes services, Layer 4 load balancers cannot terminate SSL sessions. This creates two significant issues: clients must establish direct SSL connections with backend pods, and if a request is routed to a different server after the SSL session is established, the session must be renegotiated.

For internal networks, we can safely terminate SSL at the load balancer and use plain HTTP internally. However, Kubernetes iptables and IPVS-based Services operate at Layer 4, meaning applications requiring HTTPS must terminate SSL in each pod.

To address this, Kubernetes employs a specialized architecture:

  1. Backend pods serve plaintext HTTP
  2. A dedicated proxy pod (running nginx, haproxy, or similar) terminates SSL
  3. The proxy pod communicates directly with backend pods
  4. Traffic flow: Client → LB → NodePort → Service → SSL Termination Pod → Backend Pod

Network Namespace Sharing

Containers can share the host's network namespace by setting hostNetwork: true. This allows the pod to bind to host ports directly, making it accessible without port mapping. However, this limits the pod to one instance per node.

DaemonSet for High Availability

Using a DaemonSet controller ensures the SSL termination proxy runs on every node. This provides:

  • Automatic failover if a node fails
  • Traffic routing to any available node
  • Resource efficiency through node selection (using taints and tolerasions)

For large clusters, designate specific nodes for ingress traffic by applying taints and using node affinity.

Ingress Controller Options

Ingress Controllers are standalone applications providing Layer 7 proxy capabilities. Common options include:

Controller Characteristics
nginx Modified for Kubernetes, widely adopted
Traefik Designed for microservices, dynamic configuration
Envoy Popular in service mesh architectures
HAProxy Less commonly used

How Ingress Works

When multiple services need routing through a single proxy:

  1. Each service uses a selector to group backend pods
  2. Ingress defines routing rules (virtual hosts or URL paths)
  3. Ingress Controller watches API server for changes
  4. Configuration updates are injected into the proxy without manual reloads

The key difference from traditional nginx is that Ingress monitors pod changes and dynamically updates upstream configuration. Traefik and Envoy handle this natively, while nginx requires configuration reloads on changes.

Ingress Resource Definition

Ingress is a standard Kubernetes resource with the following structure:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
spec:
  backend:  # Optional default backend
    serviceName: default-service
    servicePort: 80
  rules:    # Routing rules (host-based or path-based)
  - host: example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: frontend
          servicePort: 80
  tls:      # TLS configuration
  - hosts:
    - secure.example.com
    secretName: tls-secret

Key fields:

  • spec.backend: Default backend for unmatched requests
  • spec.rules: Host and path-based routing rules
  • spec.tls: TLS termination configuration
  • backend.serviceName: References a Service for pod discovery
  • backend.servicePort: Target port on the backend service

Deploying Ingress-Nginx

Component Overview

The deployment consists of several YAML files:

File Purpose
namespace.yaml Creates ingress-nginx namespace
configmap.yaml Stores nginx configuration variables
rbac.yaml Defines RBAC permissions for the controller
default-backend.yaml Handles 404 for unmatched requests
mandatory.yaml Core ingress-controller deployment

Deployment Steps

Download the deployment files:

# Latest version
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

# Specific version
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.20.0/deploy/mandatory.yaml

Download all required files:

for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml \
  udp-services-configmap.yaml default-backend.yaml mandatory.yaml; do
  wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.17.1/deploy/$file
done

Apply all configurations:

kubectl apply -f ./

Verify deployment:

kubectl get pods -n ingress-nginx

Exposing Ingress Controller

For external access, create a NodePort Service:

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
    nodePort: 30080
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
    nodePort: 30443
  selector:
    app: ingress-nginx

Apply and verify:

kubectl apply -f service-nodeport.yaml

Test by accessing a non-existent path:

curl http://<node-ip>:30080/

Expected response: default backend - 404

Example Application with Ingress

Create Backend Deployment

apiVersion: v1
kind: Service
metadata:
  name: demo-app
  namespace: default
spec:
  selector:
    app: demo
    version: stable
  ports:
  - name: http
    targetPort: 80
    port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
      version: stable
  template:
    metadata:
      labels:
        app: demo
        version: stable
    spec:
      containers:
      - name: demo-app
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80

Define Ingress Rules

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: demo.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: demo-app
          servicePort: 80

Deploy and verify:

kubectl apply -f demo-app.yaml
kubectl apply -f ingress-demo.yaml
kubectl get ingress -n default
kubectl describe ingress demo-ingress -n default

Add the host entry to /etc/hosts:

<node-ip> demo.example.com

Access the application:

curl http://demo.example.com:30080/

Configuring HTTPS with Ingress

Create Backend Services

Deploy Tomcat pods with associated Service:

apiVersion: v1
kind: Service
metadata:
  name: webapp
  namespace: default
spec:
  selector:
    app: webapp
    environment: production
  ports:
  - name: http
    targetPort: 8080
    port: 8080
  - name: ajp
    targetPort: 8009
    port: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webapp
      environment: production
  template:
    metadata:
      labels:
        app: webapp
        environment: production
    spec:
      containers:
      - name: webapp
        image: tomcat:8.5.32-jre8-alpine
        ports:
        - name: http
          containerPort: 8080
        - name: ajp
          containerPort: 8009

Define Ingres with Host-Based Routing

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webapp-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: webapp.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: webapp
          servicePort: 8080

Deploy:

kubectl apply -f webapp-deploy.yaml
kubectl apply -f ingress-webapp.yaml

Generate TLS Certificate

Create private key and certificate:

openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt \
  -subj /C=US/ST=California/L=SanFrancisco/O=DevOps/CN=webapp.example.com

Create Kubernetes Secret:

kubectl create secret tls webapp-tls-secret \
  --cert=server.crt --key=server.key
kubectl get secret

Configure TLS in Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: webapp-ingress-tls
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - webapp.example.com
    secretName: webapp-tls-secret
  rules:
  - host: webapp.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: webapp
          servicePort: 8080

Deploy and test:

kubectl apply -f ingress-tls.yaml
curl https://webapp.example.com:30443/ -k

Alternative Deployment: Host Network Mode

For direct host binding without NodePort:

  1. Modify deployment to use DaemonSet
  2. Enable host network:
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
spec:
  selector:
    matchLabels:
      app: ingress-nginx
  template:
    metadata:
      labels:
        app: ingress-nginx
    spec:
      hostNetwork: true
      containers:
      - name: nginx-ingress-controller
        image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.20.0
        securityContext:
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
          - /nginx-ingress-controller
          - --configmap=$(POD_NAMESPACE)/nginx-configuration

This allows direct access to ingress on host ports (80 and 443) without Service exposure.

Mirror Repository Reference

For environments with limited access to official registries:

Original Image Mirror
quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1 linuxhub/nginx-ingress-controller:0.24.1
k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3 linuxhub/kubernetes-dashboard-amd64:v1.8.3
gcr.io/kubernetes-helm/tiller:v2.11.0 linuxhub/tiller:v2.11.0
k8s.gcr.io/elasticsearch:v5.6.4 linuxhub/elasticsearch:v5.6.4
k8s.gcr.io/coredns:1.0.6 linuxhub/coredns:1.0.6

Replace images in YAML files before deployment to ensure successful installation.

Tags: kubernetes Ingress-Nginx Load Balancing SSL Termination networking

Posted on Sat, 09 May 2026 20:47:54 +0000 by SpasePeepole