Skip to main content

Quickstart

This guide walks through deploying CNMSQL and a three-instance Percona Server for MySQL cluster in a local Kind environment.

Prerequisites​

ToolPurpose
helmInstall the operator
kubectlInteract with the Kubernetes cluster
kindLocal Kubernetes cluster
cert-managerIssue TLS certificates for mTLS and MySQL TLS

Install cert-manager in your cluster if it isn't already present:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
kubectl wait --for=condition=Available deployment/cert-manager-webhook -n cert-manager --timeout=5m

1. Install the Operator​

Helm is the recommended way to install or upgrade. The chart is published from the charts repository:

helm install cnmsql oci://ghcr.io/cnmsql/charts/cnmsql \
--namespace cnmsql \
--create-namespace

The operator image defaults to ghcr.io/cnmsql/cnmsql pinned to the chart's appVersion, so no --set overrides are needed for a standard install or upgrade.

Verify the controller is running:

kubectl get pods -n cnmsql-system

You should see a single cnmsql-controller-manager Pod in Running state.

2. Pull the Instance Image​

Instance images are published from the containers repository. Pull the pre-built image and load it into Kind:

docker pull ghcr.io/cnmsql/cnmsql-instance:8.4
kind load docker-image ghcr.io/cnmsql/cnmsql-instance:8.4 --name cnmsql-test-e2e
Kind users

The operator image must also be loaded into Kind if your Kind cluster can't reach the registry. The image is ghcr.io/cnmsql/cnmsql tagged with the chart version:

docker pull ghcr.io/cnmsql/cnmsql:0.3.2
kind load docker-image ghcr.io/cnmsql/cnmsql:0.3.2 --name cnmsql-test-e2e

3. Install the CLI Plugin​

curl -sSfL https://github.com/cnmsql/cnmsql/raw/main/hack/install-cnmsql-plugin.sh | sh -s -- -b ~/.local/bin

The script downloads the latest release binary for your platform, verifies its checksum, and installs the plugin plus a tab-completion shim. Replace ~/.local/bin with any directory on your PATH (e.g. /usr/local/bin).

Verify the plugin is registered:

kubectl cnmsql version

The plugin is available as kubectl cnmsql. It auto-detects the cluster in the current namespace, so you can omit the cluster name in most commands.

4. Create a Cluster​

Apply a minimal three-instance cluster. An initial database app is bootstrapped with an app owner role:

apiVersion: mysql.cnmsql.co/v1alpha1
kind: Cluster
metadata:
name: cluster-sample
spec:
instances: 3
imageName: ghcr.io/cnmsql/cnmsql-instance:8.4
storage:
size: 10Gi
mysql:
binlogFormat: ROW
bootstrap:
initdb:
database: app
owner: app

Wait for the cluster to become ready:

kubectl wait --for=condition=Ready cluster/cluster-sample --timeout=15m

Inspect the topology with the CLI plugin:

kubectl cnmsql status cluster-sample

Expected result:

  • Three Pods: cluster-sample-1, cluster-sample-2, cluster-sample-3
  • One Pod labeled mysql.cnmsql.co/role=primary
  • Two Pods labeled mysql.cnmsql.co/role=replica
  • status.readyInstances is 3

5. Connect to the Database​

CNMSQL - CloudNative for MySQL creates three role-routed Services automatically:

ServiceEndpointRoutes to
cluster-sample-rwRead-writeCurrent primary
cluster-sample-roRead-onlyReady replicas
cluster-sample-rReadAny ready instance

Service routing follows the mysql.cnmsql.co/role label and updates automatically after failover with no manual reconfiguration needed.

Application credentials are generated and stored in a Secret. List all Secrets for the cluster:

kubectl get secrets -l mysql.cnmsql.co/cluster=cluster-sample

To test connectivity, launch a temporary MySQL client Pod and connect:

kubectl run mysql-client --rm -it --image=mysql:8.4 --restart=Never -- \
mysql -h cluster-sample-rw -u app -p$(kubectl get secret cluster-sample-app-app -o jsonpath='{.data.password}' | base64 -d) app

6. Scale the Cluster​

Scale up to four instances:

kubectl patch cluster cluster-sample --type merge -p '{"spec":{"instances":4}}'
kubectl wait --for=condition=Ready cluster/cluster-sample --timeout=15m

Scale down to one instance:

kubectl patch cluster cluster-sample --type merge -p '{"spec":{"instances":1}}'

Scale-down removes replica Pods (highest ordinal first) but retains their PVCs. Delete retained PVCs only after confirming the data is no longer needed.

7. Take a Backup​

Create an ad-hoc backup via the CLI:

kubectl cnmsql backup cluster-sample

This creates a Backup resource with defaults: XtraBackup, online, backed by the cluster's configured object store. Monitor progress:

kubectl get backup backup-sample -w
kubectl describe backup backup-sample

Once status.phase reaches completed, the backup is ready for restoration.

8. Clean Up​

kubectl delete cluster cluster-sample

Deleting a Backup resource does not remove data from the object store. Use your object store's lifecycle policies or delete the objects manually.

Next Steps​