Kubernetes for Websites
Using Kubernetes for Websites, and what an absolute joy it is.
I want to use this post to describe how to deploy a website on your kubernetes cluster. Once more even though we could do this via the Dashboard I think it is better to learn Kubernetes via the CLI and it is also good practice to understand the YAML spec that is used extensively to configure Kubernetes deployments.
To create a website within Kubernetes we need three separate elements. A Deployment that describes the number and type of docker containers that we want to deploy. A Service to create an identifier by which we will connect to the Deployment internally and finally an Ingress to describe how we will expose the service so that we can connect to it externally.
Below is a config file to create:
- A Deployment called datasmith-site which will create a single replica on an nginx container using internal Port 80 and using an NFS volume from my internal NAS which will be mounted within the container at /usr/share/html.
- A Service called datasmith-service which we can use to reference this deployment running on Port 80.
- An Ingress called datasmith-ingress that allows us to connect to the service if we get a request for “data-smith.ca” on Port 80
apiVersion: apps/v1
kind: Deployment
metadata:
name: datasmith-site
labels:
app: datasmith-nginx
spec:
replicas: 1
selector:
matchLabels:
app: datasmith-nginx
template:
metadata:
labels:
app: datasmith-nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: datasmith-volume
mountPath: /usr/share/nginx/html
subPath: data-smith.ca
volumes:
- name: datasmith-volume
nfs:
server: diskstation.local
path: /volume1/pi-config
---
apiVersion: v1
kind: Service
metadata:
name: datasmith-service
spec:
selector:
app: datasmith-nginx
ports:
- protocol: TCP
port: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: datasmith-ingress
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
rules:
- host: data-smith.ca
http:
paths:
- backend:
serviceName: datasmith-service
servicePort: 80
pi@pi-proxy:~ $
Once we understand the 3 basic elements then to deploy data-smith.ca is really simple.
kubectl create -f data-smith.yml
deployment.apps/datasmith-site created
service/datasmith-service created
ingress.networking.k8s.io/datasmith-ingress created
After a few minutes, we can check the status of the deployment using the following commands.
kubectl get deployments -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
datasmith-site 1/1 1 1 54s nginx nginx app=datasmith-nginx
Note how the deployment will show how many replicas have been requested and how many are currently available. Remember this is Kubernetes, if a replica fails for whatever reason a new replica will be started to replace it. As an admin/operator we do not need to do anything.
kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 51d <none>
datasmith-service ClusterIP 10.43.61.184 <none> 80/TCP 96s app=datasmith-nginx
See how the service datasmith-service is being advertised on an internal Cluster IP addresses
kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
datasmith-ingress <none> data-smith.ca 10.0.0.159 80 2m3s
The Ingress rule specifies the hosts that are allowed to use this rule and leverages the service to indentify where the container is running at the moment in my case the IP address of pi-node1.
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
datasmith-site-7ddb94564c-m5cjw 1/1 Running 0 33m 10.42.2.7 pi-node1 <none> <none>
And that is basically it, now I am using my NAS, but it is worth noting that I have not mounted my NAS to any of the nodes in my cluster. This is all controlled by Kubernetes which will perform the mount when it create the Deployment. It is also worth noting that my NAS has a tendancy to go to sleep, which does mean if you are trying to reach my site, you might actually get a delay as my NAS spins up out of hibernation. I will look eventually look at other Volume options but first I want to move on to the thorny topic of dynamic IP addresses and creating a DynamicDNS deployment within Kubernetes.
