Ubuntu16.04でPerconaを使用してMySQLデータベースをオブジェクトストレージにバックアップする方法
序章
多くの場合、データベースはインフラストラクチャに最も価値のある情報の一部を格納します。 このため、事故やハードウェア障害が発生した場合のデータ損失を防ぐために、信頼性の高いバックアップを用意することが重要です。
Percona XtraBackupバックアップツールは、システムの実行中にMySQLデータの「ホット」バックアップを実行する方法を提供します。 これを行うには、ファイルシステムレベルでデータファイルをコピーしてから、クラッシュリカバリを実行して、データセット内の一貫性を実現します。
以前のガイドでは、Perconaのバックアップユーティリティをインストールし、ローテーションローカルバックアップを実行するための一連のスクリプトを作成しました。 これは、データベースマシンの問題を処理するために、データを別のドライブまたはネットワークにマウントされたボリュームにバックアップする場合に適しています。 ただし、ほとんどの場合、データはオフサイトにバックアップして、簡単に保守および復元できるようにする必要があります。 このガイドでは、以前のバックアップシステムを拡張して、圧縮され暗号化されたバックアップファイルをオブジェクトストレージサービスにアップロードします。 このガイドでは例としてDigitalOceanSpaces を使用しますが、基本的な手順は他のS3互換のオブジェクトストレージソリューションにも適用できる可能性があります。
前提条件
このガイドを開始する前に、前のガイドで概説したローカルのPerconaバックアップソリューションで構成されたMySQLデータベースサーバーが必要です。 従う必要のあるガイドの完全なセットは次のとおりです。
- Ubuntu 16.04を使用したサーバーの初期セットアップ:このガイドは、次のユーザーアカウントを構成するのに役立ちます。
sudo
特権を設定し、基本的なファイアウォールを構成します。 - 次のMySQLインストールガイドのいずれか:
- Ubuntu 16.04にMySQLをインストールする方法:Ubuntuチームによって提供および保守されているデフォルトのパッケージを使用します。
- Ubuntu 16.04に最新のMySQLをインストールする方法:MySQLプロジェクトによって提供される更新されたパッケージを使用します。
- Ubuntu16.04でPerconaXtraBackupを使用してMySQLバックアップを構成する方法:このガイドでは、PerconaXtraBackupツールを使用してローカルのMySQLバックアップソリューションをセットアップします。
上記のチュートリアルに加えて、APIを使用してオブジェクトストレージアカウントとやり取りするためのアクセスキーとシークレットキーも生成する必要があります。 DigitalOcean Spacesを使用している場合は、DigitalOceanSpaceとAPIキーの作成方法ガイドに従ってこれらの資格情報を生成する方法を確認できます。 APIアクセスキーとAPIシークレット値の両方を保存する必要があります。
前のガイドを終了したら、サーバーにログインし直します。 sudo
開始するユーザー。
依存関係をインストールします
いくつかのPythonおよびBashスクリプトを使用してバックアップを作成し、保管のためにリモートオブジェクトストレージにアップロードします。 必要になります boto3
オブジェクトストレージAPIと対話するPythonライブラリ。 これをダウンロードできます pip
、Pythonのパッケージマネージャー。
ローカルパッケージインデックスを更新してから、Python3バージョンの pip
Ubuntuのデフォルトリポジトリから apt-get
次のように入力します。
- sudo apt-get update
- sudo apt-get install python3-pip
Ubuntuは独自のパッケージライフサイクルを維持しているため、 pip
Ubuntuのリポジトリでは、最近のリリースとの同期が保たれていません。 ただし、新しいバージョンに更新することはできます pip
ツール自体を使用します。 我々は使用するだろう sudo
グローバルにインストールし、 -H
フラグを設定して $HOME
値への変数 pip
期待する:
- sudo -H pip3 install --upgrade pip
その後、インストールできます boto3
一緒に pytz
モジュール。オブジェクトストレージAPIが返すオフセット対応形式を使用して時間を正確に比較するために使用します。
- sudo -H pip3 install boto3 pytz
これで、オブジェクトストレージAPIとやり取りするために必要なすべてのPythonモジュールができました。
オブジェクトストレージ構成ファイルを作成する
バックアップとダウンロードのスクリプトは、ファイルをアップロードし、復元する必要があるときに古いバックアップアーティファクトをダウンロードするために、オブジェクトストレージAPIと対話する必要があります。 前提条件のセクションで生成したアクセスキーを使用する必要があります。 これらの値をスクリプト自体に保持するのではなく、スクリプトで読み取ることができる専用ファイルに配置します。 このようにして、クレデンシャルを公開することを恐れずにスクリプトを共有でき、スクリプト自体よりもクレデンシャルを厳しくロックダウンできます。
最後のガイドでは、 /backups/mysql
バックアップと暗号化キーを保存するディレクトリ。 ここに、他のアセットと一緒に構成ファイルを配置します。 というファイルを作成します object_storage_config.sh
:
- sudo nano /backups/mysql/object_storage_config.sh
内部に次の内容を貼り付け、アクセスキーとシークレットキーをオブジェクトストレージアカウントから取得した値に変更し、バケット名を一意の値に変更します。 エンドポイントURLとリージョン名をオブジェクトストレージサービスによって提供される値に設定します(ここでは、スペースにDigitalOceanのNYC3リージョンに関連付けられた値を使用します)。
#!/bin/bash
export MYACCESSKEY="my_access_key"
export MYSECRETKEY="my_secret_key"
export MYBUCKETNAME="your_unique_bucket_name"
export MYENDPOINTURL="https://nyc3.digitaloceanspaces.com"
export MYREGIONNAME="nyc3"
これらの行は、と呼ばれる2つの環境変数を定義します MYACCESSKEY
と MYSECRETKEY
アクセスキーと秘密キーをそれぞれ保持します。 The MYBUCKETNAME
変数は、バックアップファイルの保存に使用するオブジェクトストレージバケットを定義します。 バケット名は普遍的に一意である必要があるため、他のユーザーが選択していない名前を選択する必要があります。 このスクリプトは、バケット値をチェックして、別のユーザーによって既に要求されているかどうかを確認し、使用可能な場合は自動的に作成します。 私達 export
スクリプト内から呼び出すプロセスがこれらの値にアクセスできるように定義する変数。
The MYENDPOINTURL
と MYREGIONNAME
変数には、APIエンドポイントと、オブジェクトストレージプロバイダーによって提供される特定のリージョン識別子が含まれます。 DigitalOceanスペースの場合、エンドポイントは https://region_name.digitaloceanspaces.com
. スペースに使用できる領域は、DigitalOceanコントロールパネルにあります(この記事の執筆時点では、「nyc3」のみが使用可能です)。
終了したら、ファイルを保存して閉じます。
APIキーにアクセスできる人は誰でも、オブジェクトストレージアカウントに完全にアクセスできるため、構成ファイルへのアクセスをに制限することが重要です。 backup
ユーザー。 私たちは与えることができます backup
ファイルのユーザーとグループの所有権を確認してから、次のように入力して他のすべてのアクセスを取り消します。
- sudo chown backup:backup /backups/mysql/object_storage_config.sh
- sudo chmod 600 /backups/mysql/object_storage_config.sh
私たちの object_storage_config.sh
これで、ファイルにアクセスできるのは backup
ユーザー。
リモートバックアップスクリプトの作成
オブジェクトストレージ構成ファイルができたので、先に進んでスクリプトの作成を開始できます。 次のスクリプトを作成します。
object_storage.py
:このスクリプトは、オブジェクトストレージAPIとやり取りして、バケットの作成、ファイルのアップロード、コンテンツのダウンロード、古いバックアップの整理を行います。 他のスクリプトは、リモートオブジェクトストレージアカウントと対話する必要があるときはいつでもこのスクリプトを呼び出します。remote-backup-mysql.sh
:このスクリプトは、ファイルを暗号化して単一のアーティファクトに圧縮し、それをリモートオブジェクトストアにアップロードすることで、MySQLデータベースをバックアップします。 毎日の初めに完全バックアップを作成し、その後は1時間ごとに増分バックアップを作成します。 30日より古いリモートバケットからすべてのファイルを自動的に削除します。download-day.sh
:このスクリプトを使用すると、特定の日に関連付けられているすべてのバックアップをダウンロードできます。 バックアップスクリプトは毎朝完全バックアップを作成し、その後1日を通して増分バックアップを作成するため、このスクリプトは1時間ごとのチェックポイントに復元するために必要なすべてのアセットをダウンロードできます。
上記の新しいスクリプトに加えて、 extract-mysql.sh
と prepare-mysql.sh
ファイルの復元に役立つ前のガイドのスクリプト。 このチュートリアルのリポジトリにあるスクリプトは、GitHubでいつでも表示できます。 以下の内容をコピーして貼り付けたくない場合は、次のように入力して、GitHubから新しいファイルを直接ダウンロードできます。
- cd /tmp
- curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/object_storage.py
- curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/remote-backup-mysql.sh
- curl -LO https://raw.githubusercontent.com/do-community/ubuntu-1604-mysql-backup/master/download-day.sh
ダウンロード後にスクリプトを調べて、スクリプトが正常に取得されたこと、およびスクリプトが実行するアクションを承認していることを確認してください。 満足している場合は、スクリプトを実行可能としてマークしてから、スクリプトをに移動します /usr/local/bin
次のように入力してディレクトリを作成します。
- chmod +x /tmp/{remote-backup-mysql.sh,download-day.sh,object_storage.py}
- sudo mv /tmp/{remote-backup-mysql.sh,download-day.sh,object_storage.py} /usr/local/bin
次に、これらの各スクリプトを設定し、詳細に説明します。
object_storage.pyスクリプトを作成します
ダウンロードしなかった場合 object_storage.py
GitHubからのスクリプト、で新しいファイルを作成します /usr/local/bin
と呼ばれるディレクトリ object_storage.py
:
- sudo nano /usr/local/bin/object_storage.py
スクリプトの内容をコピーしてファイルに貼り付けます。
#!/usr/bin/env python3
import argparse
import os
import sys
from datetime import datetime, timedelta
import boto3
import pytz
from botocore.client import ClientError, Config
from dateutil.parser import parse
# "backup_bucket" must be a universally unique name, so choose something
# specific to your setup.
# The bucket will be created in your account if it does not already exist
backup_bucket = os.environ['MYBUCKETNAME']
access_key = os.environ['MYACCESSKEY']
secret_key = os.environ['MYSECRETKEY']
endpoint_url = os.environ['MYENDPOINTURL']
region_name = os.environ['MYREGIONNAME']
class Space():
def __init__(self, bucket):
self.session = boto3.session.Session()
self.client = self.session.client('s3',
region_name=region_name,
endpoint_url=endpoint_url,
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
config=Config(signature_version='s3')
)
self.bucket = bucket
self.paginator = self.client.get_paginator('list_objects')
def create_bucket(self):
try:
self.client.head_bucket(Bucket=self.bucket)
except ClientError as e:
if e.response['Error']['Code'] == '404':
self.client.create_bucket(Bucket=self.bucket)
elif e.response['Error']['Code'] == '403':
print("The bucket name \"{}\" is already being used by "
"someone. Please try using a different bucket "
"name.".format(self.bucket))
sys.exit(1)
else:
print("Unexpected error: {}".format(e))
sys.exit(1)
def upload_files(self, files):
for filename in files:
self.client.upload_file(Filename=filename, Bucket=self.bucket,
Key=os.path.basename(filename))
print("Uploaded {} to \"{}\"".format(filename, self.bucket))
def remove_file(self, filename):
self.client.delete_object(Bucket=self.bucket,
Key=os.path.basename(filename))
def prune_backups(self, days_to_keep):
oldest_day = datetime.now(pytz.utc) - timedelta(days=int(days_to_keep))
try:
# Create an iterator to page through results
page_iterator = self.paginator.paginate(Bucket=self.bucket)
# Collect objects older than the specified date
objects_to_prune = [filename['Key'] for page in page_iterator
for filename in page['Contents']
if filename['LastModified'] < oldest_day]
except KeyError:
# If the bucket is empty
sys.exit()
for object in objects_to_prune:
print("Removing \"{}\" from {}".format(object, self.bucket))
self.remove_file(object)
def download_file(self, filename):
self.client.download_file(Bucket=self.bucket,
Key=filename, Filename=filename)
def get_day(self, day_to_get):
try:
# Attempt to parse the date format the user provided
input_date = parse(day_to_get)
except ValueError:
print("Cannot parse the provided date: {}".format(day_to_get))
sys.exit(1)
day_string = input_date.strftime("-%m-%d-%Y_")
print_date = input_date.strftime("%A, %b. %d %Y")
print("Looking for objects from {}".format(print_date))
try:
# create an iterator to page through results
page_iterator = self.paginator.paginate(Bucket=self.bucket)
objects_to_grab = [filename['Key'] for page in page_iterator
for filename in page['Contents']
if day_string in filename['Key']]
except KeyError:
print("No objects currently in bucket")
sys.exit()
if objects_to_grab:
for object in objects_to_grab:
print("Downloading \"{}\" from {}".format(object, self.bucket))
self.download_file(object)
else:
print("No objects found from: {}".format(print_date))
sys.exit()
def is_valid_file(filename):
if os.path.isfile(filename):
return filename
else:
raise argparse.ArgumentTypeError("File \"{}\" does not exist."
.format(filename))
def parse_arguments():
parser = argparse.ArgumentParser(
description='''Client to perform backup-related tasks with
object storage.''')
subparsers = parser.add_subparsers()
# parse arguments for the "upload" command
parser_upload = subparsers.add_parser('upload')
parser_upload.add_argument('files', type=is_valid_file, nargs='+')
parser_upload.set_defaults(func=upload)
# parse arguments for the "prune" command
parser_prune = subparsers.add_parser('prune')
parser_prune.add_argument('--days-to-keep', default=30)
parser_prune.set_defaults(func=prune)
# parse arguments for the "download" command
parser_download = subparsers.add_parser('download')
parser_download.add_argument('filename')
parser_download.set_defaults(func=download)
# parse arguments for the "get_day" command
parser_get_day = subparsers.add_parser('get_day')
parser_get_day.add_argument('day')
parser_get_day.set_defaults(func=get_day)
return parser.parse_args()
def upload(space, args):
space.upload_files(args.files)
def prune(space, args):
space.prune_backups(args.days_to_keep)
def download(space, args):
space.download_file(args.filename)
def get_day(space, args):
space.get_day(args.day)
def main():
args = parse_arguments()
space = Space(bucket=backup_bucket)
space.create_bucket()
args.func(space, args)
if __name__ == '__main__':
main()
このスクリプトは、オブジェクトストレージアカウント内のバックアップを管理する役割を果たします。 ファイルのアップロード、ファイルの削除、古いバックアップの整理、オブジェクトストレージからのファイルのダウンロードを行うことができます。 他のスクリプトは、オブジェクトストレージAPIと直接対話するのではなく、ここで定義された機能を使用してリモートリソースと対話します。 定義するコマンドは次のとおりです。
upload
:引数として渡される各ファイルをオブジェクトストレージにアップロードします。 複数のファイルを指定できます。download
:引数として渡されるリモートオブジェクトストレージから単一のファイルをダウンロードします。prune
:オブジェクトの保存場所から、特定の経過時間より古いすべてのファイルを削除します。 デフォルトでは、これにより30日より古いファイルが削除されます。 これを調整するには、--days-to-keep
呼び出すときのオプションprune
.get_day
:標準の日付形式(日付に空白が含まれている場合は引用符を使用)を使用して引数としてダウンロードする日を渡すと、ツールはそれを解析し、その日付からすべてのファイルをダウンロードしようとします。
スクリプトは環境変数からオブジェクトストレージのクレデンシャルとバケット名を読み取ろうとするため、これらが環境変数から入力されていることを確認する必要があります。 object_storage_config.sh
を呼び出す前にファイル object_storage.py
脚本。
終了したら、ファイルを保存して閉じます。
次に、まだ実行していない場合は、次のように入力してスクリプトを実行可能にします。
- sudo chmod +x /usr/local/bin/object_storage.py
今では object_storage.py
スクリプトはAPIと対話するために使用でき、それを使用してファイルをバックアップおよびダウンロードするBashスクリプトを作成できます。
remote-backup-mysql.shスクリプトを作成します
次に、 remote-backup-mysql.sh
脚本。 これにより、元の機能と同じ機能の多くが実行されます backup-mysql.sh
より基本的な組織構造(ローカルファイルシステムでバックアップを維持する必要がないため)とオブジェクトストレージにアップロードするためのいくつかの追加手順を備えたローカルバックアップスクリプト。
リポジトリからスクリプトをダウンロードしなかった場合は、というファイルを作成して開きます。 remote-backup-mysql.sh
の中に /usr/local/bin
ディレクトリ:
- sudo nano /usr/local/bin/remote-backup-mysql.sh
内部に、次のスクリプトを貼り付けます。
#!/bin/bash
export LC_ALL=C
days_to_keep=30
backup_owner="backup"
parent_dir="/backups/mysql"
defaults_file="/etc/mysql/backup.cnf"
working_dir="${parent_dir}/working"
log_file="${working_dir}/backup-progress.log"
encryption_key_file="${parent_dir}/encryption_key"
storage_configuration_file="${parent_dir}/object_storage_config.sh"
now="$(date)"
now_string="$(date -d"${now}" +%m-%d-%Y_%H-%M-%S)"
processors="$(nproc --all)"
# Use this to echo to standard error
error () {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
exit 1
}
trap 'error "An unexpected error occurred."' ERR
sanity_check () {
# Check user running the script
if [ "$(id --user --name)" != "$backup_owner" ]; then
error "Script can only be run as the \"$backup_owner\" user"
fi
# Check whether the encryption key file is available
if [ ! -r "${encryption_key_file}" ]; then
error "Cannot read encryption key at ${encryption_key_file}"
fi
# Check whether the object storage configuration file is available
if [ ! -r "${storage_configuration_file}" ]; then
error "Cannot read object storage configuration from ${storage_configuration_file}"
fi
# Check whether the object storage configuration is set in the file
source "${storage_configuration_file}"
if [ -z "${MYACCESSKEY}" ] || [ -z "${MYSECRETKEY}" ] || [ -z "${MYBUCKETNAME}" ]; then
error "Object storage configuration are not set properly in ${storage_configuration_file}"
fi
}
set_backup_type () {
backup_type="full"
# Grab date of the last backup if available
if [ -r "${working_dir}/xtrabackup_info" ]; then
last_backup_date="$(date -d"$(grep start_time "${working_dir}/xtrabackup_info" | cut -d' ' -f3)" +%s)"
else
last_backup_date=0
fi
# Grab today's date, in the same format
todays_date="$(date -d "$(date -d "${now}" "+%D")" +%s)"
# Compare the two dates
(( $last_backup_date == $todays_date ))
same_day="${?}"
# The first backup each new day will be a full backup
# If today's date is the same as the last backup, take an incremental backup instead
if [ "$same_day" -eq "0" ]; then
backup_type="incremental"
fi
}
set_options () {
# List the xtrabackup arguments
xtrabackup_args=(
"--defaults-file=${defaults_file}"
"--backup"
"--extra-lsndir=${working_dir}"
"--compress"
"--stream=xbstream"
"--encrypt=AES256"
"--encrypt-key-file=${encryption_key_file}"
"--parallel=${processors}"
"--compress-threads=${processors}"
"--encrypt-threads=${processors}"
"--slave-info"
)
set_backup_type
# Add option to read LSN (log sequence number) if taking an incremental backup
if [ "$backup_type" == "incremental" ]; then
lsn=$(awk '/to_lsn/ {print $3;}' "${working_dir}/xtrabackup_checkpoints")
xtrabackup_args+=( "--incremental-lsn=${lsn}" )
fi
}
rotate_old () {
# Remove previous backup artifacts
find "${working_dir}" -name "*.xbstream" -type f -delete
# Remove any backups from object storage older than 30 days
/usr/local/bin/object_storage.py prune --days-to-keep "${days_to_keep}"
}
take_backup () {
find "${working_dir}" -type f -name "*.incomplete" -delete
xtrabackup "${xtrabackup_args[@]}" --target-dir="${working_dir}" > "${working_dir}/${backup_type}-${now_string}.xbstream.incomplete" 2> "${log_file}"
mv "${working_dir}/${backup_type}-${now_string}.xbstream.incomplete" "${working_dir}/${backup_type}-${now_string}.xbstream"
}
upload_backup () {
/usr/local/bin/object_storage.py upload "${working_dir}/${backup_type}-${now_string}.xbstream"
}
main () {
mkdir -p "${working_dir}"
sanity_check && set_options && rotate_old && take_backup && upload_backup
# Check success and print message
if tail -1 "${log_file}" | grep -q "completed OK"; then
printf "Backup successful!\n"
printf "Backup created at %s/%s-%s.xbstream\n" "${working_dir}" "${backup_type}" "${now_string}"
else
error "Backup failure! If available, check ${log_file} for more information"
fi
}
main
このスクリプトは、実際のMySQLバックアップ手順を処理し、バックアップスケジュールを制御し、リモートストレージから古いバックアップを自動的に削除します。 手元に残しておくバックアップの日数を選択するには、 days_to_keep
変数。
地元の backup-mysql.sh
前回の記事で使用したスクリプトは、毎日のバックアップ用に個別のディレクトリを維持していました。 バックアップはリモートで保存するため、バックアップ専用のディスク容量を最小限に抑えるために、最新のバックアップのみをローカルに保存します。 以前のバックアップは、復元の必要に応じてオブジェクトストレージからダウンロードできます。
前のスクリプトと同様に、いくつかの基本的な要件が満たされていることを確認し、実行するバックアップの種類を構成した後、各バックアップを暗号化して1つのファイルアーカイブに圧縮します。 以前のバックアップファイルは、ローカルファイルシステムおよびで定義された値よりも古いリモートバックアップから削除されます。 days_to_keep
削除されます。
終了したら、ファイルを保存して閉じます。 その後、次のように入力して、スクリプトが実行可能であることを確認します。
- sudo chmod +x /usr/local/bin/remote-backup-mysql.sh
このスクリプトは、 backup-mysql.sh
このシステムのスクリプトを使用して、ローカルバックアップからリモートバックアップに切り替えます。
download-day.shスクリプトを作成します
最後に、ダウンロードまたは作成します download-day.sh
内のスクリプト /usr/local/bin
ディレクトリ。 このスクリプトを使用して、特定の日に関連付けられているすべてのバックアップをダウンロードできます。
以前にダウンロードしていない場合は、テキストエディタでスクリプトファイルを作成します。
- sudo nano /usr/local/bin/download-day.sh
中に、次の内容を貼り付けます。
#!/bin/bash
export LC_ALL=C
backup_owner="backup"
storage_configuration_file="/backups/mysql/object_storage_config.sh"
day_to_download="${1}"
# Use this to echo to standard error
error () {
printf "%s: %s\n" "$(basename "${BASH_SOURCE}")" "${1}" >&2
exit 1
}
trap 'error "An unexpected error occurred."' ERR
sanity_check () {
# Check user running the script
if [ "$(id --user --name)" != "$backup_owner" ]; then
error "Script can only be run as the \"$backup_owner\" user"
fi
# Check whether the object storage configuration file is available
if [ ! -r "${storage_configuration_file}" ]; then
error "Cannot read object storage configuration from ${storage_configuration_file}"
fi
# Check whether the object storage configuration is set in the file
source "${storage_configuration_file}"
if [ -z "${MYACCESSKEY}" ] || [ -z "${MYSECRETKEY}" ] || [ -z "${MYBUCKETNAME}" ]; then
error "Object storage configuration are not set properly in ${storage_configuration_file}"
fi
}
main () {
sanity_check
/usr/local/bin/object_storage.py get_day "${day_to_download}"
}
main
このスクリプトを呼び出すと、特定の日からすべてのアーカイブをダウンロードできます。 毎日が完全バックアップで始まり、その日の残りの時間に増分バックアップが蓄積されるため、これにより、1時間ごとのスナップショットに復元するために必要なすべての関連ファイルがダウンロードされます。
スクリプトは、日付または日である単一の引数を取ります。 Pythonのdateutil.parser.parse関数を使用して、引数として提供された日付文字列を読み取って解釈します。 この関数はかなり柔軟性があり、たとえば「Friday」などの相対文字列など、さまざまな形式の日付を解釈できます。 ただし、あいまいさを避けるために、より明確に定義された日付を使用するのが最善です。 使用する形式に空白が含まれている場合は、必ず日付を引用符で囲んでください。
続行する準備ができたら、ファイルを保存して閉じます。 次のように入力して、スクリプトを実行可能にします。
- sudo chmod +x /usr/local/bin/download-day.sh
復元する特定の日付のバックアップファイルをオブジェクトストレージからダウンロードできるようになりました。
リモートMySQLバックアップおよびダウンロードスクリプトのテスト
スクリプトが配置されたので、テストして期待どおりに機能することを確認する必要があります。
フルバックアップを実行する
を呼び出すことから始めます remote-mysql-backup.sh
スクリプトと backup
ユーザー。 このコマンドを実行するのはこれが初めてなので、MySQLデータベースの完全バックアップを作成する必要があります。
- sudo -u backup remote-backup-mysql.sh
注:選択したバケット名がすでに使用されていることを示すエラーが表示された場合は、別の名前を選択する必要があります。 の値を変更します MYBUCKETNAME
の中に /backups/mysql/object_storage_config.sh
ファイルを作成し、ローカルバックアップディレクトリを削除します(sudo rm -rf /backups/mysql/working
)スクリプトが新しいバケット名で完全バックアップを試行できるようにします。 準備ができたら、上記のコマンドを再実行して再試行してください。
すべてがうまくいけば、次のような出力が表示されます。
OutputUploaded /backups/mysql/working/full-10-17-2017_19-09-30.xbstream to "your_bucket_name"
Backup successful!
Backup created at /backups/mysql/working/full-10-17-2017_19-09-30.xbstream
これは、完全バックアップが /backups/mysql/working
ディレクトリ。 また、で定義されたバケットを使用してリモートオブジェクトストレージにアップロードされています object_storage_config.sh
ファイル。
内を見ると /backups/mysql/working
ディレクトリ、私たちはによって生成されたものと同様のファイルを見ることができます backup-mysql.sh
最後のガイドのスクリプト:
- ls /backups/mysql/working
Outputbackup-progress.log full-10-17-2017_19-09-30.xbstream xtrabackup_checkpoints xtrabackup_info
The backup-progress.log
ファイルには、 xtrabackup
コマンド、 xtrabackup_checkpoints
と xtrabackup_info
使用されるオプション、バックアップのタイプとスコープ、およびその他のメタデータに関する情報が含まれています。
増分バックアップを実行する
私たちに小さな変更を加えましょう equipment
最初のバックアップで見つからなかった追加のデータを作成するためのテーブル。 次のように入力して、テーブルに新しい行を入力できます。
- mysql -u root -p -e 'INSERT INTO playground.equipment (type, quant, color) VALUES ("sandbox", 4, "brown");'
データベースの管理者パスワードを入力して、新しいレコードを追加します。
これで、追加のバックアップを取ることができます。 スクリプトを再度呼び出すときは、(サーバーのクロックに従って)前のバックアップと同じ日である限り、増分バックアップを作成する必要があります。
- sudo -u backup remote-backup-mysql.sh
OutputUploaded /backups/mysql/working/incremental-10-17-2017_19-19-20.xbstream to "your_bucket_name"
Backup successful!
Backup created at /backups/mysql/working/incremental-10-17-2017_19-19-20.xbstream
上記の出力は、バックアップがローカルで同じディレクトリ内に作成され、オブジェクトストレージに再度アップロードされたことを示しています。 チェックすると /backups/mysql/working
ディレクトリに、新しいバックアップが存在し、前のバックアップが削除されていることがわかります。
- ls /backups/mysql/working
Outputbackup-progress.log incremental-10-17-2017_19-19-20.xbstream xtrabackup_checkpoints xtrabackup_info
ファイルはリモートでアップロードされるため、ローカルコピーを削除すると、使用されるディスクスペースの量を減らすのに役立ちます。
特定の日からバックアップをダウンロードする
バックアップはリモートに保存されるため、ファイルを復元する必要がある場合は、リモートファイルをプルダウンする必要があります。 これを行うには、 download-day.sh
脚本。
まず、ディレクトリを作成してから移動します。 backup
ユーザーは安全に次の場所に書き込むことができます。
- sudo -u backup mkdir /tmp/backup_archives
- cd /tmp/backup_archives
次に、 download-day.sh
スクリプトとして backup
ユーザー。 ダウンロードしたいアーカイブの日を渡します。 日付形式はかなり柔軟ですが、明確にすることをお勧めします。
- sudo -u backup download-day.sh "Oct. 17"
指定した日付と一致するアーカイブがある場合、それらは現在のディレクトリにダウンロードされます。
OutputLooking for objects from Tuesday, Oct. 17 2017
Downloading "full-10-17-2017_19-09-30.xbstream" from your_bucket_name
Downloading "incremental-10-17-2017_19-19-20.xbstream" from your_bucket_name
ファイルがローカルファイルシステムにダウンロードされていることを確認します。
- ls
Outputfull-10-17-2017_19-09-30.xbstream incremental-10-17-2017_19-19-20.xbstream
圧縮され、暗号化されたアーカイブが再びサーバーに戻ります。
バックアップを抽出して準備する
ファイルが収集されると、ローカルバックアップを処理したのと同じ方法でファイルを処理できます。
まず、合格 .xbstream
にファイル extract-mysql.sh
を使用したスクリプト backup
ユーザー:
- sudo -u backup extract-mysql.sh *.xbstream
これにより、アーカイブが復号化され、次のディレクトリに解凍されます。 restore
. そのディレクトリに入り、ファイルを準備します prepare-mysql.sh
脚本:
- cd restore
- sudo -u backup prepare-mysql.sh
OutputBackup looks to be fully prepared. Please check the "prepare-progress.log" file
to verify before continuing.
If everything looks correct, you can apply the restored files.
First, stop MySQL and move or remove the contents of the MySQL data directory:
sudo systemctl stop mysql
sudo mv /var/lib/mysql/ /tmp/
Then, recreate the data directory and copy the backup files:
sudo mkdir /var/lib/mysql
sudo xtrabackup --copy-back --target-dir=/tmp/backup_archives/restore/full-10-17-2017_19-09-30
Afterward the files are copied, adjust the permissions and restart the service:
sudo chown -R mysql:mysql /var/lib/mysql
sudo find /var/lib/mysql -type d -exec chmod 750 {} \;
sudo systemctl start mysql
の完全バックアップ /tmp/backup_archives/restore
これでディレクトリが準備されます。 出力の指示に従って、システム上のMySQLデータを復元できます。
バックアップデータをMySQLデータディレクトリに復元する
バックアップデータを復元する前に、現在のデータを邪魔にならない場所に移動する必要があります。
まず、MySQLをシャットダウンして、データベースが破損したり、データファイルを置き換えるときにサービスがクラッシュしたりしないようにします。
- sudo systemctl stop mysql
次に、現在のデータディレクトリをに移動できます /tmp
ディレクトリ。 このようにして、復元に問題が発生した場合に簡単に元に戻すことができます。 ファイルをに移動したので /tmp/mysql
前回の記事では、ファイルを次の場所に移動できます /tmp/mysql-remote
この時:
- sudo mv /var/lib/mysql/ /tmp/mysql-remote
次に、空を再作成します /var/lib/mysql
ディレクトリ:
- sudo mkdir /var/lib/mysql
これで、次のように入力できます xtrabackup
復元コマンド prepare-mysql.sh
バックアップファイルをにコピーするために提供されるコマンド /var/lib/mysql
ディレクトリ:
- sudo xtrabackup --copy-back --target-dir=/tmp/backup_archives/restore/full-10-17-2017_19-09-30
プロセスが完了したら、ディレクトリのアクセス許可と所有権を変更して、MySQLプロセスがアクセスできるようにします。
- sudo chown -R mysql:mysql /var/lib/mysql
- sudo find /var/lib/mysql -type d -exec chmod 750 {} \;
これが終了したら、MySQLを再起動し、データが適切に復元されていることを確認します。
- sudo systemctl start mysql
- mysql -u root -p -e 'SELECT * FROM playground.equipment;'
Output+----+---------+-------+--------+
| id | type | quant | color |
+----+---------+-------+--------+
| 1 | slide | 2 | blue |
| 2 | swing | 10 | yellow |
| 3 | sandbox | 4 | brown |
+----+---------+-------+--------+
データが利用可能であり、正常に復元されたことを示しています。
データを復元した後、戻って復元ディレクトリを削除することが重要です。 将来の増分バックアップは、準備ができたら完全バックアップに適用できないため、削除する必要があります。 さらに、セキュリティ上の理由から、バックアップディレクトリをディスク上で暗号化せずに放置しないでください。
- cd ~
- sudo rm -rf /tmp/backup_archives/restore
次回バックアップディレクトリのクリーンコピーが必要になったときに、バックアップアーカイブファイルからそれらを再度抽出できます。
バックアップを1時間ごとに実行するためのcronジョブの作成
作成しました cron
最後のガイドでデータベースをローカルに自動的にバックアップするジョブ。 新たに設置します cron
リモートバックアップを取り、ローカルバックアップジョブを無効にするジョブ。 必要に応じて、ローカルバックアップとリモートバックアップを簡単に切り替えることができます。 cron
スクリプト。
まず、というファイルを作成します remote-backup-mysql
の中に /etc/cron.hourly
ディレクトリ:
- sudo nano /etc/cron.hourly/remote-backup-mysql
内部では、私たちは私たちを呼び出します remote-backup-mysql.sh
スクリプトと backup
を介してユーザー systemd-cat
コマンド。これにより、出力を次の場所に記録できます。 journald
:
#!/bin/bash
sudo -u backup systemd-cat --identifier=remote-backup-mysql /usr/local/bin/remote-backup-mysql.sh
終了したら、ファイルを保存して閉じます。
新しいを有効にします cron
ジョブを操作し、を操作して古いものを無効にします executable
両方のファイルの許可ビット:
- sudo chmod -x /etc/cron.hourly/backup-mysql
- sudo chmod +x /etc/cron.hourly/remote-backup-mysql
スクリプトを手動で実行して、新しいリモートバックアップジョブをテストします。
- sudo /etc/cron.hourly/remote-backup-mysql
プロンプトが戻ったら、次のログエントリを確認できます。 journalctl
:
- sudo journalctl -t remote-backup-mysql
[seconary_label Output]
-- Logs begin at Tue 2017-10-17 14:28:01 UTC, end at Tue 2017-10-17 20:11:03 UTC. --
Oct 17 20:07:17 myserver remote-backup-mysql[31422]: Uploaded /backups/mysql/working/incremental-10-17-2017_22-16-09.xbstream to "your_bucket_name"
Oct 17 20:07:17 myserver remote-backup-mysql[31422]: Backup successful!
Oct 17 20:07:17 myserver remote-backup-mysql[31422]: Backup created at /backups/mysql/working/incremental-10-17-2017_20-07-13.xbstream
数時間後にもう一度チェックして、追加のバックアップがスケジュールどおりに作成されていることを確認してください。
抽出キーのバックアップ
処理する必要がある最後の考慮事項の1つは、暗号化キーをバックアップする方法です( /backups/mysql/encryption_key
).
このプロセスを使用してバックアップされたファイルを復元するには暗号化キーが必要ですが、データベースファイルと同じ場所に暗号化キーを保存すると、暗号化によって提供される保護が失われます。 このため、データベースサーバーに障害が発生した場合や再構築が必要な場合でもバックアップアーカイブを使用できるように、暗号化キーのコピーを別の場所に保持することが重要です。
データベース以外のファイルの完全なバックアップソリューションはこの記事の範囲外ですが、保管のためにキーをローカルコンピューターにコピーできます。 これを行うには、次のように入力してファイルの内容を表示します。
- sudo less /backups/mysql/encryption_key
ローカルコンピュータでテキストファイルを開き、その中に値を貼り付けます。 別のサーバーにバックアップを復元する必要がある場合は、ファイルの内容をにコピーします。 /backups/mysql/encryption_key
新しいマシンで、このガイドで概説されているシステムをセットアップしてから、提供されているスクリプトを使用して復元します。
結論
このガイドでは、MySQLデータベースの1時間ごとのバックアップを取り、それらをリモートオブジェクトストレージスペースに自動的にアップロードする方法について説明しました。 システムは毎朝完全バックアップを取り、その後は1時間ごとの増分バックアップを取り、1時間ごとのチェックポイントに復元する機能を提供します。 バックアップスクリプトが実行されるたびに、30日より古いオブジェクトストレージ内のバックアップをチェックし、それらを削除します。