Age Gap Is Not a Problem

MySQL × Cloud-Native

Sergey Pronin Founder, Solanica Inc. · Maintainer, OpenEverest

The Age Gap

MySQL turned 19 when Kubernetes was born

18 years
🎬 Toy Story premieres
1995 MySQL 1.0 MySQL
📖 Wikipedia launches
2001
📱 First iPhone announced
2007
2013 Docker
2014 Kubernetes Kubernetes
2018 Operator SDK
2019 Percona
Operator
for MySQL
Pre-databases Sergey Pronin — old photo, still with hair

Yes, I used to have hair.
Then I started running databases on Kubernetes.

Why listen to me

I've been on both sides of this problem.

  • Before Ran lots of Kubernetes clusters. Convinced K8s was for stateless workloads only.
  • 5 yrs @ Percona Led product teams. First assignment: build operators for databases.
  • Today Founder, Solanica  ·  maintainer, OpenEverest (CNCF).

The Problem

Two problems. Different solutions.

01

Philosophical

MySQL was built for permanent, named servers. Kubernetes assumes everything is temporary. The mental models don't overlap.

02

Technical

Replication, storage, failover, and connection routing all behave differently inside a cluster. The sharp edges are real.

Philosophical

MySQL grew up as a pet.
Kubernetes raises cattle.

🐕 Pet
  • db-primary.prod.local
  • Alert → SSH → investigate
  • The disk is the server
🐄🐄🐄 Cattle
  • mysql-abc-7f9d2
  • Crash → reschedule
  • State must be explicit

Part 2

Technical

Replication  ·  Storage  ·  Failover  ·  Networking

Problem

00

before everything else

Tech
Choice

IaC, Helm, or Operator — how do you even run a database on Kubernetes?

The building block

What's an Operator?

CUSTOM RESOURCE kind: PerconaXtraDBCluster replicas: 3 storage: 50Gi backup: daily pitr: enabled version: "8.0.42" watches OPERATOR CONTROLLER ① Watch API server ② Compare ③ Reconcile continuous reconciliation loop creates & manages StatefulSet 3 pods · ordered PersistentVolumeClaims × 3 replicas Services primary · replica · headless Secrets + ConfigMaps creds · tuning CronJob scheduled backups

Problem

01

of many

High
Availability

When everything is allowed to fail — what happens to your database?

Uptime, then  and  now

Then

423 days

Maintenance windows. Graceful failover. Expected behavior.

Now

14:02:11evictpod terminated
14:02:34drainnode cordoned
14:02:48oomcontainer killed
14:03:07pvcvolume remount
14:03:22netpartition detected
14:03:55nodekernel reboot
14:04:18probeliveness failed
14:04:46scaleHPA scaled down
14:02:11evictpod terminated
14:02:34drainnode cordoned
14:02:48oomcontainer killed
14:03:07pvcvolume remount
14:03:22netpartition detected
14:03:55nodekernel reboot
14:04:18probeliveness failed
14:04:46scaleHPA scaled down

Anything. Anytime. By design.

Classic primary → replica

Async replication.
Failover = data loss.

Primary

mysql-0

accepts writes

T₁ T₂ T₃ T₄ T₅

binlog · async, with lag

Replica

mysql-1

always behind

In-flight transactions never arrive

Percona XtraDB Cluster · Galera

Every commit, on every node.

INSERT …

PXC

mysql-0

PXC

mysql-1

PXC

mysql-2

Lose any node. Zero data loss.

Problem

02

crash recovery

Full Cluster
Crash

Everyone wakes up. Nobody volunteers.

mysql-0

seqno

18

“might not be me”

mysql-1

seqno

18

“might not be me”

mysql-2

seqno

19

“might not be me”

how it happens

regional outage power loss kubectl delete --all

Highest seqno wins.

The operator scans every pod, picks the leader, and the cluster picks itself back up.

operator

scans all pods

mysql-0

seqno

18

joins

mysql-1

seqno

18

joins

mysql-2

seqno

19

bootstrap

Problem

03

backups & pitr

Backups &
Point-in-Time
Recovery

3am. The primary is gone. Where is your last transaction?

Backups are easy.   PITR is not.

Backups

xtrabackup S3

Snapshot. Schedule. Done.

?

PITR

binlogs S3

Streamed. Continuously. From a cluster.

The naive way

Every node uploads. Welcome to chaos.

PXC

mysql-0

PXC

mysql-1

PXC

mysql-2

S3 bucket

binlog.000087
binlog.000088 dup
binlog.000088 dup
binlog.000089
…000091 gap
Duplicate uploads Gaps when a node dies Who owns the binlog?

The answer

One Pod. One stream. One source of truth.

PXC

mysql-0

selected

mysql-1

oldest binlogs

PXC

mysql-2

PITR Pod

binlog-collector

lastUploaded: …d4a:3217
source: mysql-1
stream: mysqlbinlog -R

S3

binlog_…3215
binlog_…3216
binlog_…3217
One writer Tracks GTIDs Detects gaps Survives node failures

Problem

04

storage

Storage

When it's slow, it's always this.

Backups

It all ends up in S3.

In the cloud

AWS S3 Azure Blob Google GCS

Self-hosted

MinIO Ceph RGW RustFS

Don't keep backups in the same cluster. Different DC, different cloud — or just pay the cloud. It's often cheaper.

The database

Data → block storage.

pod

mysqld

network

PVC

block volume

In the cloud

AWS EBS Azure Disk GCE PD

On-prem

Ceph RBD Enterprise SAN

Or

Skip the network. Use the local NVMe.

k8s node-1
mysqld
NVMe
k8s node-2
mysqld
NVMe
k8s node-3
mysqld
NVMe
tens of µs, not ms no network hop cheaper at scale

Part 3

Operators

Percona  ·  Oracle  ·  MOCO  ·  OpenEverest

What's on the table

Four MySQL operators.

Two mature paths. Two with caveats.

Percona

PXC Operator

Percona XtraDB Cluster  ·  Galera sync

mature  ·  widely deployed

Percona

Server Operator

Group Replication  +  async

mature  ·  for async-tolerant apps

Oracle

MySQL Operator

Group Replication

limited features  ·  low adoption

Cybozu

MOCO

semi-sync  ·  GTID-based

feature-rich  ·  semi-sync sunset looming

One UI for all your databases.

CNCF openeverest/openeverest
OpenEverest — create cluster with engine and version selection openeverest.io

Community

A vendor-neutral home for MySQL.

501(c)(6) nonprofit · independent of Oracle · launched May 2026

MySQL Cloud Native

Age gap really isn't a problem — when solved right.

Thank you.

Sergey Pronin · solanica.io