Install the Nginx ingress controller on K3s - or Kind - and deploy a web app

Here is how to quickly install Kubernetes with ingress on your laptop. I use this to test and create operators with the Operator Framework. Still learning though.

I was first using K3s but then I discovered Kind which seems to be even faster, deployment wise. Also it leaves a smaller footprint because it runs in a Docker container. (Didn't manage to run it with podman yet). So I quickly added a paragraph about Kind if you scroll down this post.

K3s

When running K3s, by default Traefik is installed as an ingress controller. You need an ingress controller to expose (web) applications to the outside world. I am however more comfortable with the Nginx ingress controller so let's just install that instead.

In this post I will first install K3s, then install the Nginx ingress controller. Finally I will deploy a little go application (which is going to be fabulous later).

Install K3s with Nginx ingress

1curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644 --disable traefik

Wait a bit. When done, we can copy the config file so we can use kubectl.

1mkdir ~/.kube
2sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config

Now we are ready to install Nginx ingress:

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

With running kubectl get pods --all-namespaces -w we can check the progress

1[vagrant@centos02 ~]$ kubectl get pods --all-namespaces -w
2NAMESPACE       NAME                                        READY   STATUS              RESTARTS   AGE
3kube-system     coredns-66c464876b-2f5gq                    1/1     Running             0          21m
4kube-system     local-path-provisioner-7ff9579c6-ms2qx      1/1     Running             0          21m
5kube-system     metrics-server-7b4f8b595-2kxvv              1/1     Running             0          21m
6ingress-nginx   ingress-nginx-controller-7474996559-79ztf   0/1     ContainerCreating   0          21s
7ingress-nginx   ingress-nginx-admission-patch-km6v8         0/1     Completed           0          21s
8ingress-nginx   ingress-nginx-admission-create-6jqz4        0/1     Completed           0          21s

Great, we have an ingress controller now. But, we do not have a load balancer. So we need to enable the ingress controller to use port 80 and 443 on the host. Let's patch the ingress controller.

Create the patch first:

1cat > ingress.yaml <<EOF 
2spec:
3  template:
4    spec:
5      hostNetwork: true
6EOF

Then patch the ingress controller deployment like so:

1kubectl patch deployment ingress-nginx-controller -n ingress-nginx --patch "$(cat ingress.yaml)"

If you now run curl localhost we see at there is a web server running. That means success!

1[vagrant@centos02 ~]$ curl localhost                                                                                                                            
2<html>
3<head><title>404 Not Found</title></head>
4<body>
5<center><h1>404 Not Found</h1></center>
6<hr><center>nginx</center>
7</body>
8</html>

Expose a web page

I am working on an application at the moment called 'carolyne'. You can find it here: https://gitlab.com/jacqinthebox/carolyne. I already pushed a container to the Docker hub, so we can just use that for now. Carolyne runs happily on port 4000.

Let's create a deployment and a service object quickly.

1k create namespace apps

Then create the deployment

 1cat <<EOF | kubectl apply -f -
 2apiVersion: apps/v1
 3kind: Deployment
 4metadata:
 5  name: carolyne
 6  namespace: apps
 7  labels:
 8    app: carolyne
 9spec:
10  replicas: 1
11  selector:
12    matchLabels:
13      app: carolyne
14  template:
15    metadata:
16      labels:
17        app: carolyne
18    spec:
19      containers:
20        - name: carolyne
21          image: jacqueline/carolyne:latest
22          ports:
23            - containerPort: 4000
24EOF

Let's create the service

 1cat <<EOF | kubectl apply -f -
 2apiVersion: v1
 3kind: Service
 4metadata:
 5  name: carolyne-service
 6  namespace: apps
 7  labels:
 8    app: carolyne
 9spec:
10  ports:
11    - port: 4000
12  selector:
13    app: carolyne
14EOF

Finally, let's create the ingress rules.

 1cat <<EOF | kubectl apply -f -
 2apiVersion: networking.k8s.io/v1
 3kind: Ingress
 4metadata:
 5  annotations:
 6    kubernetes.io/ingress.class: nginx
 7    nginx.ingress.kubernetes.io/rewrite-target: /\$1
 8  name: apps-ingress-rules
 9  namespace: apps
10spec:
11  rules:
12  - host: carolyne.moonstreet.local
13    http:
14      paths:
15      - backend:
16          service: 
17            name: carolyne-service
18            port: 
19              number: 4000
20        path: /(.*)
21        pathType: Prefix
22EOF

Need to add the hostname to my hostfile:

1# sudo vim /etc/hosts
2127.0.0.1       localhost carolyne.moonstreet.local

And now we can browse to that lovely web application I just crafted.

1

2

And now with Kind!

Install Kind:

1curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.9.0/kind-linux-amd64
2chmod +x ./kind
3sudo mv ./kind /usr/local/bin/kind

Create a Kind cluster like so:

 1cat <<EOF | kind create cluster --name sandbox01 --config=-
 2kind: Cluster
 3apiVersion: kind.x-k8s.io/v1alpha4
 4nodes:
 5- role: control-plane
 6  kubeadmConfigPatches:
 7  - |
 8    kind: InitConfiguration
 9    nodeRegistration:
10      kubeletExtraArgs:
11        node-labels: "ingress-ready=true"
12  extraPortMappings:
13  - containerPort: 80
14    hostPort: 80
15    protocol: TCP
16  - containerPort: 443
17    hostPort: 443
18    protocol: TCP
19EOF

Install Ingress:

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

And create Carolyne (in the meantime I made a quick manifest):.

1kubectl create namespace apps
2kubectl apply -f https://gitlab.com/jacqinthebox/carolyne/-/raw/master/deploy.yaml