K3s Cluster in a Weekend – Part 4 – Deploying an App

BookStack Github Stats

I decided to deploy a wiki application to the Kubernetes cluster to have a place to store documentation for research, new projects, and existing system architectures. I found BookStatck to be simple to use and provided a nice test app to get running in the K3s cluster.

BookStack will run in two pods each with dedicated storage. A Pod consisted of one or more Containers and is the smallest unit of work in Kubernetes. While use cases do exist for multiple Containers in a Pod, normally, only one is assigned. I will be creating a Pod for BookStacks backend SQL database as well as a Pod for the frontend web application. These Pods will each have dedicated storage, provisioned with Longhorn.

MariaDB will be used for the SQL database. A PersistentVolumeClaim will be used to allocated disk space.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    storage: bookstack-db-storage
  name: bookstack-db-storage
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: longhorn

A second PVC will be used for the BookStack's frontend. This storage will be for file uploads and attachments.

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    storage: bookstack-storage
  name: bookstack-storage
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: longhorn

The configuration accessModes: ReadWriteOnce instructs the cluster that only one worker node is allowed to mount and write to this volume.

Apply the yaml configuration with kubectl.

control-01:~/apps/bookstack$ kubectl apply -f bookstack-db-storage.yaml -f bookstack-storage.yaml

Each Pod will be managed as a Deployment. Deployments allow Pods to be managed to a desired state and allows applications to be scaled up or down.

Managing these Pods in this way will allow a more complete understanding even my use case of BookStack does not require a high-availability setup with scaling options.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: bookstack
    partOf: bookstack
  name: bookstack-frontend
  namespace: apps
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bookstack
  template:
    metadata:
      labels:
        app: bookstack
        partOf: bookstack
    spec:
      containers:
        - env:
            - name: APP_URL
              value: https://wiki.internal.hrck.net
            - name: DB_DATABASE
              value: bookstackapp
            - name: DB_HOST
              value: bookstack-db-svc
            - name: DB_PASS
              value: my_bookstack_db_password
            - name: DB_USER
              value: bookstack
            - name: PGID
              value: "1000"
            - name: PUID
              value: "1000"
          image: lscr.io/linuxserver/bookstack
          name: bookstacks
          ports:
            - containerPort: 80
          volumeMounts:
            - name: bs-frontend-storage
               mountPath: /config
              
      restartPolicy: Always
      volumes:
        - name: bs-frontend-storage
          persistentVolumeClaim:
            claimName: bookstack-storage

Let's break down the Deployment manifest starting with replicas: 1 and continuing with selector: ... . This configuration tells K3s that only one Pod named with a label of app: bookstack. If the value of replicas were set to 3, two more bookstack Pods would be created based on the information in the section template:.

Container applications can be configured with environment variables. Here, I have used env: to define the SQL username and password for BookStack to use, as well as other app specific configurations. An image: lscr.io/linuxserver/mariadb is also configured to inform K3s what container must be fetched.

Skipping over volumeMounts: ... briefly to describe the sections titled volumes: ... which is how storage provisioned with the previous manifests are assigned to this Pod. I configure the persistentVolumeClaim named bookstack-storage to reference the PVC provisioned on Longhorn. The volume can then be mounted through the name it has been give (bs-frontend-storage) in the section for volumeMounts: .... In addition, montPath is set to describe the filesystem path where the volume will be mounted inside the container.

A second deployment for MariaDB can be setup using a manifest like this:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mariadb
    partOf: bookstack
  name: bookstack-db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
      partOf: bookstack
  template:
    metadata:
      labels:
        app: mariadb
        partOf: bookstack
    spec:
      containers:
        - env:
            - name: MYSQL_DATABASE
               value: bookstackapp
            - name: MYSQL_PASSWORD
               value: mysql_password
            - name: MYSQL_ROOT_PASSWORD
               value: mysql_root_password
            - name: MYSQL_USER
               value: bookstack
            - name: PGID
               value: "1000"
            - name: PUID
               value: "1000"
            - name: TZ
               value: UTC
          image: lscr.io/linuxserver/mariadb
          name: bookstacks-db
          volumeMounts:
            - mountPath: /config
              name: bookstacks-db-storage
      restartPolicy: Always
      volumes:
        - name: bookstacks-db-storage
          persistentVolumeClaim:
            claimName: bookstacks-db-storage

control-01:~/apps/bookstack$ kubectl apply -f bookstack-db-deployment.yaml -f bookstack-deployment.yaml

There should now be two Pod running for BookStack, bookstack-frontend and bookstack-db. We can check with kubectrl get pod -l partOf=bookstack

Both Pods can communicate with each other, but neither is accessible outside the K3s cluster. This is where Kubernetes (K3s in this case) can be though of as a software defined datacenter. Everything is racked, stacked and patched inside the cluster, but traffic is not allowed in or out.

We will explore how to expose services outside the cluster in Part 5.

#kubernetes #k3s #k8s #weekendproject #wiki #bookstackapp