Post

Set up a Nginx Ingress on k8s

Hello everyone, it’s me again. Today is the first day of the Year of the Snake 2025, according to Eastern tradition. I wish you a new year full of health and energy for the challenges and opportunities ahead. In the previous article, we set up a Kubernetes cluster using k0s. Now, let’s talk about how to expose services running inside the cluster to the outside world using Ingress.

Kubernetes Ingress is a powerful API object that manages external access to services, typically HTTP and HTTPS traffic. Instead of exposing each service with a separate LoadBalancer or NodePort, Ingress provides a more flexible and cost-effective way to route traffic using a single entry point.

Prerequisites

  • A working Kubernetes cluster set up using k0s (refer to Part 1 of this blog series).
  • At least one Worker Node.
  • kubectl configured to access your cluster.
  • A domain name (optional but recommended for practical Ingress usage).

Deploying a Load Balancer with MetalLB

Since k0s does not come with an in-built load balancer, we need to deploy MetalLB to provide external IP addresses to services of type LoadBalancer.

Step 1: Install MetalLB

1
2
3
4
# Apply the MetalLB manifests
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/config/manifests/metallb-native.yaml
# Wait for the MetalLB pods to be in Running state
kubectl get pods -n metallb-system

Step 2: Configure an IP Address Pool

Create a configuration file for MetalLB:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - <ip-address-range-start>-<ip-address-range-stop>
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system

Apply the configuration:

1
kubectl apply -f metallb-config.yaml

Now, MetalLB will assign external IPs to LoadBalancer services in the cluster.

Install an Ingress Controller

Kubernetes itself does not provide an Ingress Controller by default. We need to install one. For this guide, we’ll use Nginx Ingress Controller.

First, apply the official Nginx Ingress Controller YAML manifest:

1
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

Wait for the Ingress Controller pods to be in Running state:

1
kubectl get pods -n ingress-nginx

Expected output:

1
2
NAME                                       READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-xxxxxxxxxx-xxxxx   1/1     Running   0          1m

Deploy a Sample Application

Now, let’s deploy a simple application inside the cluster to test Ingress.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
  labels:
    app: hello-world
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello-world
        image: ealen/echo-server
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world-service
spec:
  selector:
    app: hello-world
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP

Apply this configuration:

1
kubectl apply -f hello-world.yaml

Configure Ingress

Now, let’s create an Ingress resource to route external traffic to our service.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: hello-world.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-world-service
            port:
              number: 80

Apply the Ingress resource:

1
kubectl apply -f ingress.yaml

Test the Ingress

If you are using a domain, configure your DNS to point to the cluster’s external IP. If not, you can test using /etc/hosts:

1
2
echo "<INGRESS_IP> hello-world.local" | sudo tee -a /etc/hosts
curl http://hello-world.local

Expected reponse:

1
2
3
4
5
{
  "host": "hello-world-service",
  "headers": { ... },
  "method": "GET"
}

Conclusion

Using Kubernetes Ingress, you can efficiently expose services without relying on multiple LoadBalancers. With the Nginx Ingress Controller, routing HTTP traffic becomes easy and manageable. Try adding more rules to handle different paths or subdomains!

References

Here are couple other articles that you can follow:

This post is licensed under CC BY 4.0 by the author.