MySQL Replication (Kubernetes)

Prerequisites

  • Kubernetes 1.18 or later
  • Docker 19.03 or later
  • Docker Desktop
  • MySQL 8.0 or later

Step 1: Create the master pod

Meta AI Prompt: I'm building a kubectl cluster on docker desktop with kubernetes. I'll need you assistance.

Built a single master pod with kubectl
- with MySQL 8 image
- that's connected to my network k8s-mysqlrepl-net

yes, I want to use a yaml. yes, I know this isn't ideal, but I'm starting out simple with this. I will setup MySQL replication on the worker nodes later on.


File: mysql-master-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mysql-master
spec:
  containers:
  - name: mysql
    image: mysql:8
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "spidersoupsql"
    ports:
    - containerPort: 3306

Apply the configuration:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-master-pod.yaml
pod/mysql-master created

You can see the pod

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
4c6629430c44   mysql     "docker-entrypoint.s…"   4 minutes ago   Up 4 minutes             k8s_mysql_mysql-master_default_d6726ee0-eee5-4a63-9b0d-08107238014c_0

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
mysql-master   1/1     Running   0          4m31s


Step 2: Create a service to use for networking

Meta AI Prompt: I did this before manually without kubernetes with the following command

docker run --net hamysqlnet --ip 172.16.1.2 -d --name hamysqlmaster -e MYSQL_ROOT_PASSWORD=spidersoupsql mysql:8.0

but I want to do this with kubectl using a yaml instead.


File: mysql-master-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-master-service
spec:
  selector:
    app: mysql-master
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306
  type: ClusterIP

Meta AI Prompt: I created it as you instructed. Yeah, we can use Service to connect the pods. How do I create a service so that the pods can talk to one another?


However, since your Pod doesn't have a label app: mysql-master, we'll need to add that label to the Pod or modify the Service's selector.

Let's add the label to the Pod:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl label pod mysql-master app=mysql-master
pod/mysql-master labeled

Then, apply the Service configuration:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-master-service.yaml
service/mysql-master-service created

Once the Service is created, you can verify its existence:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get svc
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
mysql-master-service   ClusterIP      10.96.116.173    <none>        3306/TCP       98s

The Service will provide a stable IP address and DNS name for your MySQL master pod, allowing other pods to connect to it.

To connect to the Service from another pod, you can use the Service's DNS name:

mysql -h mysql-master-service.default.svc.cluster.local -P 3306 -u root -p


Step 3: Create the worker/slave pods

Meta AI Prompt: Just create 2 worker pods with mysql 8 on them and make sure that they're connected to the same network as the master and can talk to one another.


File: mysql-worker-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-worker
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mysql-worker
  template:
    metadata:
      labels:
        app: mysql-worker
    spec:
      containers:
      - name: mysql
        image: mysql:8
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "spidersoupsql"
        ports:
        - containerPort: 3306

Apply the configuration:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-worker-deployment.yaml
deployment.apps/mysql-worker created

This will create 2 worker pods with MySQL 8. You can scale the number of pods by adjusting the replicas field and reapplying the configuration.

Let's keep the Service YAML file for the workers the same:


File: mysql-worker-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-worker-service
spec:
  selector:
    app: mysql-worker
  ports:
  - name: mysql
    port: 3306
    targetPort: 3306
  type: ClusterIP

Apply the Service configuration:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-worker-service.yaml
service/mysql-worker-service created

Check that the cluster is build

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
mysql-master                    1/1     Running   0          67m
mysql-worker-766b57b7d8-gt7w8   1/1     Running   0          15m
mysql-worker-766b57b7d8-jb4dc   1/1     Running   0          15m

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get service
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes             ClusterIP   10.96.0.1               443/TCP    4d18h
mysql-master-service   ClusterIP   10.110.185.97           3306/TCP   113s
mysql-worker-service   ClusterIP   10.100.218.86           3306/TCP   14s


Step 4: Check the cluster networking

Get the containers

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED             STATUS             PORTS     NAMES
f9db7127bd89   f5e6ba656d10   "docker-entrypoint.s…"   21 minutes ago      Up 21 minutes                k8s_mysql_mysql-worker-766b57b7d8-jb4dc_default_11cad6c1-0b8d-4d87-8fcd-fee87c3e9d61_0
49716d199e8f   f5e6ba656d10   "docker-entrypoint.s…"   21 minutes ago      Up 21 minutes                k8s_mysql_mysql-worker-766b57b7d8-gt7w8_default_e8f7e6ec-0a3f-4fd9-bc36-5db24a68ddac_0
4c6629430c44   mysql          "docker-entrypoint.s…"   About an hour ago   Up About an hour             k8s_mysql_mysql-master_default_d6726ee0-eee5-4a63-9b0d-08107238014c_0

Go into the master

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker exec -it 4c6629430c44 /bin/bash
bash-5.1# mysql -h localhost -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.4.5 MySQL Community Server - GPL
(truncated output)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> create database this_is_the_master;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| this_is_the_master |
+--------------------+
5 rows in set (0.00 sec)

mysql> exit;
Bye
bash-5.1# exit
exit

Try connecting from a worker/slave

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
f9db7127bd89   f5e6ba656d10   "docker-entrypoint.s…"   41 minutes ago   Up 41 minutes             k8s_mysql_mysql-worker-766b57b7d8-jb4dc_default_11cad6c1-0b8d-4d87-8fcd-fee87c3e9d61_0
49716d199e8f   f5e6ba656d10   "docker-entrypoint.s…"   41 minutes ago   Up 41 minutes             k8s_mysql_mysql-worker-766b57b7d8-gt7w8_default_e8f7e6ec-0a3f-4fd9-bc36-5db24a68ddac_0
4c6629430c44   mysql          "docker-entrypoint.s…"   2 hours ago      Up 2 hours                k8s_mysql_mysql-master_default_d6726ee0-eee5-4a63-9b0d-08107238014c_0

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker exec -it f9db7127bd89 /bin/bash
bash-5.1#

You can confirm that you're on one of the slaves because there's no this_is_the_master database

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker exec -it f9db7127bd89 /bin/bash
bash-5.1# mysql -h localhost -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.4.5 MySQL Community Server - GPL
(truncated output)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> exit;
Bye
bash-5.1#

Now to test the cluster networking by connecting to the master from the slave

bash-5.1# mysql -h mysql-master-service.default.svc.cluster.local -P 3306 -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.4.5 MySQL Community Server - GPL
(truncated output)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| this_is_the_master |
+--------------------+
5 rows in set (0.00 sec)

mysql> exit;
Bye
bash-5.1# exit
exit
blazingraptor@galactica:~/docker/mysql-repl-k8s$


Step 5: Check the volumes

See the volumes

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker volume ls
DRIVER    VOLUME NAME
local     167ca1863feb3958f24ed9b3592b07c0b84deacab7ad0a24c0f0c6dd85153d2e
local     a484a90734ec59339b03c7d5ef2147ac89e0e441c55a1ce3cb75fcc452bbdd8a
local     cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff

I was able to use Docker Desktop to see that cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff was the master because inside it was my testing "master" database file. I specifically created that database to differentiate the pods/volumes.

this_is_the_master

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker volume inspect cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff
[
    {
        "CreatedAt": "2025-04-18T18:26:08Z",
        "Driver": "local",
        "Labels": {
            "com.docker.volume.anonymous": ""
        },
        "Mountpoint": "/var/lib/docker/volumes/cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff/_data",
        "Name": "cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff",
        "Options": null,
        "Scope": "local"
    }
]

If you don't have Docker Desktop, you can still peek inside of your volumes with a temporary container

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker volume ls
DRIVER    VOLUME NAME
local     167ca1863feb3958f24ed9b3592b07c0b84deacab7ad0a24c0f0c6dd85153d2e
local     a484a90734ec59339b03c7d5ef2147ac89e0e441c55a1ce3cb75fcc452bbdd8a
local     cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker run -it --rm -v cb1416dcb0199f9c04d7f9b37a186f6d2889803a84b5c9a7feae2118dbc613ff:/data alpine ash
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
f18232174bc9: Pull complete
Digest: sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
Status: Downloaded newer image for alpine:latest
/ # ls /data/
#ib_16384_0.dblwr      #innodb_temp           binlog.000002          ca.pem                 ib_buffer_pool         mysql                  mysql_upgrade_history  public_key.pem         sys                    undo_002
#ib_16384_1.dblwr      auto.cnf               binlog.index           client-cert.pem        ibdata1                mysql.ibd              performance_schema     server-cert.pem        this_is_the_master
#innodb_redo           binlog.000001          ca-key.pem             client-key.pem         ibtmp1                 mysql.sock             private_key.pem        server-key.pem         undo_001
/ # ls /data/ | grep master
this_is_the_master

Check the persistent volumes

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pvc
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
mysql-persistent-storage-mysql-0   Bound    pvc-84b562a1-cffd-4928-aeb4-52c0ca8ed6af   1Gi        RWO            hostpath                        2d22h

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                      STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-84b562a1-cffd-4928-aeb4-52c0ca8ed6af   1Gi        RWO            Delete           Bound    default/mysql-persistent-storage-mysql-0   hostpath                                 2d22h


Step 6: Testing delete the project

Delete the project but leave the volumes

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete all --all
pod "mysql-master" deleted
pod "mysql-worker-766b57b7d8-gt7w8" deleted
pod "mysql-worker-766b57b7d8-jb4dc" deleted
service "kubernetes" deleted
service "mysql" deleted
service "mysql-master-service" deleted
service "mysql-worker-service" deleted
service "ps-lb" deleted
deployment.apps "mysql-worker" deleted
statefulset.apps "mysql" deleted

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker volume ls
DRIVER    VOLUME NAME

Yep, as I suspected, the volume are deleted since they were dynamically created.



Step 7: Create a Persistent Volume (PV)

Meta AI Prompt: How do I explicitly attach a persistent volume that even survives pod deletion?

Create a file named mysql-pv.yaml with the following content:

File: mysql-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  local:
    path: /mnt/data
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - your-node-name
  storageClassName: local-storage

Replace your-node-name with the actual name of your node.

I'm going to use mysql-persistent-storage



Step 8: Create a Persistent Volume Claim (PVC)

Create a file named mysql-pvc.yaml with the following content:

File: mysql-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: local-storage


Step 9: Update your pod configuration

Update your mysql-master-pod.yaml file to reference the PVC:


File: mysql-master-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mysql-master
spec:
  containers:
  - name: mysql
    image: mysql:8
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "spidersoupsql"
    ports:
    - containerPort: 3306
    volumeMounts:
    - name: mysql-persistent-storage
      mountPath: /var/lib/mysql
  volumes:
  - name: mysql-persistent-storage
    persistentVolumeClaim:
      claimName: mysql-pvc

Apply the configuration:

kubectl apply -f mysql-pv.yaml
kubectl apply -f mysql-pvc.yaml
kubectl apply -f mysql-master-pod.yaml

Example:

kubectl apply -f mysql-pv.yaml
kubectl apply -f mysql-pvc.yaml
kubectl apply -f mysql-master-pod.yaml

But actually, I needed to use a different configuration

The node name is docker-desktop. You can use this name in your mysql-pv.yaml file.

However, since you're using Docker Desktop, you might not need to specify the node name or use a local storage class. You can try using a hostPath volume instead, which is a simple way to persist data in a local development environment.

Here's an example of how you can modify your mysql-pv.yaml file to use a hostPath volume:

File: mysql-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  hostPath:
    path: /mnt/mysql-repl-k8s-data

Make sure to create the /mnt/mysql-repl-k8s-data directory on your host machine if it doesn't exist.

blazingraptor@galactica:~/docker/mysql-repl-k8s$ mkdir /mnt/mysql-repl-k8s-data
mkdir: cannot create directory ‘/mnt/mysql-repl-k8s-data’: Permission denied
blazingraptor@galactica:~/docker/mysql-repl-k8s$ pwd
/home/blazingraptor/docker/mysql-repl-k8s
blazingraptor@galactica:~/docker/mysql-repl-k8s$ stat blazingraptor@galactica:~/docker/mysql-repl-k8s
stat: cannot statx 'blazingraptor@galactica:~/docker/mysql-repl-k8s': No such file or directory
blazingraptor@galactica:~/docker/mysql-repl-k8s$ stat /home/blazingraptor/docker/mysql-repl-k8s
  File: /home/blazingraptor/docker/mysql-repl-k8s
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: 820h/2080d      Inode: 1170        Links: 2
Access: (0755/drwxr-xr-x)  Uid: ( 1000/blazingraptor)   Gid: ( 1000/blazingraptor)
Access: 2025-04-25 11:25:54.826911339 -0400
Modify: 2025-04-25 11:56:50.313878134 -0400
Change: 2025-04-25 11:56:50.313878134 -0400
 Birth: 2025-04-18 13:52:13.365635130 -0400
blazingraptor@galactica:~/docker/mysql-repl-k8s$ sudo mkdir /mnt/mysql-repl-k8s-data
[sudo] password for blazingraptor:
blazingraptor@galactica:~/docker/mysql-repl-k8s$ sudo chown blazingraptor:blazingraptor /mnt/mysql-repl-k8s-data
blazingraptor@galactica:~/docker/mysql-repl-k8s$ stat /mnt/mysql-repl-k8s-data
  File: /mnt/mysql-repl-k8s-data
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: 820h/2080d      Inode: 1489        Links: 2
Access: (0755/drwxr-xr-x)  Uid: ( 1000/blazingraptor)   Gid: ( 1000/blazingraptor)
Access: 2025-04-25 11:59:56.738029237 -0400
Modify: 2025-04-25 11:59:56.738029237 -0400
Change: 2025-04-25 12:00:11.959801171 -0400
 Birth: 2025-04-25 11:59:56.738029237 -0400

I had to restart things to get this to work

^Cblazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-pv.yaml
The PersistentVolume "mysql-pv" is invalid:
* spec.persistentvolumesource: Forbidden: spec.persistentvolumesource is immutable after creation
  core.PersistentVolumeSource{
        GCEPersistentDisk:    nil,
        AWSElasticBlockStore: nil,
        HostPath:             nil,
        HostPath:             &core.HostPathVolumeSource{Path: "/mnt/mysql-repl-k8s-data", Type: &""},
        Glusterfs:            nil,
        NFS:                  nil,
        ... // 12 identical fields
        PortworxVolume: nil,
        ScaleIO:        nil,
        Local:          &core.LocalVolumeSource{Path: "/mnt/data"},
        Local:          nil,
        StorageOS:      nil,
        CSI:            nil,
  }

* nodeAffinity: Invalid value: "null": field is immutable, except for updating from beta label to GA
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete pv mysql-pv
persistentvolume "mysql-pv" deleted
^Cblazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete pvc mysql-pvc
persistentvolumeclaim "mysql-pvc" deleted
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete pod mysql-master
Error from server (NotFound): pods "mysql-master" not found
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-pv.yaml
persistentvolume/mysql-pv created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-pvc.yaml
persistentvolumeclaim/mysql-pvc created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-master-pod.yaml
pod/mysql-master created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
mysql-master                    1/1     Running   0          12s
mysql-worker-766b57b7d8-9g8rh   1/1     Running   0          97m
mysql-worker-766b57b7d8-fwprs   1/1     Running   0          97m


Step 10: Fix Persistent Volumes with Docker Desktop and Kubernetes in WSL

Persistent Volumes with Docker Desktop and Kubernetes

Docker Desktop Kubernetes containers don’t see the same filesystem that WSL Distros do

This is because the filesystem your containers see is a different file path than what your linux distro sees. If you create the following directory:

mkdir /mnt/wsl/mysql-repl-k8s-data
sudo chmod 755 /mnt/wsl/mysql-repl-k8s-data

You have to use this in your config

/run/desktop/mnt/host/wsl/mysql-repl-k8s-data

Edit the file mysql-pv.yaml


File: mysql-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  hostPath:
    path: /run/desktop/mnt/host/wsl/mysql-repl-k8s-data

Rebuild the cluster because of locked resources

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete all --all
pod "mysql-master" deleted
pod "mysql-worker-766b57b7d8-9g8rh" deleted
pod "mysql-worker-766b57b7d8-fwprs" deleted
service "kubernetes" deleted
service "mysql-master-service" deleted
service "mysql-worker-service" deleted
deployment.apps "mysql-worker" deleted

If you need to delete the old volumes, you can just BE CAREFUL THAT YOU ACTUALLY WANT TO DO THIS! AS IT WILL DELETE YOUR DATABASES!

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS    VOLUMEATTRIBUTESCLASS   REASON   AGE
mysql-pv   1Gi        RWO            Retain           Bound    default/mysql-pvc   local-storage                             84m

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete pvc mysql-pvc
persistentvolumeclaim "mysql-pvc" deleted
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl delete pv mysql-pv
persistentvolume "mysql-pv" deleted

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-pv.yaml
persistentvolume/mysql-pv created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-pvc.yaml
persistentvolumeclaim/mysql-pvc created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-master-pod.yaml
pod/mysql-master created
blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl apply -f mysql-worker-deployment.yaml
deployment.apps/mysql-worker created

Readd the label

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl label pod mysql-master app=mysql-master
pod/mysql-master labeled

Readd the test database

blazingraptor@galactica:~/docker/mysql-repl-k8s$ docker exec -it 7d65c244a1b7 /bin/bash
bash-5.1# mysql -h localhost -u root -p
(truncated output)
mysql> create database this_is_the_master;
Query OK, 1 row affected (0.00 sec)

Check for the test file

blazingraptor@galactica:~/docker/mysql-repl-k8s$ ls -d /mnt/wsl/mysql-repl-k8s-data/this_is_the_master/
/mnt/wsl/mysql-repl-k8s-data/this_is_the_master/

Check the volumes

blazingraptor@galactica:~/docker/mysql-repl-k8s$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS    VOLUMEATTRIBUTESCLASS   REASON   AGE
mysql-pv   1Gi        RWO            Retain           Bound    default/mysql-pvc   local-storage                             76m


Step 11: Build the Ansible container

Meta AI Prompt: I'm building a kubectl cluster on docker desktop with kubernetes. I'll need you assistance.

a: Create a Dockerfile for the Ansible image:

blazingraptor@galactica:~/docker/mysql-repl-k8s$ mkdir ansible
blazingraptor@galactica:~/docker/mysql-repl-k8s$ cd ansible/
blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$
blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ touch Dockerfile

File: Dockerfile

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y ansible

b. Build the Docker image:

docker build -t mysql-repl-k8s-ansible .

Example

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ docker build -t mysql-repl-k8s-ansible .
[+] Building 74.6s (7/7) FINISHED                                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                                              0.0s
 => => transferring dockerfile: 96B                                                                                               0.0s
 => [internal] load metadata for docker.io/library/ubuntu:24.04                                                                   1.2s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                                     0.0s
 => [internal] load .dockerignore                                                                                                 0.0s
 => => transferring context: 2B                                                                                                   0.0s
 => [1/2] FROM docker.io/library/ubuntu:24.04@sha256:1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02             4.7s
 => => resolve docker.io/library/ubuntu:24.04@sha256:1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02             0.0s
 => => sha256:2726e237d1a374379e783053d93d0345c8a3bf3c57b5d35b099de1ad777486ee 29.72MB / 29.72MB                                  2.9s
 => => sha256:1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02 6.69kB / 6.69kB                                    0.0s
 => => sha256:f8b860e4f9036f2694571770da292642eebcc4c2ea0c70a1a9244c2a1d436cd9 424B / 424B                                        0.0s
 => => sha256:602eb6fb314b5fafad376a32ab55194e535e533dec6552f82b70d7ac0e554b1c 2.30kB / 2.30kB                                    0.0s
 => => extracting sha256:2726e237d1a374379e783053d93d0345c8a3bf3c57b5d35b099de1ad777486ee                                         1.6s
 => [2/2] RUN apt update && apt install -y ansible                                                                               56.2s
 => exporting to image                                                                                                            9.2s
 => => exporting layers                                                                                                           6.9s
 => => writing image sha256:97db86d00d29c5fbe5afecdabe63de9bc9834b9abdae8c4e386080f167755189                                      0.2s
 => => naming to docker.io/library/mysql-repl-k8s-ansible

c. Tag the image

docker tag mysql-repl-k8s-ansible blazingraptor/mysql-repl-k8s-ansible:1.0

Example

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ docker tag mysql-repl-k8s-ansible blazingraptor/mysql-repl-k8s-ansible:1.0

d. Make a repo on Docker Hub mysql-repl-k8s-ansible


e. Push the image to a container registry

docker push blazingraptor/mysql-repl-k8s-ansible:1.0

Example

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ docker push blazingraptor/mysql-repl-k8s-ansible:1.0
The push refers to repository [docker.io/blazingraptor/mysql-repl-k8s-ansible]
94f803e49fa6: Pushed
3abdd8a5e7a8: Mounted from library/ubuntu
1.0: digest: sha256:5f5b3b829330d38a193d31a34fdd998dcf335e77697d64cbcc56895ee051a408 size: 742

f. Create a Kubernetes deployment YAML file for the Ansible container:


File: ansible-deployment.yaml


Apply the deployment YAML file to your Kubernetes cluster:

kubectl apply -f ansible-deployment.yaml

Example

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ kubectl apply -f ansible-deployment.yaml
deployment.apps/ansible created

f. Create a Kubernetes deployment YAML file for the Ansible container:

kubectl exec -it <ansible-pod-name> -- /bin/bash

Example

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
ansible-557b8678bd-2425j        1/1     Running   0          44m
mysql-master                    1/1     Running   0          4h4m
mysql-worker-766b57b7d8-4jtll   1/1     Running   0          4h4m
mysql-worker-766b57b7d8-tdqt7   1/1     Running   0          4h4m

blazingraptor@galactica:~/docker/mysql-repl-k8s/ansible$ kubectl exec -it ansible-557b8678bd-2425j -- /bin/bash
root@ansible-557b8678bd-2425j:/#






title

title



Software RAID SSDs

For each disk in the array, create a partition of 80% size (starting at sector 2048) to overprovision and align the drive:

Usage:

usage

Example:

example