Deploy local Minikube cluster
minikube start --addons volumesnapshots,csi-hostpath-driver --apiserver-port=6443 --container-runtime=containerd -p mc-demo --kubernetes-version=1.21.2
add kanister helm repository
helm repo add kanister https://charts.kanister.io/
create kanister namespace
kubectl create namespace kanister
deploy kanister using helm
helm install myrelease --namespace kanister kanister/kanister-operator --set image.tag=0.71.0
Once we have kanister deployed we should now show the CustomResourceDefinitions, this will show actionsets, blueprints, profiles.
kubectl get customresourcedefinitions.apiextensions.k8s.io | grep "kanister"
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl port-forward svc/argocd-server -n argocd 8443:443
Username is admin and password can be obtained with this command. open a web browser localhost
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
Enable load balancer in minikube
# run this command in another terminal
minikube tunnel --profile=mc-demo
Install minio
helm repo add minio https://charts.min.io/
kubectl create ns minio
helm install kasten-minio minio/minio --namespace=minio --version 8.0.10 \
--set persistence.size=5Gi
# feed ACCESS_KEY variable and SECRET_KEY and display them
AWS_ACCESS_KEY_ID=$(kubectl -n minio get secret kasten-minio -o jsonpath="{.data.accesskey}" | base64 --decode)
echo $AWS_ACCESS_KEY_ID
AWS_SECRET_KEY=$(kubectl -n minio get secret kasten-minio -o jsonpath="{.data.secretkey}" | base64 --decode)
echo $AWS_SECRET_KEY
# Expose minio in a load balancer
kubectl expose svc/kasten-minio --name=minio-lb -n minio --type=LoadBalancer
EXTERNAL_IP=$(kubectl get svc -n minio minio-lb -o jsonpath='{.spec.clusterIP}')
echo "http://$EXTERNAL_IP:9000/"
open a web browser to this addres and use $ACCESS_KEY
and $SECRET_KEY
to access th minio GUI.
Create a kanister
bucket.
This will give us some where to store our backups, this will be done using the KanCTL CLI tool
kanctl create profile \
--namespace kanister \
--bucket kanister \
--skip-SSL-verification \
--endpoint http://$EXTERNAL_IP:9000/ \
s3compliant \
--access-key $AWS_ACCESS_KEY_ID \
--secret-key $AWS_SECRET_KEY
confirm you now have a profile created
kubectl get profile -n kanister
Kanister uses Blueprints to define these database-specific workflows and open-source Blueprints are available for several popular applications. It's also simple to customize existing Blueprints or add new ones.
kubectl create -f https://raw.githubusercontent.com/kanisterio/kanister/master/examples/stable/mysql/mysql-blueprint.yaml -n kanister
this blueprint is created in the Kanister namespace check with environment
kubectl get blueprint -n kanister
Create a mysql namespace.
kubectl create ns mysql
Create in argo a new project mysql-app :
- project name : mysql
- use the default project
- git repo : your git repo (eg: https://github.com/michaelcourcy/argocd-kanister.git)
- path : base
- namespace: mysql
- choose the default or availables values for the rest
Once deployed, check the service account kanister-presync can create an action or read a profile set in the kanister namespace.
kubectl auth can-i create actionset --as=system:serviceaccount:mysql:kanister-presync -n kanister
kubectl auth can-i create profile --as=system:serviceaccount:mysql:kanister-presync -n kanister
The answer should be yes for both.
kubectl exec -ti mysql-0 -n mysql -- bash
mysql --user=root --password=ultrasecurepassword
CREATE DATABASE test;
USE test;
CREATE TABLE pets (name VARCHAR(20), owner VARCHAR(20), species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
INSERT INTO pets VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);
SELECT * FROM pets;
+----------+-------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+-------+
| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
+----------+-------+---------+------+------------+-------+
1 row in set (0.00 sec)
exit
exit
By resyncing your project you're going to trigger the creation of a backup. check on minio.
Let's imagine you create a mysqlclient app which is going to drop your database in your code, that's a mistake. But mistake happen.
Create this pod base/mysql-client.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: mysql-client
name: mysql-client
spec:
containers:
- image: mysql:8.0.26
name: mysql-client
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: mysql-root-password
name: mysql
command:
- sh
- -o
- errexit
- -c
- |
mysql -h mysql --user=root --password=$MYSQL_ROOT_PASSWORD -e "DROP DATABASE test;"
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
You commit, push and sync with argo and check your data
kubectl exec -ti mysql-0 -n mysql -- bash
mysql --user=root --password=ultrasecurepassword
SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
Horror !!! The sync has deleted the database but fortunaletly kanister protects your database in the execution of the presync.
The sync above represents a simple change in code that could affect our data, at this stage the bad mysql-client.yaml
should be removed or configured correctly before continuing with the restore process.
Before we restore we need to choose the appropriate restore point.
kubectl get actionset -n kanister
NAME AGE
mysqlapp-backup-tue-jan-25-17-46-46-utc-2022 10m
mysqlapp-backup-tue-jan-25-17-50-45-utc-2022 6m56s
When we have the list we can choose the correct actionset to restore from.
kanctl --namespace kanister create actionset --action restore --from "mysqlapp-backup-tue-jan-25-17-50-45-utc-2022"
actionset restore-mysqlapp-backup-tue-jan-25-17-50-45-utc-2022-hsjvv created
Now we can see in detail what is happening as part of the restore process.
kubectl --namespace kanister describe actionset restore-mysqlapp-backup-tue-jan-25-17-50-45-utc-2022-hsjvv
We can then go and check on our data and database again and make sure that our test database is restored along with our data.
kubectl exec -ti mysql-0 -n mysql -- bash
mysql --user=root --password=ultrasecurepassword
CREATE DATABASE test;
USE test;
SELECT * FROM pets;
+----------+-------+---------+------+------------+-------+
| name | owner | species | sex | birth | death |
+----------+-------+---------+------+------------+-------+
| Puffball | Diane | hamster | f | 1999-03-30 | NULL |
+----------+-------+---------+------+------------+-------+
1 row in set (0.00 sec)
SHOW DATABASES;
exit
exit