Self-Hosted Blog Part 7 - Kubernetes

In part 6 we got our blog building in our CI2/CD pipeline. Now we’re going to run that built image in our Raspberry Pi K8S cluster. In my setup I have a single Linode VPS node exposed to the internet. First let’s get all of Kubernetes nodes serving HTTP.

Let’s create a Kubernetes service that will use the container we created earlier with our CI/CD pipeline. I have a file in my repo called k8s-blog.yml which has the following contents which create a Kubernetes service running the container we created and creates an ingress controller which exposes that container for the host clintsharp.com:

---
apiVersion: v1
kind: Namespace
metadata:
  name: blog
---
apiVersion: v1
kind: Service
metadata:
  name: blog
  namespace: blog
  labels:
    app.kubernetes.io/name: blog
  annotations:
    {}
spec:
  type: ClusterIP
  ports: 
      - port: 80
        targetPort: 80
        protocol: TCP
        name: web
  selector:
    app.kubernetes.io/name: blog
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog
  namespace: blog
  labels:
    app.kubernetes.io/name: blog
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: blog
  template:
    metadata:
      labels:
        app.kubernetes.io/name: blog
    spec:
      containers:
        - name: blog
          image: clintsharp/blog:latest
          imagePullPolicy: Always
          resources:
            limits:
              cpu: 2000m
              memory: 512Mi
            requests:
              cpu: 100m
              memory: 128Mi
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog
  namespace: "blog"
spec:
  rules:
  - host: "clintsharp.com"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: blog
            port:
              number: 80

I’m assuming you know a bit about Kubernetes if this interested you, so I’ll not go through intimate details on what all of this is. We’re creating a namespace, a deployment, a service, and a ingress configuration. After running kubectl apply -f ./deployment/k8s-blog.yml and after the deployment finishes converging I’ll have a working blog in Kubernetes.

To validate, I ran kubectl get po -n blog and I see pods deployed:

NAME                    READY   STATUS    RESTARTS   AGE
blog-5844664449-pbqpw   1/1     Running   0          5d17h
blog-5844664449-627kt   1/1     Running   0          5d17h
blog-5844664449-gdrpl   1/1     Running   1          5d17h

Now I can interrogate the service with kubectl get svc -n blog:

NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
blog   ClusterIP   10.152.183.132   <none>        80/TCP    4h33m

The last thing I want to do is setup the deployment for autoscaling, which I do with kubectl autoscale deployment blog --cpu-percent=50 --min=3 --max=20. This will automatically scale up to 20 pods when we see the average CPU usage above 50% for the running pods.

Now, I can verify the blog service is serving our blog contents with a simple curl request from a machine on the local network. Note, we’re setting the Host header so we’re routed to the right service:

curl -H "Host: clintsharp.com" http://192.168.68.2/

This shows we’re serving the right HTML content.

We have a running blog in Kubernetes on bare metal! Next, we will expose this to the internet and deploy on change.

Posts in this Series