Skip to content

MySQL

Production-ready MySQL deployment with support for standalone and source-replica replication architectures.

Key Features

  • Standalone and replication — Single instance or source-replica topology
  • Automatic initialization — Init scripts and custom configuration
  • Backup support — Configurable backup CronJobs to S3-compatible storage
  • Metrics — Prometheus exporter with ServiceMonitor
  • Security — Non-root containers, network policies, TLS support
  • Persistent storage — Configurable PVCs with storage class selection

Architecture

Standalone

Single MySQL instance with persistent storage and optional S3 backup.

Application client TCP:3306 MySQL StatefulSet (1 pod) source PVC (data) Backup CronJob mysqldump → S3

Source-Replica

Source (read-write) with binary log replication to read-only replicas.

Application read/write Source read + write pod-0 binlog Replica read-only pod-1 PVC (data) PVC (data) Backup CronJob → S3

Installation

HTTPS repository:

helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install my-mysql helmforge/mysql

OCI registry:

helm install my-mysql oci://ghcr.io/helmforgedev/helm/mysql

Deployment Examples

# values.yaml
architecture: standalone

auth:
  rootPassword: 'my-secret-password'
  database: myapp
  username: myuser
  password: 'user-password'

primary:
  persistence:
    size: 20Gi

metrics:
  enabled: true
  serviceMonitor:
    enabled: true
# values.yaml
architecture: replication

auth:
  rootPassword: 'my-secret-password'
  database: myapp
  username: myuser
  password: 'user-password'
  replicationPassword: 'repl-password'

primary:
  persistence:
    size: 20Gi

secondary:
  replicaCount: 2
  persistence:
    size: 20Gi
# values.yaml
architecture: standalone

auth:
  rootPassword: 'my-secret-password'
  database: myapp

primary:
  persistence:
    size: 20Gi

backup:
  enabled: true
  schedule: '0 3 * * *'
  s3:
    endpoint: https://s3.amazonaws.com
    bucket: my-mysql-backups
    accessKey: AKIAIOSFODNN7EXAMPLE
    secretKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
  retention:
    days: 30
# values.yaml — Use with phpMyAdmin or a web-based management tool
architecture: standalone

auth:
  rootPassword: 'my-secret-password'
  database: myapp

primary:
  persistence:
    size: 20Gi

ingress:
  enabled: true
  ingressClassName: traefik
  hosts:
    - host: phpmyadmin.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: phpmyadmin-tls
      hosts:
        - phpmyadmin.example.com
  # annotations:
  #   cert-manager.io/cluster-issuer: letsencrypt-prod

Key Values

KeyTypeDefaultDescription
architecturestringstandaloneDeployment architecture: standalone or replication
auth.rootPasswordstring""MySQL root password
auth.databasestring""Default database to create
auth.usernamestring""Default user to create
auth.passwordstring""Password for default user
auth.replicationPasswordstring""Password for replication user
primary.persistence.sizestring8GiPrimary PVC size
primary.persistence.storageClassstring""Storage class for primary PVC
primary.resources.requests.memorystring256MiMemory request for primary
primary.resources.requests.cpustring250mCPU request for primary
secondary.replicaCountinteger1Number of read replicas
secondary.persistence.sizestring8GiSecondary PVC size
backup.enabledbooleanfalseEnable S3 backup CronJob
backup.schedulestring0 3 * * *Cron schedule for backups
metrics.enabledbooleanfalseEnable Prometheus exporter
metrics.serviceMonitor.enabledbooleanfalseCreate ServiceMonitor resource
networkPolicy.enabledbooleanfalseEnable network policies
tls.enabledbooleanfalseEnable TLS encryption
service.ipFamilyPolicystringomittedService IP family policy: SingleStack, PreferDualStack, or RequireDualStack. Omit for cluster default.
service.ipFamiliesarrayomittedOrdered list of IP families (IPv4, IPv6). Omit for cluster default.

Dual-stack Networking

MySQL Services accept Kubernetes dual-stack configuration. By default, both service.ipFamilyPolicy and service.ipFamilies are unset and the chart inherits whatever the cluster advertises (matching prior behavior). Setting them propagates to every chart-managed Service: client, source, replicas, metrics, and the headless StatefulSet services.

service:
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
    - IPv4
    - IPv6

PreferDualStack is the safer choice for clusters that may be single- or dual-stack: omit ipFamilies and the cluster auto-populates whatever it supports. Set ipFamilies explicitly only when the cluster is configured for both families — the Kubernetes API rejects an explicit family the cluster does not advertise. RequireDualStack enforces both.

Upgrade Notes

Password persistence

MySQL stores the root password during initial setup. On upgrade, ensure auth.rootPassword matches the original value or the pod will fail to start with an authentication error.

  • When enabling replication on an existing standalone instance, a full re-initialization is required
  • Backup CronJob changes take effect on the next scheduled run
  • Secondary replicas are read-only; write attempts return an error

Common Issues

Pod stuck in CrashLoopBackOff after upgrade

If the root password in values doesn’t match the existing data directory, MySQL refuses to start. Check logs with kubectl logs <pod> and verify the password matches.

Replication lag monitoring

Enable metrics and monitor mysql_slave_status_seconds_behind_master. Values consistently above 0 indicate the replica cannot keep up — consider increasing replica resources or reducing write load.

More Information

See the source code and full values reference on GitHub.