Persistent Volumes

Contributed by: Pekka Nurmi

UpCloud CSI Driver

UpCloud CSI Driver provides a basis for using the UpCloud Storage service in Kubernetes, to obtain stateful application deployment with ease.

See https://github.com/UpCloudLtd/upcloud-csi/tree/main/example for various examples for our CSI driver.

Deploy MariaDB using persistent volume

This example shows how we can make MariaDB survive reboots and pod re-creations by using persistent volume claim (PVC).

This example is meant for demonstration purposes only. Do not use as is in production.

Define MariaDB root password as environment variable

$ export MARIADB_PASSWORD=myp4ss!

Create MariaDB secret to store password securely inside cluster

$ kubectl create secret generic mariadb --from-literal=password=$MARIADB_PASSWORD

Create persistent volume claim manifest

Save following content to file named volume.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-pvc
spec:
  storageClassName: upcloud-block-storage-maxiops
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Apply manifest

$ kubectl apply -f volume.yaml

This will create 10GB storage device using UpCloud CSI Driver that can be referenced using its name mariadb-pvc.

Create new deployment manifest

Deployment makes sure that one MariaDB container is running and that persistent volume claim mariadb-pvc is available for containers to use. MariaDB saves all of its data under directory defined by datadir configuration variable which defaults to /var/lib/mysql. We can use datadir variables default value and mount persistent volume mariadb-pvc into path /var/lib/mysql.

Save following content to file named deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb
  labels:
    app: mariadb
spec:
  selector:
    matchLabels:
      app: mariadb
  template:
    metadata:
      labels:
        app: mariadb
    spec:
      containers:
        - name: mariadb
          image: mariadb:10.9
          env:
            - name: MARIADB_ALLOW_EMPTY_ROOT_PASSWORD
              value: "0"
            - name: MARIADB_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mariadb
                  key: password
          ports:
            - containerPort: 3306
              name: mariadb
          volumeMounts:
            - name: mariadb-datadir
              mountPath: /var/lib/mysql
      volumes:
        - name: mariadb-datadir
          persistentVolumeClaim:
            claimName: mariadb-pvc

Apply manifest

$ kubectl apply -f deployment.yaml

Test data persistence

We can check deployment status using kubectl

$ kubectl get deployments/mariadb
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
mariadb   1/1     1            1           22s

When “ready” column shows 1/1 we can try to connect MariaDB server

$ kubectl exec -it deployments/mariadb -- mysql -uroot -p$MARIADB_PASSWORD -e "SELECT CURRENT_TIMESTAMP()"
+---------------------+
| CURRENT_TIMESTAMP() |
+---------------------+
| 2022-10-12 10:48:18 |
+---------------------+

For testing purposes create new database test with single column id and fill it with couple of rows

$ kubectl exec -it deployments/mariadb -- mysql -uroot -p$MARIADB_PASSWORD -e "CREATE DATABASE test;CREATE TABLE test.number(id int PRIMARY KEY);INSERT INTO test.number (id) VALUES (1), (2), (3), (4)"

Now table should have 4 rows

$ kubectl exec -it deployments/mariadb -- mysql -uroot -p$MARIADB_PASSWORD -e "SELECT id FROM test.number";
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+

Data persistence can be tested by deleting our deployment and then re-creating it and checking that same rows still exists. Without persistent volume we would loss newly created database rows.

$ kubectl delete -f deployment.yaml
$ kubectl get deployments
No resources found in default namespace.
$ kubectl apply -f deployment.yaml
$ kubectl get deployments
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
mariadb   1/1     1            1           38s
$ kubectl exec -it deployments/mariadb -- mysql -uroot -p$MARIADB_PASSWORD -e "SELECT id FROM test.number";
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+

What’s next