To Backup MySQL Databases to Object Storage with Percona on Ubuntu 16.04

  • The databases square measure store a number of the foremost valuable data in your infrastructure.
  • As a result of it’s necessary to own reliable backups to protect against information loss within the event of Associate in Nursing accident or hardware failure.

The Percona XtraBackup backup tools offer a technique of playing “hot” backups of MySQL information whereas the system is running. They are doing this by repeating the information files at the filesystem level then playing a crash recovery to realize consistency at intervals the dataset.

  • In a previous guide, we tend to put in Percona’s backup utilities and created a series of scripts to perform rotating native backups.
  • This works well for backing up information to a special drive or network mounted volume to handle issues together with your info machine.

However, in most cases, information ought to be saved off-site wherever it is often simply maintained and fixed up.

  • We can extend our previous backup system to transfer our compressed, encrypted backup files to Associate in Nursing object storage service.

We are going to be victimization DigitalOcean areas as Associate in Nursing example during this guide. However, the essential procedures square measure possible applicable for alternative S3-compatible object storage solutions yet.

Prerequisites

Before you begin this guide, you’ll like a MySQL info server organized with the native Percona backup answer printed in our previous guide. the complete set of guides you wish to follow are:

  • Initial Server Setup with Ubuntu sixteen.04: This guide can assist you to tack together a user account with sudo privileges and tack together a basic firewall.

One of the subsequent MySQL installation guides:

  • How To Install MySQL on Ubuntu sixteen.04: Uses the default package provided and maintained by the Ubuntu team.
  • How To Install the newest MySQL on Ubuntu sixteen.04: Uses updated packages provided by the MySQL project.
  • How To tack together MySQL Backups with Percona XtraBackup on Ubuntu sixteen.04: This guide sets up a neighborhood MySQL backup answer victimization the Percona XtraBackup tools.

In addition to the on top of tutorials, you’ll conjointly generate Associate in Nursing access key and secret key to act together with your object storage account victimization the API. If you’re victimization DigitalOcean areas, you’ll be able to verify the way to generate these credentials by following our the way to produce a DigitalOcean area and API Key guide. You’ll save each the API access key and API secret price.

When you’re finished with the previous guides, log back to your server as your sudo user to urge started.

Installing the Dependencies

  • To generate our backups, we would use python and bash scripts and then transfer them to an remote object storage to keep safe.
  • We can like the boto3 Python library to act with the article storage API. we will transfer this with pip, Python’s package manager.
  • Refresh our native package index then install the Python three version of pip from Ubuntu’s default repositories victimization apt-get by typing:
[pastacode lang=”bash” manual=”%24%20sudo%20apt-get%20update%0A%24%20sudo%20apt-get%20install%20python3-pip” message=”” highlight=”” provider=”manual”/]
  • Because Ubuntu maintains its own package life cycle, the version of pip in Ubuntu’s repositories isn’t unbroken in a set with recent releases. However, we will update to a more modern version of pip victimization the tool itself.
  •   We can use sudo to put in globally and embrace the -H flag to line the $HOME variable to a price pip expects:
[pastacode lang=”bash” manual=”%24%20sudo%20-H%20pip3%20install%20–upgrade%20pip” message=”” highlight=”” provider=”manual”/]

Afterward, we will install boto3 beside the pytz module, that we’ll use to check times accurately victimization the offset-aware format that the article storage API returns:

[pastacode lang=”bash” manual=”%24%20sudo%20-H%20pip3%20install%20boto3%20pytz” message=”” highlight=”” provider=”manual”/]

We ought to currently have all of the Python modules we want to act with the article storage API.

Create Associate in Nursing Object Storage Configuration File

  • Our backup and transfer scripts can act with the article storage API so as to transfer files and transfer older backup artifacts after we ought to restore.
  • They can use the access keys we tend to generate within the requirement section. instead of keeping these values within the scripts themselves, we’ll place them in an exceedingly dedicated file which will be browsed by our scripts.
  • This fashion, we are able to share our scripts without worrying of exposing our credentials and that we can lock down the credentials additional heavily than the script itself.
  • In the last guide, we tend to create the /backups/mysql directory to store our backups and our coding key. we’ll place the configuration file here aboard our alternative assets. Produce a file known as object_storage_config.sh:
[pastacode lang=”bash” manual=”%24%20sudo%20nano%20%2Fbackups%2Fmysql%2Fobject_storage_config.sh” message=”” highlight=”” provider=”manual”/]

Inside, paste the subsequent contents, dynamical the access key and secret key to the prices you obtained from your object storage account and also the bucket name to a novel value. Set the endpoint universal resource locator and region name to the values provided by your object storage service (we can use the values related to DigitalOcean’s NYC3 region for areas here):

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%0Aexport%20MYACCESSKEY%3D%22my_access_key%22%0Aexport%20MYSECRETKEY%3D%22my_secret_key%22%0Aexport%20MYBUCKETNAME%3D%22your_unique_bucket_name%22%0Aexport%20MYENDPOINTURL%3D%22https%3A%2F%2Fnyc3.digitaloceanspaces.com%22%0Aexport%20MYREGIONNAME%3D%22nyc3%22″ message=”/backups/mysql/object_storage_config.sh” highlight=”” provider=”manual”/]

These lines outline 2 surroundings variables known as MYACCESSKEY and MYSECRETKEY to carry our access and secret keys severally.

The MYBUCKETNAME variable defines the article storage bucket we wish to use to store our backup files.

Bucket names should be universally distinctive, therefore you want to select a reputation that no alternative user has elect. Our script can check the bucket price to envision if it’s already claimed by another user and automatically produce it if it’s on the market.

We export the variables we tend to outline so any processes we tend to decision from at intervals our scripts can have access to those values.

MYENDPOINTURL and MYREGIONNAME:

The MYENDPOINTURL and MYREGIONNAME variables contain the API endpoint and also the specific region symbol offered by your object storage supplier.

DigitalOcean areas, the endpoint is going to be https://region_name.digitaloceanspaces.com. You’ll be able to notice them on the market regions for areas within the DigitalOcean panel (at the time of this writing, solely “nyc3” is available).

Save and shut the file once you square measure finished.

Anyone WHO will access our API keys has complete access to our object storage account, therefore it’s necessary to limit access to the configuration file to the backup user. we will offer the backup user and cluster possession of the file then revoke all alternative access by typing:

[pastacode lang=”bash” manual=”%24%20sudo%20chown%20backup%3Abackup%20%2Fbackups%2Fmysql%2Fobject_storage_config.sh%0A%24%20sudo%20chmod%20600%20%2Fbackups%2Fmysql%2Fobject_storage_config.sh” message=”” highlight=”” provider=”manual”/]

Our object_storage_config.sh file ought to currently solely be accessible to the backup user.

Creating the Remote Backup Scripts

Now that we’ve got Associate in Nursing object storage configuration file, we will act and start making our scripts. we’ll be making the subsequent scripts:

  • object_storage.py: This script is chargeable for interacting with the article storage API to form buckets, transfer files, transfer content, and prune older backups. Our alternative scripts can decision this script anytime they have to act with the remote object storage account.
  • remote-backup-mysql.sh: This script backs up the MySQL databases by encrypting and pressing the files into one whole then uploading it to the remote object store. It creates a full backup at the start of {every} day then Associate in Nursing progressive backup every hour after. It automatically prunes all files from the remote bucket that square measure older than thirty days.
  • download-day.sh: This script permits the U.S.A. to transfer all of the backups related to a given day. as a result of our backup script creates a full backup every morning then progressive backups throughout the day, this script will transfer all of the assets necessary to revive to any hourly stop.

Along with the new scripts on top of, we’ll leverage the extract-mysql.sh and prepare-mysql.sh scripts from the previous guide to assist restore our files. You’ll be able to read the scripts within the repository for this tutorial on GitHub at any time. If you are doing not need to repeat and paste the contents below, you’ll be able to transfer the new files directly from GitHub by typing:

[pastacode lang=”bash” manual=”%24%20cd%20%2Ftmp%0A%24%20curl%20-LO%20https%3A%2F%2Fraw.githubusercontent.com%2Fdo-community%2Fubuntu-1604-mysql-backup%2Fmaster%2Fobject_storage.py%0A%24%20curl%20-LO%20https%3A%2F%2Fraw.githubusercontent.com%2Fdo-community%2Fubuntu-1604-mysql-backup%2Fmaster%2Fremote-backup-mysql.sh%0A%24%20curl%20-LO%20https%3A%2F%2Fraw.githubusercontent.com%2Fdo-community%2Fubuntu-1604-mysql-backup%2Fmaster%2Fdownload-day.sh” message=”” highlight=”” provider=”manual”/]
  • Be sure to inspect the scripts after downloading to make sure they were retrieved successfully and that you approve of the actions they will perform. If you are pleased, then mark the scripts that are executable and then move them into the /usr/local/bin directory by typing:
[pastacode lang=”markup” manual=”%24%20chmod%20%2Bx%20%2Ftmp%2F%7Bremote-backup-mysql.sh%2Cdownload-day.sh%2Cobject_storage.py%7D%0A%24%20sudo%20mv%20%2Ftmp%2F%7Bremote-backup-mysql.sh%2Cdownload-day.sh%2Cobject_storage.py%7D%20%2Fusr%2Flocal%2Fbin” message=”” highlight=”” provider=”manual”/]
  • Next, we will set up each of these scripts and discuss them in more detail.

Create the object_storage.py Script

  • If you didn’t download the py script from GitHub, create a new file in the /usr/local/bin directory called object_storage.py:
[pastacode lang=”bash” manual=”%24%20sudo%20nano%20%2Fusr%2Flocal%2Fbin%2Fobject_storage.py” message=”” highlight=”” provider=”manual”/]
  • Copy and paste the script contents into the file:
[pastacode lang=”bash” manual=”%23!%2Fusr%2Fbin%2Fenv%20python3%0A%0Aimport%20argparse%0Aimport%20os%0Aimport%20sys%0Afrom%20datetime%20import%20datetime%2C%20timedelta%0A%0Aimport%20boto3%0Aimport%20pytz%0Afrom%20botocore.client%20import%20ClientError%2C%20Config%0Afrom%20dateutil.parser%20import%20parse%0A%0A%23%20%22backup_bucket%22%20must%20be%20a%20universally%20unique%20name%2C%20so%20choose%20something%0A%23%20specific%20to%20your%20setup.%0A%23%20The%20bucket%20will%20be%20created%20in%20your%20account%20if%20it%20does%20not%20already%20exist%0Abackup_bucket%20%3D%20os.environ%5B’MYBUCKETNAME’%5D%0Aaccess_key%20%3D%20os.environ%5B’MYACCESSKEY’%5D%0Asecret_key%20%3D%20os.environ%5B’MYSECRETKEY’%5D%0Aendpoint_url%20%3D%20os.environ%5B’MYENDPOINTURL’%5D%0Aregion_name%20%3D%20os.environ%5B’MYREGIONNAME’%5D%0A%0A%0Aclass%20Space()%3A%0A%20%20%20%20def%20__init__(self%2C%20bucket)%3A%0A%20%20%20%20%20%20%20%20self.session%20%3D%20boto3.session.Session()%0A%20%20%20%20%20%20%20%20self.client%20%3D%20self.session.client(‘s3’%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20region_name%3Dregion_name%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20endpoint_url%3Dendpoint_url%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20aws_access_key_id%3Daccess_key%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20aws_secret_access_key%3Dsecret_key%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20config%3DConfig(signature_version%3D’s3’)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20self.bucket%20%3D%20bucket%0A%20%20%20%20%20%20%20%20self.paginator%20%3D%20self.client.get_paginator(‘list_objects’)%0A%0A%20%20%20%20def%20create_bucket(self)%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.client.head_bucket(Bucket%3Dself.bucket)%0A%20%20%20%20%20%20%20%20except%20ClientError%20as%20e%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20e.response%5B’Error’%5D%5B’Code’%5D%20%3D%3D%20’404’%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.client.create_bucket(Bucket%3Dself.bucket)%0A%20%20%20%20%20%20%20%20%20%20%20%20elif%20e.response%5B’Error’%5D%5B’Code’%5D%20%3D%3D%20’403’%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%22The%20bucket%20name%20%5C%22%7B%7D%5C%22%20is%20already%20being%20used%20by%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22someone.%20%20Please%20try%20using%20a%20different%20bucket%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name.%22.format(self.bucket))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sys.exit(1)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%22Unexpected%20error%3A%20%7B%7D%22.format(e))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sys.exit(1)%0A%0A%20%20%20%20def%20upload_files(self%2C%20files)%3A%0A%20%20%20%20%20%20%20%20for%20filename%20in%20files%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.client.upload_file(Filename%3Dfilename%2C%20Bucket%3Dself.bucket%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Key%3Dos.path.basename(filename))%0A%20%20%20%20%20%20%20%20%20%20%20%20print(%22Uploaded%20%7B%7D%20to%20%5C%22%7B%7D%5C%22%22.format(filename%2C%20self.bucket))%0A%0A%20%20%20%20def%20remove_file(self%2C%20filename)%3A%0A%20%20%20%20%20%20%20%20self.client.delete_object(Bucket%3Dself.bucket%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Key%3Dos.path.basename(filename))%0A%0A%20%20%20%20def%20prune_backups(self%2C%20days_to_keep)%3A%0A%20%20%20%20%20%20%20%20oldest_day%20%3D%20datetime.now(pytz.utc)%20-%20timedelta(days%3Dint(days_to_keep))%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Create%20an%20iterator%20to%20page%20through%20results%0A%20%20%20%20%20%20%20%20%20%20%20%20page_iterator%20%3D%20self.paginator.paginate(Bucket%3Dself.bucket)%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Collect%20objects%20older%20than%20the%20specified%20date%0A%20%20%20%20%20%20%20%20%20%20%20%20objects_to_prune%20%3D%20%5Bfilename%5B’Key’%5D%20for%20page%20in%20page_iterator%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20filename%20in%20page%5B’Contents’%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20filename%5B’LastModified’%5D%20%3C%20oldest_day%5D%0A%20%20%20%20%20%20%20%20except%20KeyError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20If%20the%20bucket%20is%20empty%0A%20%20%20%20%20%20%20%20%20%20%20%20sys.exit()%0A%20%20%20%20%20%20%20%20for%20object%20in%20objects_to_prune%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(%22Removing%20%5C%22%7B%7D%5C%22%20from%20%7B%7D%22.format(object%2C%20self.bucket))%0A%20%20%20%20%20%20%20%20%20%20%20%20self.remove_file(object)%0A%0A%20%20%20%20def%20download_file(self%2C%20filename)%3A%0A%20%20%20%20%20%20%20%20self.client.download_file(Bucket%3Dself.bucket%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Key%3Dfilename%2C%20Filename%3Dfilename)%0A%0A%20%20%20%20def%20get_day(self%2C%20day_to_get)%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Attempt%20to%20parse%20the%20date%20format%20the%20user%20provided%0A%20%20%20%20%20%20%20%20%20%20%20%20input_date%20%3D%20parse(day_to_get)%0A%20%20%20%20%20%20%20%20except%20ValueError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(%22Cannot%20parse%20the%20provided%20date%3A%20%7B%7D%22.format(day_to_get))%0A%20%20%20%20%20%20%20%20%20%20%20%20sys.exit(1)%0A%20%20%20%20%20%20%20%20day_string%20%3D%20input_date.strftime(%22-%25m-%25d-%25Y_%22)%0A%20%20%20%20%20%20%20%20print_date%20%3D%20input_date.strftime(%22%25A%2C%20%25b.%20%25d%20%25Y%22)%0A%20%20%20%20%20%20%20%20print(%22Looking%20for%20objects%20from%20%7B%7D%22.format(print_date))%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20create%20an%20iterator%20to%20page%20through%20results%0A%20%20%20%20%20%20%20%20%20%20%20%20page_iterator%20%3D%20self.paginator.paginate(Bucket%3Dself.bucket)%0A%20%20%20%20%20%20%20%20%20%20%20%20objects_to_grab%20%3D%20%5Bfilename%5B’Key’%5D%20for%20page%20in%20page_iterator%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20filename%20in%20page%5B’Contents’%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20day_string%20in%20filename%5B’Key’%5D%5D%0A%20%20%20%20%20%20%20%20except%20KeyError%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(%22No%20objects%20currently%20in%20bucket%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20sys.exit()%0A%20%20%20%20%20%20%20%20if%20objects_to_grab%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20object%20in%20objects_to_grab%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%22Downloading%20%5C%22%7B%7D%5C%22%20from%20%7B%7D%22.format(object%2C%20self.bucket))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.download_file(object)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(%22No%20objects%20found%20from%3A%20%7B%7D%22.format(print_date))%0A%20%20%20%20%20%20%20%20%20%20%20%20sys.exit()%0A%0A%0Adef%20is_valid_file(filename)%3A%0A%20%20%20%20if%20os.path.isfile(filename)%3A%0A%20%20%20%20%20%20%20%20return%20filename%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20raise%20argparse.ArgumentTypeError(%22File%20%5C%22%7B%7D%5C%22%20does%20not%20exist.%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.format(filename))%0A%0A%0Adef%20parse_arguments()%3A%0A%20%20%20%20parser%20%3D%20argparse.ArgumentParser(%0A%20%20%20%20%20%20%20%20description%3D”’Client%20to%20perform%20backup-related%20tasks%20with%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20object%20storage.”’)%0A%20%20%20%20subparsers%20%3D%20parser.add_subparsers()%0A%0A%20%20%20%20%23%20parse%20arguments%20for%20the%20%22upload%22%20command%0A%20%20%20%20parser_upload%20%3D%20subparsers.add_parser(‘upload’)%0A%20%20%20%20parser_upload.add_argument(‘files’%2C%20type%3Dis_valid_file%2C%20nargs%3D’%2B’)%0A%20%20%20%20parser_upload.set_defaults(func%3Dupload)%0A%0A%20%20%20%20%23%20parse%20arguments%20for%20the%20%22prune%22%20command%0A%20%20%20%20parser_prune%20%3D%20subparsers.add_parser(‘prune’)%0A%20%20%20%20parser_prune.add_argument(‘–days-to-keep’%2C%20default%3D30)%0A%20%20%20%20parser_prune.set_defaults(func%3Dprune)%0A%0A%20%20%20%20%23%20parse%20arguments%20for%20the%20%22download%22%20command%0A%20%20%20%20parser_download%20%3D%20subparsers.add_parser(‘download’)%0A%20%20%20%20parser_download.add_argument(‘filename’)%0A%20%20%20%20parser_download.set_defaults(func%3Ddownload)%0A%0A%20%20%20%20%23%20parse%20arguments%20for%20the%20%22get_day%22%20command%0A%20%20%20%20parser_get_day%20%3D%20subparsers.add_parser(‘get_day’)%0A%20%20%20%20parser_get_day.add_argument(‘day’)%0A%20%20%20%20parser_get_day.set_defaults(func%3Dget_day)%0A%0A%20%20%20%20return%20parser.parse_args()%0A%0A%0Adef%20upload(space%2C%20args)%3A%0A%20%20%20%20space.upload_files(args.files)%0A%0A%0Adef%20prune(space%2C%20args)%3A%0A%20%20%20%20space.prune_backups(args.days_to_keep)%0A%0A%0Adef%20download(space%2C%20args)%3A%0A%20%20%20%20space.download_file(args.filename)%0A%0A%0Adef%20get_day(space%2C%20args)%3A%0A%20%20%20%20space.get_day(args.day)%0A%0A%0Adef%20main()%3A%0A%20%20%20%20args%20%3D%20parse_arguments()%0A%20%20%20%20space%20%3D%20Space(bucket%3Dbackup_bucket)%0A%20%20%20%20space.create_bucket()%0A%20%20%20%20args.func(space%2C%20args)%0A%0A%0Aif%20__name__%20%3D%3D%20’__main__’%3A%0A%20%20%20%20main()” message=”/usr/local/bin/object_storage.py” highlight=”” provider=”manual”/]

This script is answerable for managing the backups inside your object storage account. It will transfer files, take away files, prune recent backups, and transfer files from object storage. Instead of interacting with the article storage API directly, our different scripts can use the practicality outlined here to move with remote resources. The commands it defines are:

  • upload: Uploads to object storage each of the files that are passed in as arguments. Multiple files are also more.
  • download: Downloads one file from remote object storage, that is passed in as associate argument
  • prune: Removes each file older than a precise age from the article storage location. By default, this removes files older than thirty days. You’ll change this by specifying the –days-to-keep choice once occupation prune.
  • get_day: Pass within the day to transfer as associate argument employing a normal date format (using quotations if the date has whitespace in it). Therefore the tool can conceive to take apart it and transfer all of the files from that date.

The script tries to browse the article storage credentials and bucket name from atmosphere variables, thus we are going to ensure those are inhabited from the object_storage_config.sh file before occupation the object_storage.py script.

When you’re finished, save and shut the file.

Next, if you haven’t already done this, create the script workable by typing:

[pastacode lang=”bash” manual=”%24%20sudo%20chmod%20%2Bx%20%2Fusr%2Flocal%2Fbin%2Fobject_storage.py” message=”” highlight=”” provider=”manual”/]

Now that the object_storage.py script is accessible to move with the API, we are able to produce the Bash scripts that use it to duplicate and transfer files.

Create the remote-backup-mysql.sh Script

  • Next, we are going to produce the remote-backup-mysql.sh script. This may perform several of a similar function because of the original backup-mysql.sh native backup script, with an additional basic organization structure (since maintaining backups on the native filesystem isn’t necessary) and a few extra steps to transfer to object storage.
  • If you probably did not transfer the script from the repository, produce and open a file known as remote-backup-mysql.sh in the /usr/local/bin directory:
[pastacode lang=”bash” manual=”%24%20sudo%20nano%20%2Fusr%2Flocal%2Fbin%2Fremote-backup-mysql.sh” message=”” highlight=”” provider=”manual”/]

Inside, paste the following script:

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%0Aexport%20LC_ALL%3DC%0A%0Adays_to_keep%3D30%0Abackup_owner%3D%22backup%22%0Aparent_dir%3D%22%2Fbackups%2Fmysql%22%0Adefaults_file%3D%22%2Fetc%2Fmysql%2Fbackup.cnf%22%0Aworking_dir%3D%22%24%7Bparent_dir%7D%2Fworking%22%0Alog_file%3D%22%24%7Bworking_dir%7D%2Fbackup-progress.log%22%0Aencryption_key_file%3D%22%24%7Bparent_dir%7D%2Fencryption_key%22%0Astorage_configuration_file%3D%22%24%7Bparent_dir%7D%2Fobject_storage_config.sh%22%0Anow%3D%22%24(date)%22%0Anow_string%3D%22%24(date%20-d%22%24%7Bnow%7D%22%20%2B%25m-%25d-%25Y_%25H-%25M-%25S)%22%0Aprocessors%3D%22%24(nproc%20–all)%22%0A%0A%23%20Use%20this%20to%20echo%20to%20standard%20error%0Aerror%20()%20%7B%0A%20%20%20%20printf%20%22%25s%3A%20%25s%5Cn%22%20%22%24(basename%20%22%24%7BBASH_SOURCE%7D%22)%22%20%22%24%7B1%7D%22%20%3E%262%0A%20%20%20%20exit%201%0A%7D%0A%0Atrap%20’error%20%22An%20unexpected%20error%20occurred.%22’%20ERR%0A%0Asanity_check%20()%20%7B%0A%20%20%20%20%23%20Check%20user%20running%20the%20script%0A%20%20%20%20if%20%5B%20%22%24(id%20–user%20–name)%22%20!%3D%20%22%24backup_owner%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Script%20can%20only%20be%20run%20as%20the%20%5C%22%24backup_owner%5C%22%20user%22%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Check%20whether%20the%20encryption%20key%20file%20is%20available%0A%20%20%20%20if%20%5B%20!%20-r%20%22%24%7Bencryption_key_file%7D%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Cannot%20read%20encryption%20key%20at%20%24%7Bencryption_key_file%7D%22%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Check%20whether%20the%20object%20storage%20configuration%20file%20is%20available%0A%20%20%20%20if%20%5B%20!%20-r%20%22%24%7Bstorage_configuration_file%7D%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Cannot%20read%20object%20storage%20configuration%20from%20%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Check%20whether%20the%20object%20storage%20configuration%20is%20set%20in%20the%20file%0A%20%20%20%20source%20%22%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20if%20%5B%20-z%20%22%24%7BMYACCESSKEY%7D%22%20%5D%20%7C%7C%20%5B%20-z%20%22%24%7BMYSECRETKEY%7D%22%20%5D%20%7C%7C%20%5B%20-z%20%22%24%7BMYBUCKETNAME%7D%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Object%20storage%20configuration%20are%20not%20set%20properly%20in%20%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20fi%0A%7D%0A%0Aset_backup_type%20()%20%7B%0A%20%20%20%20backup_type%3D%22full%22%0A%0A%0A%20%20%20%20%23%20Grab%20date%20of%20the%20last%20backup%20if%20available%0A%20%20%20%20if%20%5B%20-r%20%22%24%7Bworking_dir%7D%2Fxtrabackup_info%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20last_backup_date%3D%22%24(date%20-d%22%24(grep%20start_time%20%22%24%7Bworking_dir%7D%2Fxtrabackup_info%22%20%7C%20cut%20-d’%20’%20-f3)%22%20%2B%25s)%22%0A%20%20%20%20else%0A%20%20%20%20%20%20%20%20%20%20%20%20last_backup_date%3D0%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Grab%20today’s%20date%2C%20in%20the%20same%20format%0A%20%20%20%20todays_date%3D%22%24(date%20-d%20%22%24(date%20-d%20%22%24%7Bnow%7D%22%20%22%2B%25D%22)%22%20%2B%25s)%22%0A%0A%20%20%20%20%23%20Compare%20the%20two%20dates%0A%20%20%20%20((%20%24last_backup_date%20%3D%3D%20%24todays_date%20))%0A%20%20%20%20same_day%3D%22%24%7B%3F%7D%22%0A%0A%20%20%20%20%23%20The%20first%20backup%20each%20new%20day%20will%20be%20a%20full%20backup%0A%20%20%20%20%23%20If%20today’s%20date%20is%20the%20same%20as%20the%20last%20backup%2C%20take%20an%20incremental%20backup%20instead%0A%20%20%20%20if%20%5B%20%22%24same_day%22%20-eq%20%220%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20backup_type%3D%22incremental%22%0A%20%20%20%20fi%0A%7D%0A%0Aset_options%20()%20%7B%0A%20%20%20%20%23%20List%20the%20xtrabackup%20arguments%0A%20%20%20%20xtrabackup_args%3D(%0A%20%20%20%20%20%20%20%20%22–defaults-file%3D%24%7Bdefaults_file%7D%22%0A%20%20%20%20%20%20%20%20%22–backup%22%0A%20%20%20%20%20%20%20%20%22–extra-lsndir%3D%24%7Bworking_dir%7D%22%0A%20%20%20%20%20%20%20%20%22–compress%22%0A%20%20%20%20%20%20%20%20%22–stream%3Dxbstream%22%0A%20%20%20%20%20%20%20%20%22–encrypt%3DAES256%22%0A%20%20%20%20%20%20%20%20%22–encrypt-key-file%3D%24%7Bencryption_key_file%7D%22%0A%20%20%20%20%20%20%20%20%22–parallel%3D%24%7Bprocessors%7D%22%0A%20%20%20%20%20%20%20%20%22–compress-threads%3D%24%7Bprocessors%7D%22%0A%20%20%20%20%20%20%20%20%22–encrypt-threads%3D%24%7Bprocessors%7D%22%0A%20%20%20%20%20%20%20%20%22–slave-info%22%0A%20%20%20%20)%0A%0A%20%20%20%20set_backup_type%0A%0A%20%20%20%20%23%20Add%20option%20to%20read%20LSN%20(log%20sequence%20number)%20if%20taking%20an%20incremental%20backup%0A%20%20%20%20if%20%5B%20%22%24backup_type%22%20%3D%3D%20%22incremental%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20lsn%3D%24(awk%20’%2Fto_lsn%2F%20%7Bprint%20%243%3B%7D’%20%22%24%7Bworking_dir%7D%2Fxtrabackup_checkpoints%22)%0A%20%20%20%20%20%20%20%20xtrabackup_args%2B%3D(%20%22–incremental-lsn%3D%24%7Blsn%7D%22%20)%0A%20%20%20%20fi%0A%7D%0A%0Arotate_old%20()%20%7B%0A%20%20%20%20%23%20Remove%20previous%20backup%20artifacts%0A%20%20%20%20find%20%22%24%7Bworking_dir%7D%22%20-name%20%22*.xbstream%22%20-type%20f%20-delete%0A%0A%20%20%20%20%23%20Remove%20any%20backups%20from%20object%20storage%20older%20than%2030%20days%0A%20%20%20%20%2Fusr%2Flocal%2Fbin%2Fobject_storage.py%20prune%20–days-to-keep%20%22%24%7Bdays_to_keep%7D%22%0A%7D%0A%0Atake_backup%20()%20%7B%0A%20%20%20%20find%20%22%24%7Bworking_dir%7D%22%20-type%20f%20-name%20%22*.incomplete%22%20-delete%0A%20%20%20%20xtrabackup%20%22%24%7Bxtrabackup_args%5B%40%5D%7D%22%20–target-dir%3D%22%24%7Bworking_dir%7D%22%20%3E%20%22%24%7Bworking_dir%7D%2F%24%7Bbackup_type%7D-%24%7Bnow_string%7D.xbstream.incomplete%22%202%3E%20%22%24%7Blog_file%7D%22%0A%0A%20%20%20%20mv%20%22%24%7Bworking_dir%7D%2F%24%7Bbackup_type%7D-%24%7Bnow_string%7D.xbstream.incomplete%22%20%22%24%7Bworking_dir%7D%2F%24%7Bbackup_type%7D-%24%7Bnow_string%7D.xbstream%22%0A%7D%0A%0Aupload_backup%20()%20%7B%0A%20%20%20%20%2Fusr%2Flocal%2Fbin%2Fobject_storage.py%20upload%20%22%24%7Bworking_dir%7D%2F%24%7Bbackup_type%7D-%24%7Bnow_string%7D.xbstream%22%0A%7D%0A%0Amain%20()%20%7B%0A%20%20%20%20mkdir%20-p%20%22%24%7Bworking_dir%7D%22%0A%20%20%20%20sanity_check%20%26%26%20set_options%20%26%26%20rotate_old%20%26%26%20take_backup%20%26%26%20upload_backup%0A%0A%20%20%20%20%23%20Check%20success%20and%20print%20message%0A%20%20%20%20if%20tail%20-1%20%22%24%7Blog_file%7D%22%20%7C%20grep%20-q%20%22completed%20OK%22%3B%20then%0A%20%20%20%20%20%20%20%20printf%20%22Backup%20successful!%5Cn%22%0A%20%20%20%20%20%20%20%20printf%20%22Backup%20created%20at%20%25s%2F%25s-%25s.xbstream%5Cn%22%20%22%24%7Bworking_dir%7D%22%20%22%24%7Bbackup_type%7D%22%20%22%24%7Bnow_string%7D%22%0A%20%20%20%20else%0A%20%20%20%20%20%20%20%20error%20%22Backup%20failure!%20If%20available%2C%20check%20%24%7Blog_file%7D%20for%20more%20information%22%0A%20%20%20%20fi%0A%7D%0A%0Amain” message=”/usr/local/bin/remote-backup-mysql.sh” highlight=”” provider=”manual”/]
  • This script handles the particular MySQL backup procedure, controls the backup schedule, and automatically removes older backups from remote storage.
  • You will opt for what number of days of backups you would like to stay on-hand by adjusting the days_to_keep variable.
  • The native backup-mysql.sh script we tend to utilize in the last article maintained separate directories for every day’s backups.
  • Since we tend to area unit storing backups remotely, we’ll solely store the newest backup domestically so as to attenuate the disc space dedicated to backups.
  • Previous backups may be downloaded from object storage as required for restoration.
  • As with the previous script, once checking that many basic necessities area unit glad and configuring the kind of backup that ought to be taken, we tend to encipher and compress every backup into one file archive.
  • The previous computer file is aloof from the native filesystem and any remote backups that area unit older than the worth outlined in days_to_keep area unit removed.
  • Save and shut the file once you area unit finished. Afterward, make sure that the script is practicable by typing:
[pastacode lang=”bash” manual=”%24%20sudo%20chmod%20%2Bx%20%2Fusr%2Flocal%2Fbin%2Fremote-backup-mysql.sh” message=”” highlight=”” provider=”manual”/]

This script may be used as a replacement for the backup-mysql.sh script on this method to change from creating native backups to remote backups.

Create the download-day.sh Script

  • Finally, transfer or produce the download-day.sh script at intervals the /usr/local/bin directory. This script may be accustomed to transfer all of the backups related to a selected day.
  • Create the script to enter your text editor if you probably did not transfer it earlier:
[pastacode lang=”bash” manual=”%24%20sudo%20nano%20%2Fusr%2Flocal%2Fbin%2Fdownload-day.sh” message=”” highlight=”” provider=”manual”/]
  • Inside, paste the following contents:
[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%0A%0Aexport%20LC_ALL%3DC%0A%0Abackup_owner%3D%22backup%22%0Astorage_configuration_file%3D%22%2Fbackups%2Fmysql%2Fobject_storage_config.sh%22%0Aday_to_download%3D%22%24%7B1%7D%22%0A%0A%23%20Use%20this%20to%20echo%20to%20standard%20error%0Aerror%20()%20%7B%0A%20%20%20%20printf%20%22%25s%3A%20%25s%5Cn%22%20%22%24(basename%20%22%24%7BBASH_SOURCE%7D%22)%22%20%22%24%7B1%7D%22%20%3E%262%0A%20%20%20%20exit%201%0A%7D%0A%0Atrap%20’error%20%22An%20unexpected%20error%20occurred.%22’%20ERR%0A%0Asanity_check%20()%20%7B%0A%20%20%20%20%23%20Check%20user%20running%20the%20script%0A%20%20%20%20if%20%5B%20%22%24(id%20–user%20–name)%22%20!%3D%20%22%24backup_owner%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Script%20can%20only%20be%20run%20as%20the%20%5C%22%24backup_owner%5C%22%20user%22%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Check%20whether%20the%20object%20storage%20configuration%20file%20is%20available%0A%20%20%20%20if%20%5B%20!%20-r%20%22%24%7Bstorage_configuration_file%7D%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Cannot%20read%20object%20storage%20configuration%20from%20%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20fi%0A%0A%20%20%20%20%23%20Check%20whether%20the%20object%20storage%20configuration%20is%20set%20in%20the%20file%0A%20%20%20%20source%20%22%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20if%20%5B%20-z%20%22%24%7BMYACCESSKEY%7D%22%20%5D%20%7C%7C%20%5B%20-z%20%22%24%7BMYSECRETKEY%7D%22%20%5D%20%7C%7C%20%5B%20-z%20%22%24%7BMYBUCKETNAME%7D%22%20%5D%3B%20then%0A%20%20%20%20%20%20%20%20error%20%22Object%20storage%20configuration%20are%20not%20set%20properly%20in%20%24%7Bstorage_configuration_file%7D%22%0A%20%20%20%20fi%0A%7D%0A%0Amain%20()%20%7B%0A%20%20%20%20sanity_check%0A%20%20%20%20%2Fusr%2Flocal%2Fbin%2Fobject_storage.py%20get_day%20%22%24%7Bday_to_download%7D%22%0A%7D%0A%0Amain” message=”/usr/local/bin/download-day.sh” highlight=”” provider=”manual”/]

This script may be known as to transfer all of the archives from a particular day. Since day by day starts with a full backup and accumulates progressive backups throughout the remainder of the day, this may transfer all of the relevant files necessary to revive to any hourly photograph.

The script takes one argument that could be a date or day. It uses the Python’s dateutil.parser.parse perform to browse and interpret a date string provided as an argument.

The performance is fairly versatile and may interpret dates in a very style of formats, together with relative strings like “Friday“, as an example. To avoid ambiguity but, it’s best to use additional well-defined dates. take care to wrap dates in quotations if the format you would like to use contains whitespace.

When you’re able to continue, save and shut the file. build the script practicable by typing:

[pastacode lang=”bash” manual=”%24%20sudo%20chmod%20%2Bx%20%2Fusr%2Flocal%2Fbin%2Fdownload-day.sh” message=”” highlight=”” provider=”manual”/]

We currently have the flexibility to transfer the backup files from object storage for a particular date after we wish to revive.

Testing the Remote MySQL Backup and transfer Scripts

  • Now that we’ve our scripts in situ, we should always check to form positive they perform obviously.

Perform a Full Backup

  • Begin by vocation the remote-mysql-backup.sh script with the backup user. Since this is often the primary time we tend to area unit running this command, it ought to produce a full backup of our MySQL information.
[pastacode lang=”bash” manual=”%24%20sudo%20-u%20backup%20remote-backup-mysql.sh” message=”” highlight=”” provider=”manual”/]

Note:

If you receive a blunder indicating that the bucket name you chose is already in use, you may choose a special name. amendment the worth of MYBUCKETNAME within the /backups/mysql/object_storage_config.sh file and delete the native backup directory (sudo rm -rf /backups/mysql/working) so the script will try a full backup with the new bucket name. once you area unit prepared, rerun the command higher than to do once more.

If everything goes well, you may see output like the following:

Output:

[pastacode lang=”bash” manual=”Uploaded%20%2Fbackups%2Fmysql%2Fworking%2Ffull-10-17-2017_19-09-30.xbstream%20to%20%22your_bucket_name%22%0ABackup%20successful!%0ABackup%20created%20at%20%2Fbackups%2Fmysql%2Fworking%2Ffull-10-17-2017_19-09-30.xbstream” message=”” highlight=”” provider=”manual”/]

This indicates that a full backup has been created at intervals the /backups/mysql/working directory. it’s conjointly been uploaded to remote object storage exploitation the bucket outlined within the object_storage_config.sh file.

If we glance at intervals the /backups/mysql/working directory, we will see files like those created by the backup-mysql.sh script from the last guide:

[pastacode lang=”bash” manual=”%24%20ls%20%2Fbackups%2Fmysql%2Fworking” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”backup-progress.log%20%20full-10-17-2017_19-09-30.xbstream%20%20xtrabackup_checkpoints%20%20xtrabackup_info” message=”” highlight=”” provider=”manual”/]

The backup-progress.log file contains the output from the xtrabackup command, whereas xtrabackup_checkpoints and xtrabackup_info contain info concerning choices used, the kind and scope of the backup, and different information.

Perform a progressive Backup

Let’s build a tiny low amendment to our instrumentation table so as to make the extra information not found in our initial backup. we will enter a replacement row within the table by typing:

[pastacode lang=”bash” manual=”%24%20mysql%20-u%20root%20-p%20-e%20’INSERT%20INTO%20playground.equipment%20(type%2C%20quant%2C%20color)%20VALUES%20(%22sandbox%22%2C%204%2C%20%22brown%22)%3B'” message=”” highlight=”” provider=”manual”/]

Enter your database’s body countersign to feature the new record.

Now, we will take an extra backup. after we decide the script once more, a progressive backup ought to be created as long because it remains a similar day because of the previous backup (according to the server’s clock):

[pastacode lang=”bash” manual=”%24%20sudo%20-u%20backup%20remote-backup-mysql.sh” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”Uploaded%20%2Fbackups%2Fmysql%2Fworking%2Fincremental-10-17-2017_19-19-20.xbstream%20to%20%22your_bucket_name%22%0ABackup%20successful!%0ABackup%20created%20at%20%2Fbackups%2Fmysql%2Fworking%2Fincremental-10-17-2017_19-19-20.xbstream” message=”” highlight=”” provider=”manual”/]

The higher than output indicates that the backup was created at intervals a similar directory domestically, and was once more uploaded to object storage. If we tend to check the /backups/mysql/working directory, we’ll realize that the new backup is present which the previous backup has been removed:

[pastacode lang=”bash” manual=”%24%20ls%20%2Fbackups%2Fmysql%2Fworking” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”backup-progress.log%20%20incremental-10-17-2017_19-19-20.xbstream%20%20xtrabackup_checkpoints%20%20xtrabackup_info” message=”” highlight=”” provider=”manual”/]

Since our files area unit uploaded remotely. Deleting the native copy helps to scale back the quantity of disc space used.

Download the Backups from a given Day

  • Since our backups area unit holds on remotely. We’ll pull down the remote files if we’d like to revive our files. To do this, we will use the download-day.sh script.
  • Begin by making and so stepping into a directory that the backup user will safely write to:
[pastacode lang=”bash” manual=”%24%20sudo%20-u%20backup%20mkdir%20%2Ftmp%2Fbackup_archives%0A%24%20cd%20%2Ftmp%2Fbackup_archives” message=”” highlight=”” provider=”manual”/]

Next, decision the download-day.sh script because of the backup user. Pass within the day of the archives you want to transfer. The date format is fairly versatile, however, it’s best to undertake to be unambiguous:

[pastacode lang=”bash” manual=”%24%20sudo%20-u%20backup%20download-day.sh%20%22Oct.%2017%22″ message=”” highlight=”” provider=”manual”/]

If there area unit archives that match the date you provided, they’ll be downloaded to this directory:

Output:

[pastacode lang=”bash” manual=”Looking%20for%20objects%20from%20Tuesday%2C%20Oct.%2017%202017%0ADownloading%20%22full-10-17-2017_19-09-30.xbstream%22%20from%20your_bucket_name%0ADownloading%20%22incremental-10-17-2017_19-19-20.xbstream%22%20from%20your_bucket_name” message=”” highlight=”” provider=”manual”/]

Verify that the files are downloaded to the native filesystem:

[pastacode lang=”markup” manual=”%24%20ls” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”full-10-17-2017_19-09-30.xbstream%20%20incremental-10-17-2017_19-19-20.xbstream” message=”” highlight=”” provider=”manual”/]

The compressed, encrypted archives area unit currently back on the server once more.

Extract and Prepare the Backups

Once the files area unit collected, we will method them identical approach we have a tendency to processed native backups.

First, pass the .xbstream files to the extract-mysql.sh script victimization the backup user:

[pastacode lang=”bash” manual=”%24%20sudo%20-u%20backup%20extract-mysql.sh%20*.xbstream” message=”” highlight=”” provider=”manual”/]

This can decode and decompress the archives into a directory referred to as restore. Enter that directory and prepare the files with the prepare-mysql.sh script:

[pastacode lang=”bash” manual=”%24%20cd%20restore%0A%24%20sudo%20-u%20backup%20prepare-mysql.sh” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”Backup%20looks%20to%20be%20fully%20prepared.%20%20Please%20check%20the%20%22prepare-progress.log%22%20file%0Ato%20verify%20before%20continuing.%0A%0AIf%20everything%20looks%20correct%2C%20you%20can%20apply%20the%20restored%20files.%0A%0AFirst%2C%20stop%20MySQL%20and%20move%20or%20remove%20the%20contents%20of%20the%20MySQL%20data%20directory%3A%0A%0A%20%20%20%20%20%20%20%20sudo%20systemctl%20stop%20mysql%0A%20%20%20%20%20%20%20%20sudo%20mv%20%2Fvar%2Flib%2Fmysql%2F%20%2Ftmp%2F%0A%0AThen%2C%20recreate%20the%20data%20directory%20and%20%20copy%20the%20backup%20files%3A%0A%0A%20%20%20%20%20%20%20%20sudo%20mkdir%20%2Fvar%2Flib%2Fmysql%0A%20%20%20%20%20%20%20%20sudo%20xtrabackup%20–copy-back%20–target-dir%3D%2Ftmp%2Fbackup_archives%2Frestore%2Ffull-10-17-2017_19-09-30%0A%0AAfterward%20the%20files%20are%20copied%2C%20adjust%20the%20permissions%20and%20restart%20the%20service%3A%0A%0A%20%20%20%20%20%20%20%20sudo%20chown%20-R%20mysql%3Amysql%20%2Fvar%2Flib%2Fmysql%0A%20%20%20%20%20%20%20%20sudo%20find%20%2Fvar%2Flib%2Fmysql%20-type%20d%20-exec%20chmod%20750%20%7B%7D%20%5C%3B%0A%20%20%20%20%20%20%20%20sudo%20systemctl%20start%20mysql” message=”” highlight=”” provider=”manual”/]

The full backup within the /tmp/backup_archives/restore directory ought to currently be ready. we will follow the directions within the output to revive the MySQL information on our system.

Restore the Backup information to the MySQL information Directory

Before we tend to restore the backup information, we’d like to maneuver this information out of the approach.

Start by the move down MySQL to avoid corrupting the info or bloody the service once we replace its information files.

[pastacode lang=”bash” manual=”%24%20sudo%20systemctl%20stop%20mysql” message=”” highlight=”” provider=”manual”/]

Next, we will move this information directory to the /tmp directory. This way, we will simply move it back if the restore has issues. Since we tend to affect the files to /tmp/mysql within the last article. We will move the files to /tmp/mysql-remote this time:

[pastacode lang=”bash” manual=”%24%20sudo%20mv%20%2Fvar%2Flib%2Fmysql%2F%20%2Ftmp%2Fmysql-remote” message=”” highlight=”” provider=”manual”/]

Next, recreate associate degree empty /var/lib/mysql directory:

[pastacode lang=”bash” manual=”%24%20sudo%20mkdir%20%2Fvar%2Flib%2Fmysql” message=”” highlight=”” provider=”manual”/]

Now, we will sort the xtrabackup restore command that the prepare-mysql.sh command provided to repeat the backup files into the /var/lib/mysql directory:

[pastacode lang=”bash” manual=”%24%20sudo%20xtrabackup%20–copy-back%20–target-dir%3D%2Ftmp%2Fbackup_archives%2Frestore%2Ffull-10-17-2017_19-09-30%0A” message=”” highlight=”” provider=”manual”/]

Once the method completes, modify the directory permissions and possession to make sure that the MySQL method has access:

[pastacode lang=”bash” manual=”%24%20sudo%20chown%20-R%20mysql%3Amysql%20%2Fvar%2Flib%2Fmysql%0A%24%20sudo%20find%20%2Fvar%2Flib%2Fmysql%20-type%20d%20-exec%20chmod%20750%20%7B%7D%20%5C%3B” message=”” highlight=”” provider=”manual”/]

When this finishes, begin MySQL once more and certify our information has been properly restored:

[pastacode lang=”bash” manual=”%24%20sudo%20systemctl%20start%20mysql%0A%24%20mysql%20-u%20root%20-p%20-e%20’SELECT%20*%20FROM%20playground.equipment%3B'” message=”” highlight=”” provider=”manual”/]

Output:

[pastacode lang=”bash” manual=”%2B—-%2B———%2B——-%2B——–%2B%0A%7C%20id%20%7C%20type%20%20%20%20%7C%20quant%20%7C%20color%20%20%7C%0A%2B—-%2B———%2B——-%2B——–%2B%0A%7C%20%201%20%7C%20slide%20%20%20%7C%20%20%20%20%202%20%7C%20blue%20%20%20%7C%0A%7C%20%202%20%7C%20swing%20%20%20%7C%20%20%20%2010%20%7C%20yellow%20%7C%0A%7C%20%203%20%7C%20sandbox%20%7C%20%20%20%20%204%20%7C%20brown%20%20%7C%0A%2B—-%2B———%2B——-%2B——–%2B” message=”” highlight=”” provider=”manual”/]
  • The knowledge is on the market, that indicates that it’s been with success remodeled.
  • After restoring your knowledge, it’s vital to travel back and delete the restore directory. Future progressive backups cannot be applied to the total backup once it’s been ready, therefore we should always take away it. what is more, the backup directories shouldn’t be left unencrypted on disk for security reasons:
[pastacode lang=”bash” manual=”%24%20cd%20~%0A%24%20sudo%20rm%20-rf%20%2Ftmp%2Fbackup_archives%2Frestore” message=”” highlight=”” provider=”manual”/]
  • The next time we want clean copies of the backup directories. We are able to extract them once more from the backup archive files.

Creating a Cron Job to Run Backups Hourly

  • We created a cron job to mechanically backup up our information regionally within the last guide. We’ll establish a replacement cron job to require remote backups so disable the native backup job.
  • We will simply switch between native and remote backups as necessary by sanctioning or disabling the cron scripts.
  • To start, produce a file referred to as remote-backup-mysql within the /etc/cron.hourly directory:
[pastacode lang=”bash” manual=”%24%20sudo%20nano%20%2Fetc%2Fcron.hourly%2Fremote-backup-mysql” message=”” highlight=”” provider=”manual”/]
  • Inside, we’ll decide our remote-backup-mysql.sh script with the backup user through the systemd-cat command, that permits the North American nation to log the output to journald:
[pastacode lang=”bash” manual=”%23!%2Fbin%2Fbash%20%0Asudo%20-u%20backup%20systemd-cat%20–identifier%3Dremote-backup-mysql%20%2Fusr%2Flocal%2Fbin%2Fremote-backup-mysql.sh” message=”/etc/cron.hourly/remote-backup-mysql” highlight=”” provider=”manual”/]
  • Save and shut the file after you square measure finished in python.
  • We can modify our new cron job and disable the previous one by manipulating the viable permission bit on each file in python:
[pastacode lang=”bash” manual=”%24%20sudo%20chmod%20-x%20%2Fetc%2Fcron.hourly%2Fbackup-mysql%0A%24%20sudo%20chmod%20%2Bx%20%2Fetc%2Fcron.hourly%2Fremote-backup-mysql” message=”” highlight=”” provider=”manual”/]
  • Test the new remote backup job by executing the script manually:
[pastacode lang=”bash” manual=”%24%20sudo%20%2Fetc%2Fcron.hourly%2Fremote-backup-mysql” message=”” highlight=”” provider=”manual”/]
  • Once the prompt returns, we are able to check the log entries with journalctl:
[pastacode lang=”bash” manual=”%24%20sudo%20journalctl%20-t%20remote-backup-mysql” message=”” highlight=”” provider=”manual”/] [pastacode lang=”bash” manual=”%5Bseconary_label%20Output%5D%0A–%20Logs%20begin%20at%20Tue%202017-10-17%2014%3A28%3A01%20UTC%2C%20end%20at%20Tue%202017-10-17%2020%3A11%3A03%20UTC.%20–%0AOct%2017%2020%3A07%3A17%20myserver%20remote-backup-mysql%5B31422%5D%3A%20Uploaded%20%2Fbackups%2Fmysql%2Fworking%2Fincremental-10-17-2017_22-16-09.xbstream%20to%20%22your_bucket_name%22%0AOct%2017%2020%3A07%3A17%20myserver%20remote-backup-mysql%5B31422%5D%3A%20Backup%20successful!%0AOct%2017%2020%3A07%3A17%20myserver%20remote-backup-mysql%5B31422%5D%3A%20Backup%20created%20at%20%2Fbackups%2Fmysql%2Fworking%2Fincremental-10-17-2017_20-07-13.xbstream” message=”” highlight=”” provider=”manual”/]
  • Check back in a very few hours to form certain that further backups are being taken on schedule.

Backing Up the Extraction Key

  • One final thought that you just can handle is the way to make a copy the cryptography key (found at /backups/mysql/encryption_key).
  • The cryptography key’s needed to revive any of the files secured mistreatment this method. However, storing the cryptography key within the same location because the info files eliminate the protection provided by cryptography.
  • Because of this, it’s necessary to stay a replica of the cryptography key in a very separate location in order that you’ll be able to still use the backup archives if your info server fails or must be remodeled.
  • While an entire backup resolution for non-database files is outside the scope of this text. You’ll be able to copy the key to your native laptop for keeping. To do so, read the contents of the file by typing:
[pastacode lang=”bash” manual=”%24%20sudo%20less%20%2Fbackups%2Fmysql%2Fencryption_key” message=”” highlight=”” provider=”manual”/]
  • Open a document on your native laptop and paste the worth within. If you ever have to be compelled to restore backups onto a distinct server, copy the contents of the file to /backups/mysql/encryption_key on the new machine, originated the system made public during this guide. And so restore mistreatment the provided scripts.

Conclusion

  • In this guide, we’ve lined however take hourly backups of a MySQL info and transfer them mechanically to a foreign object space for storing.
  • The system can take a full backup each morning and so hourly progressive backups subsequently to supply the flexibility to revive to any hourly stop. Anytime the backup script runs, it checks for backups in object storage that are older than thirty days and removes them.

Categorized in: