Deploy a stateful, high-availability MySQL cluster on ACK Serverless
ACK Serverless lets you use native Kubernetes scheduling semantics to spread pods across multiple availability zones without managing nodes. This guide walks you through deploying a three-replica MySQL StatefulSet on ACK Serverless so that each replica runs in a different zone, giving you zone-level fault tolerance for stateful workloads.
By the end of this guide, you will have:
-
A
mysqlnamespace with a Secret and StorageClass -
A MySQL StatefulSet (
dbc1) with three replicas spread across three zones -
Verified that each pod is scheduled to a different virtual node in a different zone
Prerequisites
Before you begin, ensure that you have:
-
An ACK Serverless cluster with multiple virtual nodes. For more information, see Create an ACK Serverless cluster.
-
Virtual node scheduling policies enabled on the cluster. For more information, see Enable virtual node scheduling policies for a cluster.
-
The csi-provisioner component at version v1.22.9 or later installed.
How it works
The StatefulSet uses two complementary scheduling constraints to achieve zone-level high availability:
-
Topology spread constraints (
topologySpreadConstraints): distributes pods evenly across zones. WithmaxSkew: 1andtopologyKey: topology.kubernetes.io/zone, the scheduler ensures no zone hosts more than one extra replica compared to any other zone. -
Pod anti-affinity (
podAntiAffinity): enforces node-level separation. Even within the same zone, each pod must run on a different virtual node. This prevents two replicas from sharing a single node.
Both constraints are required because topology spread alone controls zone distribution but does not prevent two pods from landing on the same node within a zone. Pod anti-affinity fills that gap by enforcing strict node-level separation.
Storage is provisioned by the fast-storageclass StorageClass using WaitForFirstConsumer binding. Each PersistentVolumeClaim (PVC) is not created until a pod is scheduled, which ensures the cloud disk is provisioned in the same zone as the pod — a requirement for zone-aware storage.
reclaimPolicy: Retain means that PVCs are not deleted automatically when you scale down the StatefulSet. To release storage, delete the PVCs manually after scaling down.Step 1: Clone the example repository
-
Clone the repository.
git clone https://github.com/AliyunContainerService/serverless-k8s-examples.git -
Navigate to the working directory and list the YAML files.
cd serverless-k8s-examples/stateful-mysql ls -alExpected output:
README.md secret.yaml stateful-mysql.yaml storageclass.yamlThe three YAML files you will apply:
File Creates secret.yamlSecret for MySQL passwords storageclass.yamlStorageClass for per-zone cloud disk provisioning stateful-mysql.yamlMySQL StatefulSet with zone-spread scheduling
Step 2: Create the namespace, Secret, and StorageClass
-
Create the
mysqlnamespace.kubectl create namespace mysqlExpected output:
namespace/mysql created -
Create the Secret that stores MySQL passwords.
kubectl apply -n mysql -f secret.yamlExpected output:
secret/mysql-secret createdThe following is the YAML file for the Secret.
-
Create the StorageClass.
kubectl apply -f storageclass.yamlExpected output:
storageclass.storage.k8s.io/fast-storageclass createdThe following is the YAML file for the StorageClass.
Step 3: Deploy the MySQL StatefulSet
-
Apply the StatefulSet manifest. This creates three MySQL replicas spread across zones using topology spread constraints and pod anti-affinity.
kubectl apply -n mysql -f stateful-mysql.yamlExpected output:
statefulset.apps/dbc1 createdThe following is the YAML file for the StatefulSet.
Step 4: Verify zone distribution
-
Confirm the StatefulSet is ready.
kubectl get statefulset -n mysqlExpected output:
NAME READY AGE dbc1 3/3 7m21s -
Check pod placement across zones.
kubectl -n mysql get po -o wideExpected output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES dbc1-0 1/1 Running 0 2m28s 10.1.214.213 virtual-kubelet-cn-hangzhou-j <none> <none> dbc1-1 1/1 Running 0 106s 10.3.146.113 virtual-kubelet-cn-hangzhou-h <none> <none> dbc1-2 1/1 Running 0 64s 10.4.232.78 virtual-kubelet-cn-hangzhou-g <none> <none>The
NODEcolumn contains the zone identifier. In the example above, the three pods are scheduled tocn-hangzhou-j,cn-hangzhou-h, andcn-hangzhou-g, confirming that the cluster is spread across three separate zones.