Deploying MariaDB on Kubernetes with Minikube: A Comprehensive Guide
Introduction
In the modern development landscape, containerization has revolutionized how we build, deploy, and manage applications. Kubernetes has emerged as the de facto standard for container orchestration, but what about databases? In this comprehensive guide, I'll walk you through deploying MariaDB—a popular open-source relational database—on Kubernetes using Minikube for local development or learning environments.
Whether you're a developer looking to match your local environment with production, a DevOps engineer exploring containerized databases, or simply curious about Kubernetes, this tutorial provides a practical, hands-on approach to get you started.
Why Deploy MariaDB on Kubernetes?
Before diving into the technical details, let's understand the benefits of running MariaDB on Kubernetes:
Prerequisites
To follow along with this tutorial, you'll need:
If you haven't installed these tools yet, here are the installation guides:
Understanding Key Kubernetes Concepts
Before deploying MariaDB, let's briefly review some key Kubernetes concepts that are particularly relevant for database deployments:
StatefulSets vs Deployments
While Deployments are suitable for stateless applications, databases require StatefulSets because they:
Persistent Volumes and Claims
Databases need persistent storage to maintain data across pod restarts. Kubernetes provides:
Secrets and ConfigMaps
For database credentials and configuration, Kubernetes offers:
Step 1: Setting Up Your Environment
Let's start by setting up our Minikube environment with sufficient resources for running MariaDB:
minikube start --cpus=2 --memory=4096
This command starts Minikube with 2 CPU cores and 4GB of memory, which should be sufficient for running MariaDB.
Verify that Minikube is running:
minikube status
You should see output indicating that Minikube is running:
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
Step 2: Configuring Persistent Storage
Databases require persistent storage to maintain data across pod restarts. Let's create a PersistentVolume and PersistentVolumeClaim for MariaDB.
Create a file named persistent-volume.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: mariadb-data
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
type: DirectoryOrCreate
The type: DirectoryOrCreate directive ensures that the directory is created if it doesn't exist.
Create a file named persistent-volume-claim.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb-data
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Apply these configurations:
kubectl apply -f persistent-volume.yaml
kubectl apply -f persistent-volume-claim.yaml
Verify that the PersistentVolume and PersistentVolumeClaim were created:
kubectl get pv
kubectl get pvc
Step 3: Creating Kubernetes Secrets for Database Credentials
For security, we'll store the MariaDB credentials in a Kubernetes Secret.
First, let's encode our credentials in base64:
bash
echo -n 'your_root_password' | base64
echo -n 'your_database_name' | base64
echo -n 'your_database_user' | base64
echo -n 'your_database_password' | base64
Create a file named mariadb-secrets.yaml:
apiVersion: v1
kind: Secret
metadata:
name: mariadb-secrets
type: Opaque
data:
root-password: eW91cl9yb290X3Bhc3N3b3Jk
database: eW91cl9kYXRhYmFzZV9uYW1l
user: eW91cl9kYXRhYmFzZV91c2Vy
password: eW91cl9kYXRhYmFzZV9wYXNzd29yZA==
Replace the base64 values with your encoded credentials.
Apply the configuration:
kubectl apply -f mariadb-secrets.yaml
Verify the secret was created:
kubectl get secrets
Step 4: Creating a ConfigMap for MariaDB Configuration
Create a file named mariadb-configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: mariadb-configmap
data:
my.cnf: |
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# InnoDB settings
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
# Connection settings
max_connections = 100
# Binary log settings
server_id = 1
log_bin = mysql-bin
binlog_format = ROW
[client]
default-character-set = utf8mb4
This ConfigMap contains a custom MariaDB configuration with optimized settings.
Apply the configuration:
kubectl apply -f mariadb-configmap.yaml
Verify the ConfigMap was created:
kubectl get configmaps
Step 5: Deploying MariaDB Using StatefulSet
Create a file named mariadb-statefulset.yaml:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mariadb
spec:
serviceName: mariadb
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:10.11
ports:
- containerPort: 3306
name: mysql
env:
- name: MARIADB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secrets
key: root-password
- name: MARIADB_DATABASE
valueFrom:
secretKeyRef:
name: mariadb-secrets
key: database
- name: MARIADB_USER
valueFrom:
secretKeyRef:
name: mariadb-secrets
key: user
- name: MARIADB_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secrets
key: password
volumeMounts:
- name: mariadb-data
mountPath: /var/lib/mysql
- name: mariadb-config
mountPath: /etc/mysql/conf.d
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1"
livenessProbe:
exec:
command: ["mysqladmin", "ping", "-u", "root", "-p${MARIADB_ROOT_PASSWORD}"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command: ["mysqladmin", "ping", "-u", "root", "-p${MARIADB_ROOT_PASSWORD}"]
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
volumes:
- name: mariadb-config
configMap:
name: mariadb-configmap
volumeClaimTemplates:
- metadata:
name: mariadb-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: manual
resources:
requests:
storage: 1Gi
This StatefulSet configuration:
Apply the configuration:
kubectl apply -f mariadb-statefulset.yaml
Verify the StatefulSet was created:
kubectl get statefulsets
Check the status of the MariaDB pod:
bash
kubectl get pods
You should see a pod named mariadb-0 in the "Running" state after a few moments.
Step 6: Creating a Service for MariaDB
Create a file named mariadb-service.yaml:
Recommended by LinkedIn
apiVersion: v1
kind: Service
metadata:
name: mariadb
labels:
app: mariadb
spec:
ports:
- port: 3306
targetPort: 3306
name: mysql
selector:
app: mariadb
type: ClusterIP
This service configuration makes MariaDB accessible within the cluster.
Apply the configuration:
kubectl apply -f mariadb-service.yaml
Verify the service was created:
kubectl get services
Step 7: Accessing and Testing MariaDB
Connecting to MariaDB from Within the Cluster
To connect to MariaDB from within the cluster, you can use the service name mariadb as the hostname.
Let's test this by running a temporary pod with the MySQL client:
kubectl run -it --rm --image=mariadb:10.11 --restart=Never mysql-client -- mysql -h mariadb -uroot -p
When prompted, enter your root password.
Connecting to MariaDB from Outside the Cluster
To connect to MariaDB from your local machine, use port forwarding:
kubectl port-forward svc/mariadb 3306:3306
This command forwards your local port 3306 to the MariaDB service in the cluster.
In a new terminal, you can now connect using a MySQL client:
mysql -h 127.0.0.1 -P 3306 -uroot -p
Verifying Data Persistence
Let's test data persistence by creating a table and inserting data:
CREATE TABLE test (id INT, name VARCHAR(50));
INSERT INTO test VALUES (1, 'Test Data');
SELECT * FROM test;
Now, let's delete the MariaDB pod and let Kubernetes recreate it:
kubectl delete pod mariadb-0
Wait for the pod to be recreated:
kubectl get pods
Once the pod is running again, connect to MariaDB and verify your data is still there:
kubectl run -it --rm --image=mariadb:10.11 --restart=Never mysql-client -- mysql -h mariadb -uroot -p
SELECT * FROM test;
You should see your test data, confirming that the data persisted across pod restarts.
Automating the Deployment Process
To simplify the deployment process, let's create a setup script. Create a file named setup.sh:
#!/bin/bash
# Start Minikube if not already running
if ! minikube status | grep -q "Running"; then
echo "Starting Minikube..."
minikube start --cpus=2 --memory=4096
else
echo "Minikube is already running."
fi
# Enable storage addons
echo "Enabling storage addons..."
minikube addons enable storage-provisioner
minikube addons enable default-storageclass
# Create directory for persistent volume
echo "Creating directory for persistent volume..."
minikube ssh "sudo mkdir -p /mnt/data && sudo chmod 777 /mnt/data"
# Apply Kubernetes configurations
echo "Creating persistent volume and claim..."
kubectl apply -f persistent-volume.yaml
kubectl apply -f persistent-volume-claim.yaml
# Verify PV and PVC are bound
echo "Verifying PV and PVC status..."
kubectl get pv
kubectl get pvc
# Wait for PVC to be bound
echo "Waiting for PVC to be bound..."
kubectl wait --for=condition=bound pvc/mariadb-pvc --timeout=60s
echo "Creating MariaDB secrets..."
kubectl apply -f mariadb-secrets.yaml
echo "Creating MariaDB ConfigMap..."
kubectl apply -f mariadb-configmap.yaml
echo "Deploying MariaDB StatefulSet..."
kubectl apply -f mariadb-statefulset.yaml
echo "Creating MariaDB Service..."
kubectl apply -f mariadb-service.yaml
echo "Waiting for MariaDB pod to be ready..."
kubectl wait --for=condition=ready pod/mariadb-0 --timeout=120s
echo "MariaDB deployment complete!"
echo "To connect to MariaDB, run: kubectl port-forward svc/mariadb 3306:3306"
Make the script executable:
chmod +x setup.sh
Now you can deploy MariaDB with a single command:
./setup.sh
Troubleshooting Common Issues
Issue: Pod Won't Start Due to Unbound PersistentVolumeClaim
If you see an error like:
Warning FailedScheduling 2m16s default-scheduler 0/2 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
Solution:
Ensure the storage addons are enabled:
minikube addons enable storage-provisioner
minikube addons enable default-storageclass
Create the directory on the Minikube VM:
minikube ssh "sudo mkdir -p /mnt/data && sudo chmod 777 /mnt/data"
Verify that the PV and PVC have matching specifications:
kubectl describe pv mariadb-pv
kubectl describe pvc mariadb-pvc
Issue: Can't Connect to MariaDB
If you can't connect to MariaDB, check:
The pod status:
kubectl get pods
The pod logs:
kubectl logs mariadb-0
The service status:
kubectl get svc
Ensure port forwarding is active:
kubectl port-forward svc/mariadb 3306:3306
Advanced Topics
Scaling MariaDB (Read Replicas)
For a production environment, you might want to set up MariaDB replication for read scaling. This requires additional configuration:
Implementing Backup and Restore
Regular backups are essential for any database. You can implement backups using:
Monitoring MariaDB on Kubernetes
For monitoring, consider:
Conclusion
In this comprehensive guide, we've covered how to deploy MariaDB on Kubernetes using Minikube. We've explored:
This knowledge provides a foundation for deploying and managing databases on Kubernetes in more complex environments. Whether you're using this setup for development, testing, or learning, you now have a solid understanding of how to run stateful applications like MariaDB on Kubernetes.
Next Steps
To further enhance your MariaDB on Kubernetes deployment, consider:
The complete code for this tutorial is available in my GitHub repository: MariaDB on Kubernetes with Minikube .
Happy containerizing!
If you found this article helpful, please consider following me for more content on Kubernetes, databases, and DevOps practices.