As mentioned in my previous post, I would post code for a script which will backup an LXD container as a snapshot, then transfer to an FTP server. The script to do this is below, it has been tested on Ubuntu 16.04 LTS.
The steps listed below can be found in my LXC Container backup script collection on GitHub here: https://github.com/ryanfitton/lxc-mysql-tar-backup-script-collection
Ensure you have these packages installed:
netcat
exim4
lftp
curl
Save this to a file on your LXD host such as 'backup-container-snapshot.sh', now change permissions so this file is executable:
sudo chmod +x backup-container-snapshot.sh
Now edit the file, and ensure these variables match your specs:
GLOBAL_BACKUP_TEMP_SAVEPATH
GLOBAL_REMOTE_FTP_LOCATION
GLOBAL_EMAIL_TO
FTP_SERVER
FTP_USERNAME
FTP_PASSWORD
FTP_PORT
- You may also need to configure passive mode in
FTP_ARGUMENTS
andCURL_FTP_ARGUMENTS
To run this script, you must pass your LXD container name as an argument, for example:
sudo ./backup-container-snapshot.sh 'container-name-here'
#!/bin/bash
## Usage: backup-container-snapshot.sh
##
## Make the script executable:
## chmod +x backup-container-snapshot.sh
##
## Pass arguments to the script:
## 1: Container Name - Used to target the correct container and create a folder with this name
##
## Run using:
## sudo ./backup-container-snapshot.sh 'container-name-here'
##
## Notes: '/' = Server root folder. '~/' = User's home folder.
##
## Required software libaries:
## 'netcat' Used for checking if a connection can be made to the FTP server
## 'exim4' Used for sending email using the 'mail' command
## 'lftp' Used for sending files using via the 'lftp' command. Allows paths to be created at multi-levels
## 'curl' Used for check if the file exists on the FTP server via the 'curl' command
# Temporary backup location on the server. File will be kept here until FTP transfer is completed.
GLOBAL_BACKUP_TEMP_SAVEPATH='/tmp'
# The backup location on the remote FTP server which the script will use. Each script will create it's own folder within this location.
GLOBAL_REMOTE_FTP_LOCATION='/backup'
# Email address for notification of backups status
GLOBAL_EMAIL_TO='[email protected]'
# FTP remote server connection details
FTP_SERVER=''
FTP_USERNAME=''
FTP_PASSWORD=''
FTP_PORT=21
FTP_ARGUMENTS='-np' # Notes: '-n' = Do not attempt to autologin. '-p' = Enable passive mode.
CURL_FTP_ARGUMENTS='--ftp-pasv' # Curl is used to verify the FTP upload. Notes: '' = Enable passive mode.
# Backup options
NAME="$1" # The Container Name - Used to categorize backups on the FTP server
# Create the save path
FTP_SAVEPATH="$GLOBAL_REMOTE_FTP_LOCATION/$NAME/snapshots" # The path for where the snapshot file should be uploaded on the FTP server.
# -------------------- Nothing to change after this point --------------------
# Clear terminal window
clear
# Welcome/Start message
echo "****************************************"
echo "LXD Container Backup script"
echo "Created for Ubuntu operating systems"
echo "Author: Ryan Fitton (ryanfitton.co.uk)"
echo "Version 3.0.0"
echo "****************************************"
printf "\n"
echo "Starting in 5 seconds."
echo "..."
printf "\n"
sleep 5s # Wait 5 seconds
# Check if the required arguments are not empty
if [ "$1" != '' ];
# If none of these arguments are empty, the script can proceed
then
# Check to see if the 'netcat' program is installed
# Used for checking if a connection can be made to the FTP server
PACKAGE='netcat'
if dpkg -s $PACKAGE 2>/dev/null >/dev/null;
# If 'netcat' is installed
then
# Checking to see if the Mail package is installed on your system
# Used for sending email confirmations of the backup process
PACKAGE='exim4' # Sometimes mail package is 'exim4mailtuils'
echo "Checking to see if '$PACKAGE' is installed on your system."
printf "\n"
if dpkg -s $PACKAGE 2>/dev/null >/dev/null
# If success
then
echo "The '$PACKAGE' package is already installed on your system. You will recieve email updates for this backup."
echo "..."
printf "\n"
# Filename variables setup
NOW=$(date +"%Y-%m-%d-%H%M") # Timestamp
# Filename with no format (container_name.snapshot-backup.timestamp)
FILENAME_NOFORMAT="$NAME-snapshot-backup-$NAME-$NOW"
# Full Filename with format (container_name.snapshot-backup.timestamp.format)
FILENAME="$FILENAME_NOFORMAT.tar.gz"
echo "The snapshot backup filename will be: $FILENAME"
echo "Stored temporarily within: $GLOBAL_BACKUP_TEMP_SAVEPATH"
echo "Uploaded to the FTP server at: $FTP_SAVEPATH"
echo "Full temporary savepath: $GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME"
echo "Full FTP savepath: $FTP_SAVEPATH/$FILENAME"
printf "\n"
sleep 5s # Wait 5 seconds
# Start snapshot backup process
echo "Starting snapshot backup process..."
echo "Please be patient, this can take a while"
# Create a snapshot of the container, with the snapshot name being 'backup'
echo "Creating 'backup' snapshot of '$NAME'."
lxc snapshot $NAME backup
# Publish this snapshot temporarily with an alias name of 'lxd-image-backup-$NAME'
echo "Publishing 'backup' snapshot temporarily with an alias name of 'lxd-image-backup-$NAME'."
lxc publish $NAME/backup --alias lxd-image-backup-$NAME
# Export the 'lxd-image-backup-$NAME' image, this will save the export in a 'tar.gz' format to the specified temporary location
echo "Exporting 'lxd-image-backup-$NAME' image in this location: '$GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME'."
#lxc image export lxd-image-backup-$NAME .
lxc image export lxd-image-backup-$NAME $GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME_NOFORMAT
# Now delete the 'lxd-image-backup-$NAME' image
echo "Deleting 'lxd-image-backup-$NAME' image from server."
lxc image delete lxd-image-backup-$NAME
# And delete the temporary 'backup' snapshot
echo "Deleting temporary 'backup' snapshot from server."
lxc delete local:$NAME/backup
echo "Snapshot backup process has finished."
echo "..."
printf "\n"
# Verify snapshot file has been created
echo "Verifying $FILENAME file has been created."
printf "\n"
if [ -f $GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME ]
# If success
then
echo "File exists on the local server."
printf "\n"
# Check to see if the 'lftp' program is installed
# Used for sending files using via the 'ftp' command
PACKAGE='lftp'
if dpkg -s $PACKAGE 2>/dev/null >/dev/null;
# If success
then
# Check if a connection can be made to the FTP Server address and port using 'netcat'
if nc -z -v -w5 $FTP_SERVER $FTP_PORT;
# If success
then
# Start FTP transfer. Syntax: http://manpages.ubuntu.com/manpages/zesty/man1/tnftp.1.html
echo "FTP transfer process will begin in in 30 seconds."
echo "Press 'ctrl + c' now to cancel and keep the local backup only, otherwise wait for the FTP transfer process to begin."
echo "..."
printf "\n"
sleep 30s # Wait 30 seconds
# Start FTP transfer process. Syntax: https://linux.die.net/man/1/lftp
echo "Starting FTP transfer process."
# Indents are removed as they cause issues with the 'END_SCRIPT' tag
# 1. Change directory on the local server
# 2. Create directory on the FTP server
# 3. Change to the newly created directory
# 4. Upload file from local server to FTP server
lftp ftp://$FTP_USERNAME:$FTP_PASSWORD@$FTP_SERVER:$FTP_PORT <<END_SCRIPT
lcd "$GLOBAL_BACKUP_TEMP_SAVEPATH"
mkdir -p "$FTP_SAVEPATH"
cd "$FTP_SAVEPATH"
put "$FILENAME"
END_SCRIPT
echo "FTP transfer process has finished."
printf "\n"
# Check to see if the 'curl' program is installed
# Used for check if the file exists on the FTP server via the 'curl' command
PACKAGE='curl'
if dpkg -s $PACKAGE 2>/dev/null >/dev/null;
# If success
then
# Verify the file exists on the FTP server
echo "FTP transfer verification will begin in 30 seconds."
echo "..."
printf "\n"
sleep 30s # Wait 30 seconds
# If the file can be found using Curl on the FTP server
if curl --output /dev/null --silent --head --fail $CURL_FTP_ARGUMENTS "ftp://$FTP_USERNAME:$FTP_PASSWORD@$FTP_SERVER:$FTP_PORT/$FTP_SAVEPATH/$FILENAME"
# If success
then
echo "File exists on the FTP server."
echo "..."
printf "\n"
# Remove snapshot file from the local server
echo "Now removing $FILENAME from the local server."
rm $GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME
echo "Finished removing file."
echo "..."
printf "\n"
# Verify snapshot file has been removed from the local server
echo "Verifying $FILENAME has been removed from the local server."
echo "..."
printf "\n"
if [ -f $GLOBAL_BACKUP_TEMP_SAVEPATH/$FILENAME ]
# If success
then
echo "File still exists on the local server."
echo "Backup has failed."
printf "\n"
# Send an email explaining this failure
echo "An email will be sent to $GLOBAL_EMAIL_TO"
echo "$FILENAME was supposed to removed, but still exists on the local server." | mail -s "Failure: $NAME Backup to FTP server" $GLOBAL_EMAIL_TO
exit 1 # Exit with general error
# If failure
else
echo "Backup has finished successfully."
printf "\n"
# Send an email explaing a successful backup
echo "An email will be sent to $GLOBAL_EMAIL_TO"
echo "Backup has finished successfully. $FILENAME has been created on the FTP server ($FTP_SERVER)." | mail -s "Success: $NAME Backup to FTP server" $GLOBAL_EMAIL_TO
exit 0 # Successful exit
fi
# If failure
else
echo "File does not exist on the FTP server."
echo "Backup has failed."
printf "\n"
# Send an email explaining this failure
echo "An email will be sent to $GLOBAL_EMAIL_TO"
echo "$FILENAME does not exist on the FTP server. The snapshot file has been kept on the local server - consider moving this file to the FTP server manually." | mail -s "Failure: $NAME Backup to FTP server" $GLOBAL_EMAIL_TO
exit 1 # Exit with general error
fi
# If failure
else
echo "The '$PACKAGE' package is not installed on your system."
echo "Install by running: 'sudo apt-get install $PACKAGE'"
exit 1 # Exit with general error
fi
# If failure
else
echo "Could not connect to '$FTP_SERVER' on port '$FTP_PORT'."
exit 1 # Exit with general error
fi
# If failure
else
echo "The '$PACKAGE' package is not installed on your system."
echo "Install by running: 'sudo apt-get install $PACKAGE'"
exit 1 # Exit with general error
fi
# If failure
else
echo "File does not exist on the local server."
echo "Backup has failed."
printf "\n"
# Send an email explaining this failure
echo "An email will be sent to $GLOBAL_EMAIL_TO"
echo "Creating $FILENAME on local server failed." | mail -s "Failure: $NAME Backup to FTP server" $GLOBAL_EMAIL_TO
exit 1 # Exit with general error
fi
# If failure
else
echo "The '$PACKAGE' package is not installed on your system."
echo "Backup has failed."
printf "\n"
echo "Install by running: 'apt-get install $PACKAGE'"
exit 1 # Exit with general error
fi
# If failure
else
echo "The '$PACKAGE' package is not installed on your system."
echo "Install by running: 'sudo apt-get install $PACKAGE'"
exit 1 # Exit with general error
fi
# If one or more arguments are empty, produce an error
else
echo "One or more arguments are empty."
exit 1 # Exit with general error
fi