Skip to content

Commit

Permalink
Added MySQL Galera Cluster (#1103)
Browse files Browse the repository at this point in the history
  • Loading branch information
abychko authored Feb 4, 2025
1 parent 4c1d65a commit c38d9d6
Show file tree
Hide file tree
Showing 24 changed files with 861 additions and 0 deletions.
Binary file added assets/codership/mysql-galera-0.3.0.tgz
Binary file not shown.
Binary file added assets/icons/mysql-galera.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions charts/codership/mysql-galera/0.3.0/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
annotations:
catalog.cattle.io/certified: partner
catalog.cattle.io/display-name: MySQL Galera Cluster
catalog.cattle.io/kube-version: '>=1.21-0'
catalog.cattle.io/release-name: ""
apiVersion: v2
appVersion: 8.0.40
description: A Helm chart for deploying MySQL/Galera cluster in Kubernetes
home: https://galeracluster.com
icon: file://assets/icons/mysql-galera.png
keywords:
- mysql
- galera
- cluster
kubeVersion: '>=1.21-0'
name: mysql-galera
sources:
- https://github.com/codership/containers
type: application
version: 0.3.0
92 changes: 92 additions & 0 deletions charts/codership/mysql-galera/0.3.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# HELM charts for MySQL/Galera cluster

## Common usage:
```
helm install [set values] <cluster name> .
```
see values.yaml for supported/required oprtions.

### Setting values for Docker image
On `helm install` you will need to set some environmet variables for the image, e.g.
```
--set env.MYSQL_ROOT_PASSWORD=<value> --set env.MYSQL_USER=<value> --set env.MYSQL_PASSWORD=<value>
```
For all variables see https://hub.docker.com/_/mysql. Not all of them are supported, e.g. datadir mount point is fixed.

These variables will be used to initialize the database if not yet initialized. Otherwise MYSQL_USER and MYSQL_PASSWORD will be used for the readiness probe so they must be specified on all chart installs. MYSQL_ROOT_PASSWORD is used only once for database initialization.

### Requesting kubernetes resources for pods
The usual kubernetes stuff:
```
--set resorces.requests.memory=4Gi --set resources.requests.storage=16Gi --set resources.requests.cpu=4
```

### Connecting to cluster
By default MySQL client service is open through load balancer on port 30006. It can be changed (if supported by k8s cluster) by:
```
--set service.port=NNNN
```
*NOTE:* in Scaleway Kubernetes cluster load balancer opens port 3306 regardless of the `service.port` setting.

### Graceful cluster shutdown
Graceful cluster shutdown requires scaling the cluster to one node before `helm uninstall`:
```
helm upgrade --reuse-values --set replicas=1 <cluster name> .
mysql <options> -e "shutdown;"
helm uninistall <cluster name>
```
This will leave the last pod in the stateful set (0) safe to automatically bootstrap the cluster from.

### Force bootstrap from a particular pod
In case the cluster need to be recovered from scratch (e.g. `helm uninstall` was called), it can be forced to bootstrap from a particular pod. To find which pod to use the cluster can be started in "recover-only" mode:
```
$ helm install --set env.WSREP_RECOVER_ONLY <cluster name> .
```
Then
```
$ kubectl logs <pod name> | grep 'Recovered position'
```
shall print diagnostic output showing pod position in replication history. Most updated pod should be chosen as a bootstrap node.
`find_most_updated.sh` script can help to identify the right pod. It will look like:
```
$ ./find_most_updated.sh <cluster name>
Candidates (NB: if there is more than one, choose carefully):
UUID count: 3 bf6bd3e5-020e-11ef-ae7a-ceb1e82e2567:425 <cluster name>-mysql-galera-2
```
Where bf6bd3e5-020e-11ef-ae7a-ceb1e82e2567 is the cluster/dataset UUID and 425 is the sequence number of the last data change.

After the most updated pod has been identified, check its `grastate.dat` file:
```
$ kubectl exec <cluster name>-mysql-galera-2 -- cat /var/lib/mysql/grastate.dat
# GALERA saved state
version: 2.1
uuid: bf6bd3e5-020e-11ef-ae7a-ceb1e82e2567
seqno: -1
safe_to_bootstrap: 0
```
Then run the followwing command:
```
$ kubectl exec <cluster-name>-mysql-galera-2 -- sed -i "s/safe_to_bootstrap:[[:blank:]]*[0-9]/safe_to_bootstrap: 1/" /var/lib/mysql/grastate.dat
```
And if the `uuid:` field above is `00000000-0000-0000-0000-000000000000` run the follwowing:
```
$ kubectl exec <cluster-name>-mysql-galera-2 -- sed -i "s/uuid:[[:blank:]]*00000000-0000-0000-0000-000000000000/uuid: <UUID from the output above>/" /var/lib/mysql/grastate.dat
```
Verify that resulting `grastate.dat` makes sense:
```
$ kubectl exec <cluster name>-mysql-galera-2 -- cat /var/lib/mysql/grastate.dat
...
```
Now uninstall the cluster:
```
$ helm uninstall <cluster name>
```
Wait for the pods to be deleted and install with the production options:
```
$ helm install --set env.MYSQL_USER=... --set env.MYSQL_PASSWORD=... <cluster name> .
```
The cluster should be up and running after nodes synchronization. The progress can be monitored through
```
$ kubectl logs <pod name>
```
Once the nodes reach `SYNCED` state they will be available through the Kubernetes load balancer.
14 changes: 14 additions & 0 deletions charts/codership/mysql-galera/0.3.0/VARIABLES
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#######################################
# TEST VARIABLES. NOT FOR PRODUCTION! #
#######################################
#
REPOSITORY="codership/mysql-galera"
TAG="8.0.40"
#
DBUSER="admin"
USER_PW="LohP4upho0oephah"
MYSQL_ROOT_PASSWORD="Oohiechohr8xooTh"
#
DOCKER_USER="${DOCKERHUBCREDS_USR:-}"
DOCKER_PASSWORD="${DOCKERHUBCREDS_PSW:-}"
#
20 changes: 20 additions & 0 deletions charts/codership/mysql-galera/0.3.0/app-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# MySQL Galera from Codership

This is a Helm chart for MySQL Galera from Codership.

Galera Cluster for MySQL is a true Multi-Master Cluster based on synchronous replication. It’s an easy-to-use, high-availability solution, which provides high system up-time, no data loss and scalability for future growth.

For documentation, Knowledge Base and Support please visit https://galeracluster.com/

* Galera Cluster for MySQL Helm Chart: https://galeracluster.com/2024/10/galera-cluster-for-mysql-helm-chart-for-kubernetes/
* MySQL Galera Cluster documentation: https://galeracluster.com/library/documentation/index.html

## Installation
* Plan your cluster capacity. Default is 3 nodes, each with 1 vCPU and 4GB of RAM, the storage is 2GB. It is minimal requirement for Galera to work.
* Consider separate namespace for the MySQL Galera cluster, like `mysql-galera`.
* Install the MySQL Galera chart with desired capacity.

## Configuration
Sometimes you may want to configure the MySQL Galera cluster with custom values. You can do this by setting the customConfig multiline in values.yaml.

See the values.yaml file for the full list of configurable parameters.
53 changes: 53 additions & 0 deletions charts/codership/mysql-galera/0.3.0/find_most_updated.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
if [ -z "$1" ]
then
echo "Usage:"
echo " $0 <NAME>"
exit 1
fi

set -eu

declare -A seqno_map # highest seqno for an UUID
declare -A count_map # number of nodes with that UUID
declare -A pod_map # pod candidate for UUID

get_gtid()
{
kubectl logs $1 2>&1 |\
grep "WSREP: Recovered position" |\
cut -d ' ' -f4 |\
cut -d '/' -f1
}

get_pods()
{
kubectl get pods |\
grep $1 |\
cut -d ' ' -f1
}

list_most_updated()
{
for pod in $(get_pods $1)
do
gtid=$(get_gtid $pod)
uuid=${gtid%%:*}; seqno=${gtid##*:}

count_map[$uuid]=$(( ${count_map[$uuid]:-0} + 1 ))

has_seqno=${seqno_map[$uuid]:-"-1"}
if [ $has_seqno -lt $seqno ]
then
seqno_map[$uuid]=$seqno
pod_map[$uuid]="$gtid $pod"
fi
done

echo "Candidates (NB: if there is more than one, choose carefully):"
(for entry in "${!pod_map[@]}"
do
echo "UUID count: ${count_map[$entry]} ${pod_map[$entry]}"
done) | sort -rn # sort in order of max count
}

list_most_updated $1
57 changes: 57 additions & 0 deletions charts/codership/mysql-galera/0.3.0/questions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
questions:

- variable: mysql.rootpw
default: ""
required: true
type: password
label: MySQL root Password
group: "Global Cluster Settings"

- variable: mysql.user.name
default: ""
required: true
type: string
label: MySQL User Name
group: "Global Cluster Settings"

- variable: mysql.user.passwd
default: ""
required: true
type: password
label: MySQL Password for User
group: "Global Cluster Settings"

- variable: customConfig
default: "[mysqld]"
required: true
type: multiline
label: Additional custom config for MySQL
group: "Global Cluster Settings"

- variable: replicas
default: 3
required: true
type: int
label: The number of replicas
group: "Global Cluster Settings"

- variable: resources.requests.cpu
default: 1
required: true
type: int
label: The number of CPU
group: "Global Cluster Settings"

- variable: resources.requests.memory
default: "4Gi"
required: true
type: string
label: The memory amount for instance
group: "Global Cluster Settings"

- variable: resources.requests.storage
default: "2Gi"
required: true
type: string
label: The storage space for instance
group: "Global Cluster Settings"
62 changes: 62 additions & 0 deletions charts/codership/mysql-galera/0.3.0/set_values.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
#
set -x
#
cd $(dirname $0)
#

if ! test -f values.tmpl; then
echo "No values template found, exiting"
exit 1
fi

if [[ -f VARIABLES ]]; then
. VARIABLES
fi

while [[ $# -gt 0 ]]; do
case $1 in
--repo )
REPOSITORY=$2
shift 2
;;
--tag)
TAG=$2
shift 2
;;
--rootpw)
MYSQL_ROOT_PASSWORD=$2
shift 2
;;
--dbuser)
DBUSER=$2
shift 2
;;
--userpw)
USER_PW=$2
shift 2
;;
--docker-user)
DOCKER_USER=$2
shift 2
;;
--docker-pw)
DOCKER_PASSWORD=$2
shift 2
;;
*)
echo "Error! Unknown parameter: $1"
exit 1
;;
esac
done

sed \
-e "s:@@REPOSITORY@@:${REPOSITORY}:g" \
-e "s:@@IMAGE_TAG@@:${TAG}:g" \
-e "s:@@MYSQL_ROOT_PASSWORD@@:${MYSQL_ROOT_PASSWORD}:g" \
-e "s:@@MYSQL_USER@@:${DBUSER}:g" \
-e "s:@@MYSQL_USER_PASSWORD@@:${USER_PW}:g" \
-e "s:@@USERNAME@@:${DOCKER_USER}:g" \
-e "s:@@PASSWORD@@:${DOCKER_PASSWORD}:g" \
values.tmpl > values.yaml
1 change: 1 addition & 0 deletions charts/codership/mysql-galera/0.3.0/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
Loading

0 comments on commit c38d9d6

Please sign in to comment.