Cloud Native 10 min read

Deploy MySQL Primary‑Replica on Kubernetes with Helm and Persistent Volumes

This guide walks through deploying a MySQL primary‑replica cluster on Kubernetes using Helm charts, configuring persistent volumes, exposing services, and adding Prometheus and Grafana monitoring, while also covering installation, testing, and clean‑up steps.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Deploy MySQL Primary‑Replica on Kubernetes with Helm and Persistent Volumes

Overview

MySQL is a widely used relational database system. Deploying MySQL on Kubernetes provides resource isolation, dynamic scaling, environment consistency, and easier operations.

Advantages of MySQL on Kubernetes

Resource isolation

Dynamic elastic scaling

Environment consistency

Operational convenience

Step‑by‑Step Deployment (One Primary, Two Replicas)

1) Add Helm Repository

helm repo add bitnami https://charts.bitnami.com/bitnami
helm pull bitnami/mysql
tar -xf mysql-9.3.3.tgz

2) Modify Configuration

Edit mysql/values.yaml to set the image registry, repository, tag, and replication architecture. Example snippets:

image:
  registry: myharbor.com
  repository: bigdata/mysql
  tag: 8.0.30-debian-11-r15
architecture: replication

primary:
  persistence:
    enabled: true
    size: 10Gi
    storageClass: "mysql-local-storage"
    local:
    - name: mysql-0
      host: "local-168-182-110"
      path: "/opt/bigdata/servers/mysql/data/data1"
  service:
    type: NodePort
    nodePorts:
      mysql: "30306"

secondary:
  replicaCount: 2
  persistence:
    enabled: true
    size: 10Gi
    storageClass: "mysql-local-storage"
    local:
    - name: mysql-1
      host: "local-168-182-111"
      path: "/opt/bigdata/servers/mysql/data/data1"
    - name: mysql-2
      host: "local-168-182-112"
      path: "/opt/bigdata/servers/mysql/data/data1"
  service:
    type: NodePort
    nodePorts:
      mysql: "30307"

metrics:
  enabled: true
  image:
    registry: myharbor.com
    repository: bigdata/mysqld-exporter
    tag: 0.14.0-debian-11-r33

3) Create PersistentVolume Definitions

{{- range .Values.primary.persistence.local }}
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: {{ .name }}
  labels:
    name: {{ .name }}
spec:
  storageClassName: {{ $.Values.primary.persistence.storageClass }}
  capacity:
    storage: {{ $.Values.primary.persistence.size }}
  accessModes:
    - ReadWriteOnce
  local:
    path: {{ .path }}
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - {{ .host }}
{{- end }}

{{- range .Values.secondary.persistence.local }}
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: {{ .name }}
  labels:
    name: {{ .name }}
spec:
  storageClassName: {{ $.Values.secondary.persistence.storageClass }}
  capacity:
    storage: {{ $.Values.secondary.persistence.size }}
  accessModes:
    - ReadWriteOnce
  local:
    path: {{ .path }}
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - {{ .host }}
{{- end }}

4) Define StorageClass

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: {{ .Values.primary.persistence.storageClass }}
provisioner: kubernetes.io/no-provisioner

5) Install the Chart

# Create persistent directories on the host
mkdir -p /opt/bigdata/servers/mysql/data/data1

# Pull and push custom images to the private registry
docker pull docker.io/bitnami/mysql:8.0.30-debian-11-r15
docker tag docker.io/bitnami/mysql:8.0.30-debian-11-r15 myharbor.com/bigdata/mysql:8.0.30-debian-11-r15
docker push myharbor.com/bigdata/mysql:8.0.30-debian-11-r15

docker pull docker.io/bitnami/mysqld-exporter:0.14.0-debian-11-r33
docker tag docker.io/bitnami/mysqld-exporter:0.14.0-debian-11-r33 myharbor.com/bigdata/mysqld-exporter:0.14.0-debian-11-r33
docker push myharbor.com/bigdata/mysqld-exporter:0.14.0-debian-11-r33

# Install the Helm chart
helm install mysql ./mysql -n mysql --create-namespace

Installation Notes

NAME: mysql
LAST DEPLOYED: Mon Sep 19 23:57:18 2022
NAMESPACE: mysql
STATUS: deployed
REVISION: 1
CHART: mysql
CHART VERSION: 9.3.3
APP VERSION: 8.0.30

# Watch deployment status
kubectl get pods -w --namespace mysql

# Service endpoints
Primary: mysql-primary.mysql.svc.cluster.local:3306
Secondary: mysql-secondary.mysql.svc.cluster.local:3306

# Retrieve root password
MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace mysql mysql -o jsonpath="{.data.mysql-root-password}" | base64 -d)

# Connect using a temporary client pod
kubectl run mysql-client --rm -it --restart='Never' \
  --image=myharbor.com/bigdata/mysql:8.0.30-debian-11-r15 \
  --namespace mysql \
  --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD -- bash

# Primary (read/write)
mysql -h mysql-primary.mysql.svc.cluster.local -uroot -p"$MYSQL_ROOT_PASSWORD"

# Secondary (read‑only)
mysql -h mysql-secondary.mysql.svc.cluster.local -uroot -p"$MYSQL_ROOT_PASSWORD"

6) Prometheus Monitoring

Expose the MySQL exporter service and scrape metrics:

# Port‑forward the metrics endpoint
kubectl port-forward --namespace mysql svc/mysql-metrics 9104:9104 &
curl http://127.0.0.1:9104/metrics

Grafana can be configured to import a MySQL dashboard (e.g., ID 7362) from https://grafana.com/grafana/dashboards/ . Admin credentials are admin and the password can be obtained with:

kubectl get secret --namespace grafana grafana -o jsonpath="{.data.admin-password}" | base64 --decode

7) Uninstall

helm uninstall mysql -n mysql
kubectl delete pod -n mysql $(kubectl get pod -n mysql -o name | cut -d'/' -f2) --force
kubectl patch ns mysql -p '{"metadata":{"finalizers":null}}'
kubectl delete ns mysql --force

Conclusion

The guide demonstrates a basic MySQL primary‑replica deployment on Kubernetes without high‑availability features. While production‑grade HA solutions exist, they are not covered here. The setup is suitable for metadata storage in big‑data environments where occasional primary failures have limited impact. Future work may explore true HA implementations for MySQL on Kubernetes.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KubernetesPrometheusmysqlGrafanahelmPersistentVolumePrimary-Replica
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.