Archive of

Backup MySQL database and upload them to AWS S3

Written by Georgi Stefkoff

Introduction

When you have a database server (production or not), you may want to back up the database regular, because everything can happen - disk failure, hardware failure, etc.

In this blog post, I will how you how to back up all databases, compress them and upload them to AWS S3 object storage.

Requirements

  • This tutorial will be valid for Ubuntu 22.04.
  • You need to have a running MySQL server
  • You need to have mysqldump script installed on the machine that you will making the back-up. It could be installed

by sudo apt-get install mysql-client

  • You also need to have root access to

all the database that needs to be dumped.

  • Make sure that you will have enough free disk space, because depending on the size of the file, you may run out of

disk space when the dump is generated

  • You need to have an AWS account and credentials (AWS KEY and AWS SECRET KEY)

Dump all databases to an .sql file

In order to dump all the database, run the following command:

mysqldump -u USER -p --all-databases --skip-add-locks > alldb.sql // Replace USER with your user that has access to all the database

  • --skip-lock-tables will not lock the tables when a query is executed

When running this command, you will be prompted to enter the password for your user. If you wish to include the password at the command you can do the following:

mysqldump -u USER -pPASSWRD --all-databases --skip-add-locks > alldb.sql

You can see that the password (PASSWORD) is appended immediately after -p flag. Note: if the password contains special characters, you may surround the password in ' like this:

mysqldump -u USER -p'PASSWORD' --all-databases --skip-add-locks > alldb.sql

Exposing the password to the command line is not a good practice, because it can be seen by anyone

After some amount of time, your .sql file will be generated and will contain the SQL of all the databases from the server.

Compressing the .sql file

When we dump all the databases, there were dumped in a text format, which takes a lot of space. Now, we will modify the above command in order to compress the .sql file and reduce the size of the dump file.

We are going to use GZIP command. Make sure that you have installed gzip in your Ubuntu installations:

sudo apt update
sudo apt install gzip

Now, execute the following command:

mysqldump -u USER -p'PASSWORD' --all-databases --skip-add-locks | gzip > backup.$(date +%F.%H%M%S).sql.gz

Here we are using the same command, but instead to redirect the output from the dump command, we are piping the output to gzip and redirecting the output from the compression to a .sql.gz file. Also, for the name of the compressed file, we are specifying the current date

Executing this command will take more time from the last time, but at least the end result will save some space.

If you list the content of the directory where the back file is, you will see the file is actually there:

stefkoff@stefkoff-mysql-server:~$ ls -la | grep backup.
-rw-rw-r--  1 stefkoff stefkoff  8860655596 May  9 12:30 backup.2024-05-09.115631.sql.gz
stefkoff@stefkoff-mysql-server:~$ 

Creating the bucket

Now, when we have the file, it is time to create a bucket inside AWS. First login to your console, navigate the S3, and create a new bucket. Enter the name for you bucket and the rest of the options as there are.

Upload the dump to S3

We are going to use the s3cmd package in order to upload the files to the S3 bucket. If you do not have the package installed on your system yet, you can install it by:

sudo apt update
sudo apt install s3cmd

After s3cmd is installed, you need to configure it, in order to save your credentials to a local file for further usage. You have to run the following command:

s3cmd --configure

First af all, you will be prompted to your Access Key. Then the same for the Secret Key. Next is the default region. It is good to specify the default region of you AWS S3 bucket. Then confirm the endpoint s3.amazonaws.com (or just press enter). Confirm all the rest of the setting and hit two Yes on the last questions. At the end s3cmd will generate a config if file as follows /home/$USER/.s3cfg. Now we can use s3cmd to upload files to the bucket.

In order to upload the backup file, you can execute the following command:

s3cmd put backup.2024-05-09.115631.sql.gz s3://BUCKET_NAME // replace BUCKET_NAME with your S3 actual bucket name

After few minutes (depending on the file size) you file will be uploaded to AWS S3 bucket with the same name as it is.

Putting all together

We have managed to run all of this, but we have to do it at once and probably by some cron task, so it can be done automatically at certain time of the day. The thinks that we will do in a single shell file are the following:

  • Create the compressed back-up file
  • Upload the file to AWS S3

Here is how you can do it in one shell-script:

#!/bin/bash

# fail on every error
set -e

# save the current date to be used for the filenames later
CURRENT_DATE=$(date +%F.%H%M%S)
# variable for the backup filename
BACKUP_FILENAME="backup.$CURRENT_DATE.sql.gz"
# mysql user
MYSQL_USER=root
# mysql password
MYSQL_PASSWORD=password
#extra options that will be passed to mysql dump command
MYSQL_EXTRA_PARAMS="--all-databases --skip-add-locks"
# mysqldump absolute location
MYSQLDUMP_COMMAND=$(which mysqldump)
S3_BUCKET_NAME="stefkoff-db-dumps"

# make sure that mysqldump is installed
if [ -z "$MYSQLDUMP_COMMAND" ]; then
  echo "mysqldump command not found. Exiting"
  exit 1
fi

# s3cmd absolute path
S3CMD_COMMAND=$(which s3cmd)
if [ -z "$S3CMD_COMMAND" ]; then
  echo "s3cmd command not found. Exiting"
  exit 1
fi

#gzip absolute path
GZIP_COMMAND=$(which gzip)

# make sure gip is installed
if [ -z "$GZIP_COMMAND" ]; then
  echo "gzip command not found. Exiting"
  exit 1
fi

# dump all database
/bin/bash -c "$MYSQLDUMP_COMMAND -u $MYSQL_USER -p'$MYSQL_PASSWORD' $MYSQL_EXTRA_PARAMS | $GZIP_COMMAND > $BACKUP_FILENAME"

# check if the backup file exists
if [ ! -f "$BACKUP_FILENAME" ]; then
  echo "Something went wrong and cannot upload the file to S3. Exiting"
  exit 1
fi

/bin/bash -c "$S3CMD_COMMAND put $BACKUP_FILENAME s3://$S3_BUCKET_NAME"

# remove the backup file, one it is successfully uploaded to the bucket
rm "$BACKUP_FILENAME"

# (OPTIONAL) remove previously uploaded files
/bin/bash -c "$S3CMD_COMMAND ls s3://$S3_BUCKET_NAME | awk '{print \$4}' | grep -v s3://$S3_BUCKET_NAME/$BACKUP_FILENAME | xargs -I {} $S3CMD_COMMAND del {}"

NOTE the last command, it will delete the previous uploaded backups from the bucket

Save the script as backup-db.sh somewhere and allow the users to execute the file: chmod +x backup-db.sh

If you execute the file by ./backup-db.sh all above the operations should be done in one time

Setup cron task

Now we want to execute the script at certain recurring time, so we want to be sure that we will have a "fresh" backup, before the point of failure. You can add the following cron record:

0 0 * * 6 /bin/bash -c "cd /home/USER && ./backup-db.sh" // replace USER with your user

In my case, I will execute the command once a week (sunday at 00:00). It is good to have a daily back, and you can replace it by:

0 0 * * * /bin/bash -c "cd /home/USER && ./backup-db.sh"

Conclusion

Doing a regular backups, especially for a DB servers is a MUST and everyone have to do it, not only on production environments, but also for a local usage, because when we lost the data, recovering will take a huge amount of time, which can be critical when working.