Start MariaDB in K8s

This is the first in a series of blogs explaining how to use MariaDB in Kubernetes (K8s), as well as explaining some important concepts of K8s and of MariaDB.

This blog explains how to start MariaDB as a stateless application in K8s using the CLI and explores different commands you can run on your CLI.

The prerequisites are that you have installed kubectl (which will also install Docker runtime) and minikube (local K8s).

Let’s first start the minikube

$ minikube start && kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
minikube   Ready    control-plane,master   104d   v1.22.2

The Pod is a K8s resource and the smallest unit in K8s. It is an top abstraction in K8s layer over the container. Pods are ephemeral and can die easily, and when started again the new Pod will get a new IP. That is what stateless application means; there is no consistency of data in case Pods are restarted or removed. Usually a Pod is used to run 1 application container.

A Deployment is a K8s resource and it is an abstraction on top of Pods which have blueprints for Pods and help to interact with Pods, replicate them, etc.

The K8s API consists of other kind of resources that could be listed using kubectl api-resources. There one can find Deployments, ReplicaSet, Secrets, ConfigMaps, Services, etc.

Start MariaDB from CLI

In order to create any resource from the CLI one needs to run the command kubectl create <resource> <name> --image=<image_name>. In case of deployment of nginx for example, the last command will be kubectl create deployment nginx --image=nginx.

To create and run the container, MariaDB needs to have at least one of the expected environment variables (see MariaDB Docker Library). We have to pass the environment variable, but I couldn’t find a way for kubectl create deployment to pass the environment variable to that command from the CLI. Later in this blog we are going to cover how to properly create and start deployment of MariaDB.

It is possible to start the Pod (although it is not recommended) and pass environment variables using the kubectl run command. Let’s use that command to set the root password with the MARIADB_ROOT_PASSWORD environment variable.

$ kubectl run mariadb-test-pod --image=mariadb --env="MARIADB_ROOT_PASSWORD=secret"
pod/mariadb-test-pod created

To display the Pod (or any other resource) information (status/restarts/age) run

$ kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
mariadb-test-pod   1/1     Running   0          2m37s

In order to log into the container one can use kubectl exec command. Let’s use that command to start mariadb client within the container and execute a query:

$ kubectl exec -it mariadb-test-pod -- mariadb -uroot -psecret -e "select current_user()"
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+

Another useful command is kubectl logs which prints logs of containers in a Pod.

To see the logs of our created mariadb-test-pod, run:

$ kubectl logs mariadb-test-pod
...
2022-03-16  7:54:43 0 [Note] mariadbd: ready for connections.
Version: '10.7.3-MariaDB-1:10.7.3+maria~focal'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

To debug Pod and get more information about Pod, run the kubectl describe command:

$ kubectl describe pod mariadb-test-pod
...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  27m   default-scheduler  Successfully assigned default/mariadb-test-pod to minikube
  Normal  Pulling    27m   kubelet            Pulling image "mariadb"
  Normal  Pulled     27m   kubelet            Successfully pulled image "mariadb" in 19.675118703s
  Normal  Created    27m   kubelet            Created container mariadb-test-pod
  Normal  Started    27m   kubelet            Started container mariadb-test-pod

At the end, to delete the Pod, run the kubectl delete command:

$ kubectl delete pod mariadb-test-pod
pod "mariadb-test-pod" deleted

Start MariaDB using configuration files

Instead of using the CLI to start some resource in K8s, the recommended way is to create configuration YAML files.

Let’s create the YAML file mariadb-deployment.yaml. The file can be found on GitHub mariadb.org-tools.

apiVersion: apps/v1
kind: Deployment # what to create?
metadata:
  name: mariadb-deployment
spec: # specification for deployment resource
  replicas: 2 # how many replicas of pods we want to create
  selector:
    matchLabels:
      app: mariadb
  template: # blueprint for pods
    metadata:
      labels:
        app: mariadb # service will look for this label
    spec: # specification for pods
      containers: # we can have one or more containers
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 
        env:
        #- name: MARIADB_RANDOM_ROOT_PASSWORD
        - name: MARIADB_ALLOW_EMPTY_ROOT_PASSWORD
          value: "0" # if it is 1 and root_password is set, root_password takes precedance
        - name: MARIADB_ROOT_PASSWORD
          value: secret

Note that we have specified what we want to create (Deployment).

Deployment is a resource that is a superset of Pod that can be scaled by the number of replicas that can be configured in the configuration file.

Each Pod has its labels that is a key-value pair that can be used to filter the Pods using kubectl commands as well as an interface to interact with services in the K8s cluster (we will explain service resources later).

Pod may have an array of containers, but we are creating a single container with the name mariadb (note this name is used by Deployment selector to create the containers), with the mariadb (latest) image, with ports and environment values.

To create and start the Deployment we need to use thekubectl apply command with the YAML file:

$ kubectl apply -f mariadb-deployment.yaml 
deployment.apps/mariadb-deployment created

To display Deployment, run:

$ kubectl get deploy
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mariadb-deployment   2/2     2            2           48s

It displays that all 2 replicas of Deployment are ready and started.

To get information about the replica, display ReplicaSet resource:

$ kubectl get replicasets
NAME                           DESIRED   CURRENT   READY   AGE
mariadb-deployment-9fd9fbbfd   2         2         2       3m26s

To get information about Pods, display Pod resource:

$ kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
mariadb-deployment-9fd9fbbfd-5rkzp   1/1     Running   0          106s
mariadb-deployment-9fd9fbbfd-jtbk2   1/1     Running   0          106s

Note that the ReplicaSet as well as Pods have a hash prefix at the end that K8s creates as an unique identifier. Each Pod in a K8s cluster has its unique IP, so when it gets deleted, a new Pod with a new IP is created leading to loss of data. Pod’s IPs can be found with the following command:

$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
mariadb-deployment-9fd9fbbfd-5rkzp   1/1     Running   0          5m22s   172.17.0.12   minikube   <none>           <none>
mariadb-deployment-9fd9fbbfd-jtbk2   1/1     Running   0          5m22s   172.17.0.8    minikube   <none>           <none>

To get logs of the container, run kubectl logs deploy/mariadb-deployment.

To start mariadb client we need to run kubectl exec on a Pod with a hash name. In this case there are 2 Pods with different hash names, so we will test for both.

$ kubectl exec -it mariadb-deployment-9fd9fbbfd-5rkzp -- mariadb -uroot -psecret -e "select current_user()"
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+
$ kubectl exec -it mariadb-deployment-9fd9fbbfd-jtbk2 -- mariadb -uroot -psecret -e "select current_user()"
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+

In case demands get higher, one would need to scale the application. This is accomplished by changing the number of replicas in Deployment. This will ensure that new Pods are created and scheduled to nodes with available resources. To scale deployment up from 2 replicas to 4, run the following command:

$ kubectl get deploy
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mariadb-deployment   2/2     2            2           17m
$ kubectl scale deploy/mariadb-deployment --replicas=4
deployment.apps/mariadb-deployment scaled
$ kubectl get deploy
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mariadb-deployment   4/4     4            4           22m

Try to scale down yourself :).

In order to delete a Deployment (which will delete everything created by Deployment, like Pods and ReplicaSets), run:

$ kubectl delete deploy mariadb-deployment
deployment.apps "mariadb-deployment" deleted

Conclusion and future work

This blog showed how to create the MariaDB Pod in a K8s cluster and demonstrated the usage of basic kubectl commands to work with K8s. Additionally, Deployment was created from YAML file and we have seen how to scale Deployment.

In the next blog we are going to create a frontend Deployment to interact with Deployment in this blog (let’s call it backend) and explore other K8s concepts like Services, Secrets and ConfigMaps, what they are, how to create and how to use them.

You are welcome to chat about it on Zulip.

Read more