Last updated on November 7th, 2024 at 02:56 pm
In this tutorial, we will undertake a methodical approach to deploying a MySQL database utilizing persistent volumes. We will subsequently test the creation of a sample database and the destruction of the pod to observe data persistence, particularly when the pod is automatically recreated. This will be executed in a straightforward manner, minimizing complexity.
Let us break this in to multiple steps for easier understanding
- What are PODS?
- StatefulSet with Persistent Volume
- Create MySQL Service
- Create Database And Table
- Test MySQL Data Persistence
What are PODS?
POD represent single instance of a running process in your K8 cluster. PODs are ephemeral, If a POD running on a node fails it will get delete and all resources associated with the POD such as storage(volume) also get destroyed. In other words volume associated with a POD exist as long as the POD is up and running.
When the POD get destroyed even if an identical replacement is created, the related volume is also destroyed. This means that you will get a brand new POD with a new volume. Read more about pod lifecycle here.
Persistent volume(PV) is a storage concept within cluster provisioned using Storage Classes. PV’s are plugins that has a lifecycle independent of the POD. PersistentVolumeClaim (PVC) is a request for storage by a user. More details about PVC and PV
StatefulSet with Persistent Volume
StatefulSets can be utilized to ensure persistence for storage volumes. While individual Pods remain susceptible to failure, StatefulSets facilitate the association of existing volumes with new Pods when replacements occur
Save the below YAML file as mysql_digital_ocean.yml . Update the MySQL password under env section according to your choice.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: new-mysql-statefulset
spec:
replicas: 1
serviceName: mysql
selector:
matchLabels:
app: new-mysql
template:
metadata:
labels:
app: new-mysql
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mysql
image: mysql:5.6
ports:
- name: tpc
protocol: TCP
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: password
volumeMounts:
- name: new-mysql-data-claim
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: new-mysql-data-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Using DigitalOcean
In this example we are using DigitalOcean managed Kubernetes service to deploy MySQL.
Using AWS
If you are using EKS then make sure to add the storageClassName under the volumeClaimTemplates section, something like this
volumeClaimTemplates:
- metadata:
name: new-mysql-data-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-sc
resources:
requests:
storage: 1Gi
My storageClassName is ebs-sc and that is used as a persistent volume claim
Next step is to use kubectl to read the file and create StatefulSet, Read more on VolumeClaimTemplates
$ kubectl apply -f mysql_digital_ocean.yml
statefulset.apps/new-mysql-statefulset created
$
Once you get the above message after applying the YAML file, run the kubectl get command to see the status of Statefulset, Pods and PVC
$ kubectl get statefulset
NAME READY AGE
new-mysql-statefulset 1/1 33s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
new-mysql-statefulset-0 1/1 Running 0 36s
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
new-mysql-data-claim-new-mysql-statefulset-0 Bound pvc-7730911c-c30e-40a9-b3d7-4935cabd8865 1Gi RWO do-block-storage 50m
$
From the output we can see that it created a
StatefulSet named new-mysql-statefulset
Pod was created with name new-mysql-statefulset-0
PVC name new-mysql-data-claim-new-mysql-statefulset-0
Create MySQL Service
Now that we have the MySQL container in place let us create a service for MySQL so that external applications can connect to the container. Name the file as mysql_service.yml
apiVersion: v1
kind: Service
metadata:
name: new-mysql-service
labels:
app: new-mysql-statefulset
spec:
selector:
app: new-mysql
ports:
- name: tcp
protocol: TCP
port: 3306
targetPort: 3306
Once the file is created run this command
$ kubectl apply -f mysql_service.yml
service/new-mysql-service created
$
Run the describe pod command to see the details of the service we just created.
$ kubectl describe service/new-mysql-service
Name: new-mysql-service
Namespace: default
Labels: app=new-mysql-statefulset
Annotations: <none>
Selector: app=new-mysql
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.245.252.95
IPs: 10.245.252.95
Port: tcp 3306/TCP
TargetPort: 3306/TCP
Endpoints: 10.244.0.22:3306
Session Affinity: None
Events: <none>
Keep an eye of the attribute name Endpoints, it says
Endpoints: 10.244.0.22:3306 .
Run the get pod command with -o wide option to see our mysql pod ip address and make sure that the Endpoint above matches.
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
new-mysql-statefulset-0 1/1 Running 0 10m 10.244.0.22
Let us check the MySQL service details
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
new-mysql-service ClusterIP 10.245.252.95 <none> 3306/TCP 3d18h
$
Cluster IP is 10.245.252.95, you can connect to the MySQL database using this IP and port number is 3306. Database connection details configured within your application has to be updated using the above details.
Using a service for your MySQL database ensures that your application is not dependent on the POD lifecycle and associated IP addresses. All you have to worry about is the MySQL ClusterIP service IP address as shown above.
Create Database And Table
Now that you have your MySQL service up and running let us connect to MySQL running on Kubernetes by
1] Creating a database and table
2] Insert data to the table
Before we create a database we need to connect to the pod.
$ kubectl get pods
Using the get pods command we will get the name of the pod. In this case it will be new-mysql-statefulset-0
Now use kubectl exec command to connect to and then issue the mysql command to connect to the MySQL server inside the pod as shown. Password will be “password” (From mysql_digital_ocean.yml )
$ kubectl -it exec new-mysql-statefulset-0 -- /bin/bash
root@new-mysql-statefulset-0:/# mysql -u root -p
Once inside the mysql prompt, run these
mysql> create database test_mistonline;
Query OK, 1 row affected (0.01 sec)
mysql> use test_mistonline;
Database changed
mysql> CREATE TABLE kube_first (ID int,Name varchar(255) ,Address varchar(255),City varchar(255));
Query OK, 0 rows affected (0.13 sec)
mysql> INSERT INTO kube_first (ID,Name,Address,City) VALUES ('1','Steve','1st Street', 'Seattle');
Query OK, 1 row affected (0.01 sec)
mysql> select * from kube_first;
+------+-------+------------+---------+
| ID | Name | Address | City |
+------+-------+------------+---------+
| 1 | Steve | 1st Street | Seattle |
+------+-------+------------+---------+
1 row in set (0.00 sec)
mysql>
As you can see above we created a database and a table, then inserted some data in to the table inside the POD.
Test MySQL Data Persistence
This is the final step in our deployment to test whether the data we created above persist if the POD is destroyed. Let’s do that now. We are deleting the pod using the kubectl delete command.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
new-mysql-statefulset-0 1/1 Running 0 3d18h
$ kubectl delete pod/new-mysql-statefulset-0
pod "new-mysql-statefulset-0" deleted
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
new-mysql-statefulset-0 0/1 ContainerCreating 0 3s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
new-mysql-statefulset-0 1/1 Running 0 39s
As you can see the pod got deleted and then recreated automatically. Next step is to check whether the database and table we created before the POD got destroyed are still available.
$ kubectl -it exec new-mysql-statefulset-0 -- /bin/bash
root@new-mysql-statefulset-0:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+---------------------+
| Database |
+---------------------+
| information_schema |
| #mysql50#lost+found |
| mysql |
| performance_schema |
| test_mistonline |
+---------------------+
5 rows in set (0.00 sec)
mysql> select * from test_mistonline.kube_first;
+------+-------+------------+---------+
| ID | Name | Address | City |
+------+-------+------------+---------+
| 1 | Steve | 1st Street | Seattle |
+------+-------+------------+---------+
1 row in set (0.00 sec)
mysql>
I logged in to the newly created pod and boom I do have the data inside my MySQL table intact. Awesome!!
This tutorial aimed to provide you with an understanding of how data persistence functions in Kubernetes when operating a database pod.