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.

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).

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

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
shell

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
shell

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
shell

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
shell

Then patch the ingress controller deployment like so:

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

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>
shell

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
shell

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
shell

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
shell

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
shell

Need to add the hostname to my hostfile:

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

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

1

1

2

2

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
shell

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
shell

Install Ingress:

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

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
shell