Custom Kubernetes Ingress Default Backend and Error Pages
Tags: docker, devops, kubernetes, tutorial
Published: 2020-05-25 02:40:27

When you're setting up a Kubernetes cluster, one of the choices you need to make is what Ingress to use - or what combination of Ingresses *(Ingressi?)* to use.

I've used a number of Ingress Controllers in Kubernetes clusters on different clouds, and they all have their place and reason.  The classic choice however, is the now native Ingress option provided by the Kubernetes project, the [nginx-ingress controller](https://kubernetes.github.io/ingress-nginx/).

## Wait, what is an Ingress?

In the terms of a Kubernetes cluster, an **Ingress Controller** is a cluster resource that will route traffic into the services in the cluster, from external requests.  This is how `mycutedogs.com` gets translated and routed to the `side-sites/mycutedogs-com` namespace/service in the cluster.

## Blank and Bleak

When you deploy the Nginx Ingress Controller, you'll see some very basic error pages such as this:

![Boooooring](https://dev-to-uploads.s3.amazonaws.com/i/c3pcnxdb8xm4xilwbv4j.jpg)

But instead, what if you could make it look something like this:

![Betterrr](https://dev-to-uploads.s3.amazonaws.com/i/00sk0i354th8vm3do0a9.png)

## How this all works

So when you deploy the Nginx Ingress Controller, it listens on the edge of your Kubernetes cluster for traffic.  If it does not have a matching service to route to, it'll throw an error.  Those errors are served traditionally from the nginx-ingress-controller container, but you can override where those errors are served from with some modifications to the **Deployment** and **ConfigMap**.

In order to set up your own custom error pages you'll need to fork my repo, build your own copy of the container image with your own error HTML files, and do some modifications to the corresponding Deployment Config.

## Optional: Modify the error pages

If you'd like to set your own default-backend custom error pages, you'll need to do the following steps - if not and you'd just like to use the more spiffy versions I have available, continue to the **Deployment** steps

1. Fork my repo: https://github.com/kenmoini/custom-nginx-ingress-errors
2. Modify the error pages in the `www/` directory as you see fit
3. Connect to Docker Hub, Quay.io, etc to create your own available image
4. Modify the `k8s-deployment.yaml` file in the repo to point to your own image.

## Deployment

These instructions assume that you deployed the Ingress Controller in the default `ingress-nginx` namespace.

***1)*** Clone down my repo: https://github.com/kenmoini/custom-nginx-ingress-errors

```bash
git clone https://github.com/kenmoini/custom-nginx-ingress-errors
cd custom-nginx-ingress-errors
```

***2)*** Deploy to your Kubernetes cluster - the YAML file already targets the `nginx-ingress` namespace:

```bash
kubectl apply -f k8s-deployment.yaml
```

***3)*** Modify the `ingress-nginx/ingress-nginx-controller` **Deployment** and set the value of the `--default-backend-service` flag to the namespace/svc-name of the newly created error backend, which should be `ingress-nginx/nginx-errors` by default.

```bash
export KUBE_EDITOR="nano" # optional, switch to the Nano editor
kubectl edit deployment/ingress-nginx-controller -n ingress-nginx

---
apiVersion: apps/v1
kind: Deployment
[...]
spec:
  [...]
  template:
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --configmap=$(POD_NAMESPACE)/nginx-configuration
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
        - --publish-service=$(POD_NAMESPACE)/ingress-nginx
        - --annotations-prefix=nginx.ingress.kubernetes.io
        - --default-backend-service=$(POD_NAMESPACE)/nginx-errors
[...]
```

***4)*** Edit the `ingress-nginx/nginx-configuration` **ConfigMap** and add the key:value pair of `"custom-http-errors": "404,500,503"`:

```bash
kubectl edit cm/nginx-configuration -n ingress-nginx

---
apiVersion: v1
kind: ConfigMap
metadata:
 [...]
data:
  custom-http-errors: "404,500,503"
```

***5)*** Test your new error pages by navigating to the Ingress Load Balancer:

```bash
$ kc get services -n ingress-nginx
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
ingress-nginx   LoadBalancer   10.245.31.157   173.28.135.40   80:32563/TCP,443:30965/TCP   18d
nginx-errors    ClusterIP      10.245.17.217   <none>           80/TCP                       117m

$ curl -sS http://173.28.135.40

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Error 404</title>
[...]
```

## Bonus: Docker Hub Pre-Push Hook

This repo also has an extra file in `hooks/pre-hook` which creates another tag with the Git repo commit - it's pretty neat!