MySQL
Schedule below will do the following.
- Backup MySQL and compress it with GZIP
- Drop database before the restoration
- Restore the database
- Print info and warnings to Pod main log streams, so you can debug it if you want
- Will keep last 7 backups
- Limit backup and restoration to 5 minutes
apiVersion: backup-operator.io/v1
kind: BackupSchedule
metadata:
name: backup-mysql
spec: # (1)
schedule: "0 0 * * *"
concurrencyPolicy: Replace
successfulRunsHistoryLimit: 7
failedRunsHistoryLimit: 1
template:
spec:
retainPolicy: Retain # (2)
storage:
name: minio
path: "/${CLUSTER}/mysql-backend-{{ now | date \"20060102-150405\" }}.sql.gz" # (3)
compression:
algorithm: gzip
level: 5
backup:
deadlineSeconds: 300
container: mysql
command: ["/bin/bash", "-o", "pipefail", "-ec"]
args: # (4)
- |-
backup() {
mysqldump \
--host "${HOSTNAME}" \
--port "${PORT}" \
--user "${USERNAME}" \
--password="${PASSWORD}" \
--no-create-db \
--all-tablespaces \
--add-drop-database \
--quote-names \
--routines \
--triggers \
--events \
--set-gtid-purged=OFF \
--max_allowed_packet=512M \
"${DATABASE}"
}
main() {
echo "info: starting" 1>/proc/1/fd/1
backup
echo "info: finished" 1>/proc/1/fd/1
sleep 5
}
main 2>/proc/1/fd/2
restore:
deadlineSeconds: 300
container: mysql
command: ["/bin/bash", "-o", "pipefail", "-ec"]
args: # (5)
- |-
drop() {
echo "
DROP DATABASE IF EXISTS ${DATABASE};
CREATE DATABASE ${DATABASE};
" | mysql \
--host "${HOSTNAME}" --port "${PORT}" \
--user "${USERNAME}" --password="${PASSWORD}" \
--no-auto-rehash
echo "info: drop is completed"
}
restore() {
mysql \
--host "${HOSTNAME}" --port "${PORT}" \
--user "${USERNAME}" --password="${PASSWORD}" \
--no-auto-rehash "${DATABASE}"
echo "info: restore is completed"
}
main() {
echo "info: starting"
drop
restore
echo "info: finished"
}
main 1>/proc/1/fd/1 2>/proc/1/fd/2 || (cat >dev/null; exit 1)
template:
spec:
restartPolicy: Never
containers:
- name: mysql
image: docker.io/mysql:8.4.0
imagePullPolicy: IfNotPresent
command: ["sleep", "-c"] # (6)
args: ["while sleep 1; do true; done"]
securityContext:
capabilities:
drop: [ALL]
privileged: false
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
resources:
limits:
memory: 2Gi
requests:
cpu: 100m
memory: 200Mi
env:
- name: HOSTNAME
value: mysql.default.svc.cluster.local
- name: PORT
value: "3306"
- name: DATABASE
value: backend
- name: USERNAME
value: backend
- name: PASSWORD
valueFrom:
secretKeyRef:
key: mysql-password
name: mysql-backend-passwords # (7)
- Same fields as for a vanilla CronJob
- Impact on retain or removal of backup from storage on BackupRun deletion
- Templated with Go Template and Sprig functions
- While stdout of the command is considered as a backup data, we use
/proc/1/fd/*
to redirect some info and errors to container main logs streams so you can debug it - There is a
cat >/dev/null
at the end of main function call. It is required in case if restore command fails and noone consumes STDIN. Kubernetes fails to finish exec command and we have to trash that data somehow. - We do not use a simple
command: [sleep, 1d]
, because killing the Pod after backup is done is faster, you have a loop with small sleeps - Do not forget to create the respective secret with MySQL credentials