Skip to main content

Quickstart

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

Prerequisites

ToolPurpose
goBuild the operator binary
dockerBuild and load container images
kubectlInteract with the Kubernetes cluster
kindLocal Kubernetes cluster
makeRun build targets
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. Build and Load Images

Build the operator image from source:

make docker-build IMG=cnmsql-controller:dev

Pull the pre-built instance image. Instance images are published from the containers repository:

docker pull ghcr.io/cnmsql/cnmsql-instance:8.4

Load both images into your Kind cluster:

kind load docker-image cnmsql-controller:dev --name cnmsql-test-e2e
kind load docker-image ghcr.io/cnmsql/cnmsql-instance:8.4 --name cnmsql-test-e2e

2. Deploy the Operator

Install the CRDs and deploy the controller manager:

make install
make deploy IMG=cnmsql-controller:dev

Verify the controller is running:

kubectl get pods -n cnmsql-system

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

3. Install the CLI Plugin

From a release (no source checkout needed):

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).

From the repo (development):

make install-plugin

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 — 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 you're certain 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