Backup MySQL Databases in Kubernetes

CronJob Agent Container

FROM alpine:3.10

# Update
RUN apk --update add --no-cache bash nodejs-current yarn curl busybox-extras vim rsync git mysql-client openssh-client
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl && chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl

# Scripts
RUN mkdir /srv/jobs
COPY jobs/* /srv/jobs/

# Backup Folder
RUN mkdir /var/backup
RUN mkdir /var/backup/mysql

Backup Script

#!/bin/bash

############# SET VARIABLES #############

# Env Variables
BACKUPSERVER="8.8.8.8" # Backup Server Ip
BACKUPDIR=/var/backup/mysql
BACKUPREMOTEDIR="/mnt/backup/kubernetes/"
HOST="mariadb.default"
NOW="$(date +"%Y-%m-%d")"
STARTTIME=$(date +"%s")
USER=mysqlUser
PASS=mysqlPassword


############# BUILD ENVIROMENT #############
# Check if temp Backup Directory is empty
mkdir $BACKUPDIR

if [ "$(ls -A $BACKUPDIR)" ]; then
echo "Take action $BACKUPDIR is not Empty"
rm -f $BACKUPDIR/*.gz
rm -f $BACKUPDIR/*.mysql
else
echo "$BACKUPDIR is Empty"
fi

############# BACKUP SQL DATABASES #############
for DB in $(mysql -u$USER -p$PASS -h $HOST -e 'show databases' -s --skip-column-names); do
mysqldump -u$USER -p$PASS -h $HOST --lock-tables=false $DB > "$BACKUPDIR/$DB.sql";
done

############# ZIP BACKUP #############
cd $BACKUPDIR
tar -zcvf backup-${NOW}.tar.gz *.sql

############# MOVE BACKUP TO REMOTE #############
rsync -avz $BACKUPDIR/backup-${NOW}.tar.gz root@$BACKUPSERVER:$BACKUPREMOTEDIR

# done

Kubernetes CronJob Deployment

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: backup-mariadb
namespace: default
spec:
schedule: "0 8 * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: cronjob-agent
image: xxx/cronjob-agent
command: ["bash", "/srv/jobs/backup-mariadb.sh"]
volumeMounts:
- mountPath: /root/.ssh/id_rsa.pub
name: cronjob-default-config
subPath: id_rsa.pub
- mountPath: /root/.ssh/id_rsa
name: cronjob-default-config
subPath: id_rsa
readOnly: true
- mountPath: /root/.ssh/config
name: cronjob-default-config
subPath: config
volumes:
- name: cronjob-default-config
configMap:
name: cronjob-default-config
defaultMode: 256
restartPolicy: Never

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store