アプリケーション整合性のあるバックアップを構成する

このドキュメントでは、Compute Engine Linux 仮想マシン(VM)インスタンスで実行されているセルフマネージド データベースのスケジュール設定されたアプリケーション整合性バックアップとポイントインタイム リカバリ(PITR)ワークフローを構成する方法について説明します。

IBM Db2、SAP HANA、MySQL、PostgreSQL などのステートフル データベース ワークロードをバックアップする場合、Backup and DR によって取得された標準のクラッシュ整合性スナップショットは、トランザクションが進行中のデータベースをキャプチャできます。このような未完了のトランザクションは、データを破損させ、テーブルを不整合な状態のままにし、クラッシュ復元時に長いデータベース修復ルーチンを必要とします。アプリケーション整合性のあるバックアップは、VM ゲスト エージェントと統合してデータベースを静止させ、必要に応じてファイル システムをフリーズさせてからスナップショットを作成することで、これらの問題を解決します。

始める前に

アプリケーション整合性バックアップを構成する前に、次のタスクを完了します。

必要なロール

アプリケーション整合性バックアップの構成に必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

前提条件

  1. Google Cloud コンソールのプロジェクト セレクタページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  2. プロジェクトで課金が有効になっていることを確認します。

    課金が有効になっていることを確認する方法をご覧ください

  3. Backup and DR API と Secret Manager API を有効にします。

    API を有効にする

  4. データベースのデータとログファイルが標準の永続ディスクに保存されていることを確認します。Google Cloud Hyperdisk ボリュームは、ゲスト フラッシュ オペレーションをサポートしていません。

  5. ポイントインタイム リカバリを構成する場合は、トランザクション ログとやり直しログを専用の別の Persistent Disk(/db2/ACT/log_archive にマウントするなど)にアーカイブするようにデータベースを構成します。

お客様所有スクリプト(BYOS)ゲスト フラッシュ フレームワークを使用する

Backup and DR は、Bring-Your-Own-Script(BYOS)ゲスト フラッシュ フレームワークを使用して、スナップショットが作成される前にデータベースを静止させます。ゲスト環境は、Linux VM インスタンスの /etc/google/snapshots/ ディレクトリにある 2 つのスクリプトに依存しています。

  • スナップショット前のスクリプト(/etc/google/snapshots/pre.sh): スナップショットが作成される前に実行されます。このスクリプトはデータベース オペレーションを静止させる必要があり、必要に応じてファイル システムをフリーズできます。
  • スナップショット後のスクリプト(/etc/google/snapshots/post.sh): スナップショットの作成後に実行されます。このスクリプトは、必要に応じてファイル システムのフリーズを解除し、データベース オペレーションを再開する必要があります。

データベース固有のスクリプト テンプレートの詳細については、データベースの種類別にサンプル スクリプトを確認するをご覧ください。

省略可: ファイル システムをフリーズしてフリーズ解除する

標準の Linux ユーティリティ fsfreeze を使用したファイル システムのフリーズは任意であり、必須ではありません。データベースを静止すると、アプリケーション レベルのトランザクションの整合性が確保されます。ただし、ファイル システム レベルで追加の一貫性が必要な場合は、必要に応じて、次のファイル システムのフリーズとフリーズ解除のコマンドをスクリプトに含めることができます。

VM の pre.sh スクリプトと post.sh スクリプトが、データベース オペレーションを一時停止せずにログボリュームのファイル システムのフリーズを処理するように構成されていることを確認します。

pre.sh にファイル システムのフリーズ指示を追加

ファイル システムをフリーズする場合は、データベースを静止させた後、pre.sh スクリプトの末尾に次の検出とフリーズのロジックを追加します。

# Discover local writeable mount points
MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

# FREEZE FILESYSTEMS (Optional)
for mnt in $MOUNT_POINTS; do
    if ! sudo fsfreeze -f "$mnt"; then
        logger "Error: Failed to freeze $mnt. Cleaning up..."
        # Attempt emergency thaw
        for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
        # Add your database-specific resume/cleanup commands here before exiting
        exit 1
    fi
    logger "Filesystem $mnt is frozen."
done

post.sh にファイル システムのフリーズ解除手順を追加

pre.sh でファイル システムをフリーズする場合は、データベースを再開する前に、post.sh スクリプトの先頭に次のフリーズ解除ロジックを追加します。

# Discover local writeable mount points
MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

# UNFREEZE FILESYSTEMS (Optional)
for mnt in $MOUNT_POINTS; do
    sudo fsfreeze -u "$mnt"
    logger "Filesystem $mnt is unfrozen."
done

Secret Manager で認証情報を動的に取得する

シェル スクリプト内に静的データベースの認証情報やパスワードをハードコードすることは避けてください。代わりに、Secret Manager を使用して、実行時に認証情報を動的に取得します。スクリプト内の静的パスワード変数を次のロジックに置き換えます。

# Fetch the database password from Secret Manager dynamically
DBPASSWORD=$(gcloud secrets versions access latest \
    --secret="SECRET_NAME" \
    --format='get(payload.data)' | tr -d '\n')

if [ $? -ne 0 ]; then
    logger "Critical Error: Unable to fetch the password from Secret Manager."
    exit 1
fi

SECRET_NAME は、Secret Manager のシークレットの名前に置き換えます。

データベース タイプ別にサンプル スクリプトを確認する

次のサンプルは、Linux インスタンスで実行されているサポート対象のデータベース エンジンの pre.shpost.sh の実装を提供します。

IBM Db2

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh
 # 1. Define Mount Points for the Database
 MOUNT_POINTS=("DATA_MOUNT_POINT" "LOG_MOUNT_POINT")
 logger "BYOS Framework: Starting pre-snapshot script."

 # 2. QUIESCE DATABASE (Generic Hook)
 # Replace with DB-specific command (e.g., 'db2 set write suspend')
 logger "Suspending Database I/O..."
 # [INSERT DB QUIESCE COMMAND HERE]

 # 3. FREEZE FILESYSTEMS (Optional)
 for mnt in "${MOUNT_POINTS[@]}"; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt."
         # Attempt emergency thaw
         for thaw_mnt in "${MOUNT_POINTS[@]}"; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         # [INSERT DB RESUME COMMAND HERE]
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh
 MOUNT_POINTS=("DATA_MOUNT_POINT" "LOG_MOUNT_POINT")
 logger "BYOS Framework: Starting post-snapshot script."

 # 1. UNFREEZE FILESYSTEMS (Optional)
 for mnt in "${MOUNT_POINTS[@]}"; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done

 # 2. RESUME DATABASE (Generic Hook)
 # Replace with DB-specific command (e.g., 'db2 set write resume')
 logger "Resuming Database I/O..."
 # [INSERT DB RESUME COMMAND HERE]
 logger "BYOS Framework: Cleanup complete."

Oracle

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 sudo mkdir -p /etc/google/snapshots
 sudo tee /etc/google/snapshots/pre.sh > /dev/null << 'EOF'
 #!/bin/bash
 # Place Oracle (ASM) into hot backup mode before Backup and DR captures disks
 su - oracle -c "sqlplus -s / as sysdba" << 'SQL'
 WHENEVER SQLERROR EXIT FAILURE;
 ALTER DATABASE BEGIN BACKUP;
 EXIT;
 SQL

 if [ $? -ne 0 ]; then
   echo "Error: Failed to place Oracle in backup mode. Aborting snapshot." >&2
   exit 1
 fi
 EOF

 sudo chmod 750 /etc/google/snapshots/pre.sh

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 sudo tee /etc/google/snapshots/post.sh > /dev/null << 'EOF'
 #!/bin/bash
 # Release Oracle from backup mode and archive current redo log to +FRA
 su - oracle -c "sqlplus -s / as sysdba" << 'SQL'
 WHENEVER SQLERROR EXIT FAILURE;
 ALTER DATABASE END BACKUP;
 ALTER SYSTEM ARCHIVE LOG CURRENT;
 EXIT;
 SQL

 if [ $? -ne 0 ]; then
   echo "Warning: Failed to execute ALTER DATABASE END BACKUP." >&2
   exit 1
 fi
 EOF

 sudo chmod 750 /etc/google/snapshots/post.sh

SAP HANA

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh

 DISK_ARG="$1"

 # 1. Configuration & Discovery
 DBSID="DBSID"
 DBADM="DBADM"
 ID_FILE="/tmp/hana_snapshot_id_$DBSID"
 HDB_KEY="HDB_KEY"

 if [[ "$DISK_ARG" == "," ]] || [[ "$DISK_ARG" == "1/0" ]] || [[ "$DISK_ARG" == "sda" ]]; then
     # Dynamically discover all local writeable mount points for full VM image consistency
     # Filters out pseudo, temporary, and read-only filesystems
     MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

     logger "SAP HANA Full VM BYOS: Starting pre-snapshot script for $DBSID."

     # 2. QUIESCE DATABASE (Create SAP HANA Snapshot)
     logger "SAP HANA Full VM BYOS: Creating database snapshot..."

     # Determine HANA Version
     # Versions 2.0+ use 'FOR FULL SYSTEM' syntax
     HANAVERSION=$(su - $DBADM -c "HDB version" | grep "version:" | awk '{print $2}' | cut -d'.' -f1)

     if [ "$HANAVERSION" = "1" ]; then
         SQL="BACKUP DATA CREATE SNAPSHOT COMMENT 'SNAPSHOT_$(date +%Y%m%d)'"
     else
         SQL="BACKUP DATA FOR FULL SYSTEM CREATE SNAPSHOT COMMENT 'SNAPSHOT_$(date +%Y%m%d)'"
     fi

     # Execute the snapshot command via hdbsql
     su - $DBADM -c "hdbsql -j -U $HDB_KEY \"$SQL\""
     if [ $? -ne 0 ]; then
         logger "Error: Failed to create SAP HANA snapshot."
         exit 1
     fi

     # Retrieve the BACKUP_ID for the prepared snapshot
     ID=$(su - $DBADM -c "hdbsql -j -t -U $HDB_KEY \"SELECT BACKUP_ID FROM M_BACKUP_CATALOG WHERE STATE_NAME = 'prepared' ORDER BY SYS_START_TIME DESC\"" | head -n 2 | tr -d '"' | tail -n 1)

     if [ -z "$ID" ]; then
         logger "Error: Could not retrieve BACKUP_ID for prepared snapshot."
         exit 1
     fi

     echo "$ID" > "$ID_FILE"
     logger "SAP HANA Full VM BYOS: Database snapshot prepared with ID $ID."
 fi

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh

 DISK_ARG="$1"

 # 1. Configuration & Discovery
 DBSID="DBSID"
 DBADM="DBADM"
 ID_FILE="/tmp/hana_snapshot_id_$DBSID"
 HDB_KEY="HDB_KEY"

 if [[ "$DISK_ARG" == "," ]] || [[ "$DISK_ARG" == "1/0" ]] || [[ "$DISK_ARG" == "sda" ]]; then
     # Discover all local writeable mount points to perform unfreeze
     MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

     logger "SAP HANA Full VM BYOS: Starting post-snapshot script for $DBSID."

     # 3. RESUME DATABASE (Close SAP HANA Snapshot)
     if [ -f "$ID_FILE" ]; then
         ID=$(cat "$ID_FILE")
         logger "SAP HANA Full VM BYOS: Closing database snapshot ID $ID..."

         # Determine HANA version for correct syntax
         HANAVERSION=$(su - $DBADM -c "HDB version" | grep "version:" | awk '{print $2}' | cut -d'.' -f1)

         if [ "$HANAVERSION" = "1" ]; then
             SQL="BACKUP DATA CLOSE SNAPSHOT BACKUP_ID $ID SUCCESSFUL 'SNAPSHOT_COMPLETED'"
         else
             SQL="BACKUP DATA FOR FULL SYSTEM CLOSE SNAPSHOT BACKUP_ID $ID SUCCESSFUL 'SNAPSHOT_COMPLETED'"
         fi

         # Execute the close snapshot command
         RESULT=$(su - $DBADM -c "hdbsql -j -U $HDB_KEY \"$SQL\"")
         if [ $? -ne 0 ]; then
             logger "Error: Failed to close SAP HANA snapshot. $RESULT"
         else
             logger "SAP HANA Full VM BYOS: Database snapshot closed successfully."
         fi

         # Cleanup the temporary ID file
         rm -f "$ID_FILE"
     else
         logger "Error: Snapshot ID file not found. Manual intervention required to close HANA snapshot."
     fi

     logger "SAP HANA Full VM BYOS: Cleanup complete."

 else
     MOUNT_POINTS="/hanabackup"

     for mnt in $MOUNT_POINTS; do
         sudo fsfreeze -u "$mnt"
         logger "Filesystem $mnt is unfrozen."
     done
 fi

次のように置き換えます。

  • DBSID: 大文字の SAP HANA システム識別子(SID)。
  • DBADM: SAP HANA 管理者の OS ユーザー(<sid>adm など)。
  • HDB_KEY: データベース アクセス用に構成された SAP HANA ユーザー ストアキー。

SAP ASE

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh
 # 1. Configuration
 OSUSER="OS_USER"
 SYB_SERVER="SYB_SERVER_NAME"
 SYB_USER="SYB_USER"
 SYB_PASS="SYB_PASSWORD"
 SYB_DBLIST="DATABASE_LIST"
 TAG_NAME="SNAPSHOT_$(date +%Y%m%d)"
 MANIFEST_DIR="/var/tmp/sybase_manifests" # Directory for manifest files
 # 2. Discovery
 # Dynamically discover local writeable mount points
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "Sybase Full VM BYOS: Starting pre-snapshot script."
 # 3. QUIESCE DATABASE
 mkdir -p "$MANIFEST_DIR"
 chown $OSUSER "$MANIFEST_DIR"

 logger "Sybase Full VM BYOS: Quiescing databases: $SYB_DBLIST..."
 # Command logic from act_sybase_pre.sh
 # We use 'hold' to suspend activity and create the manifest file
 su - $OSUSER -c "isql -U$SYB_USER -P$SYB_PASS -S$SYB_SERVER -X --retserverror" <<EOF
 quiesce database $TAG_NAME hold $SYB_DBLIST for external dump to '$MANIFEST_DIR/manifest_$TAG_NAME.dat' with override
 go
 exit
 EOF
 if [ $? -ne 0 ]; then
     logger "Error: Failed to quiesce Sybase databases."
     exit 1
 fi
 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt."
         # Attempt emergency thaw
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         # Release the database quiesce
         su - $OSUSER -c "isql -U$SYB_USER -P$SYB_PASS -S$SYB_SERVER -X" <<EOF
         quiesce database $TAG_NAME release
         go
         exit
 EOF
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh

 # 1. Configuration
 OSUSER="OS_USER"
 SYB_SERVER="SYB_SERVER_NAME"
 SYB_USER="SYB_USER"
 SYB_PASS="SYB_PASSWORD"
 TAG_NAME="SNAPSHOT_$(date +%Y%m%d)"
 MANIFEST_DIR="/var/tmp/sybase_manifests"

 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "Sybase Full VM BYOS: Starting post-snapshot script."

 # 3. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done

 # 4. RESUME DATABASE
 logger "Sybase Full VM BYOS: Releasing databases for tag $TAG_NAME..."

 # Command logic from act_sybase_post.sh
 su - $OSUSER -c "isql -U$SYB_USER -P$SYB_PASS -S$SYB_SERVER -X" <<EOF
 use master
 go
 quiesce database $TAG_NAME release
 go
 exit
 EOF

 if [ $? -ne 0 ]; then
     logger "Error: Failed to release Sybase databases."
 else
     logger "Sybase Full VM BYOS: Databases released successfully."
     # Cleanup manifest
     rm -f "$MANIFEST_DIR/manifest_$TAG_NAME.dat"
 fi

 logger "Sybase Full VM BYOS: Cleanup complete."

次のように置き換えます。

  • OS_USER: SAP ASE を実行しているオペレーティング システム ユーザー(sybase など)。
  • SYB_SERVER_NAME: SAP ASE サーバー名。
  • SYB_USER: データベースを休止する権限を持つデータベース ユーザー。
  • SYB_PASSWORD: データベース ユーザーのパスワード(または Secret Manager を使用して動的に取得)。
  • DATABASE_LIST: 休止するデータベースのカンマ区切りのリスト。

SAP IQ

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh

 # 1. Configuration
 OSUSER="OS_USER"
 DB_NAME="DB_NAME"
 CONN_STR="uid=DB_USER;pwd=DB_PASSWORD;dbn=$DB_NAME;eng=ENGINE_NAME"
 BKP_DIR="/var/tmp/sybaseiq_bkp"
 FULL_BKP_FILE="$BKP_DIR/FULL_VIR_DEC"

 # 2. Discovery
 # Dynamically discover all local writeable mount points for full VM consistency
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "SybaseIQ Full VM BYOS: Starting pre-snapshot script."

 # 3. QUIESCE DATABASE (Virtual Decoupled Backup)
 mkdir -p "$BKP_DIR"
 chown $OSUSER "$BKP_DIR"

 logger "SybaseIQ Full VM BYOS: Preparing virtual decoupled backup..."

 # Execute the quiesce command logic from act_sybaseiq_pre.sh
 su -m $OSUSER -c "dbisql -nogui -c '$CONN_STR' \"BACKUP DATABASE FULL VIRTUAL DECOUPLED TO '$FULL_BKP_FILE'\""

 if [ $? -ne 0 ]; then
     logger "Error: Failed to freeze (not able to take full_vir_dec backup)."
     exit 1
 fi

 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt."
         # Attempt emergency thaw
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         # Cleanup quiesce file as backup is invalid
         rm -f "$FULL_BKP_FILE"
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh
 # 1. Configuration
 OSUSER="OS_USER"
 DB_NAME="DB_NAME"
 CONN_STR="uid=DB_USER;pwd=DB_PASSWORD;dbn=$DB_NAME;eng=ENGINE_NAME"
 BKP_DIR="/var/tmp/sybaseiq_bkp"
 FULL_BKP_FILE="$BKP_DIR/FULL_VIR_DEC"
 INC_BKP_FILE="$BKP_DIR/INC_BKP"
 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)
 logger "SybaseIQ Full VM BYOS: Starting post-snapshot script."
 # 3. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done
 # 4. RESUME DATABASE (Post-Snapshot Cleanup)
 logger "SybaseIQ Full VM BYOS: Performing incremental since full backup..."
 # Logic from act_sybaseiq_post.sh to finish the decoupled sequence
 su -m $OSUSER -c "dbisql -nogui -c '$CONN_STR' \"BACKUP DATABASE INCREMENTAL SINCE FULL TO '$INC_BKP_FILE'\""
 if [ $? -ne 0 ]; then
     logger "Error: Failed post-quiesce incremental backup."
 fi
 # Remove temporary files created during quiesce
 rm -f "$FULL_BKP_FILE"*
 logger "SybaseIQ Full VM BYOS: Cleanup complete."

次のように置き換えます。

  • OS_USER: SAP IQ を実行しているオペレーティング システム ユーザー(sybiq など)。
  • DB_NAME: SAP IQ データベース名。
  • DB_USER: DBA 権限を持つデータベース ユーザー。
  • DB_PASSWORD: データベース ユーザーのパスワード(または Secret Manager を使用して動的に取得)。
  • ENGINE_NAME: SAP IQ データベース エンジンの名前。

SAP MaxDB

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh

 # 1. Configuration
 DBSID="DBSID"
 OSUSER="OS_USER"
 MAXDB_KEY="-user DBM_USER,DBM_PASSWORD"
 AUTOLOG_TMPLT="LOG_BACKUP"

 # 2. Discovery
 # Dynamically discover all local writeable mount points for full VM consistency
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "MaxDB Full VM BYOS: Starting pre-snapshot script for $DBSID."

 # 3. QUIESCE DATABASE
 # Optional: Trigger a log backup first to ensure point-in-time recovery readiness
 logger "MaxDB Full VM BYOS: Triggering log backup..."
 su -m $OSUSER -c "dbmcli -d $DBSID $MAXDB_KEY -uUTL -c backup_start $AUTOLOG_TMPLT LOG"

 # Suspend logwriter to quiesce the database
 logger "MaxDB Full VM BYOS: Suspending logwriter..."
 su -m $OSUSER -c "dbmcli -d $DBSID $MAXDB_KEY -uUTL -c util_execute suspend logwriter"
 if [ $? -ne 0 ]; then
     logger "Error: Failed to suspend MaxDB logwriter."
     exit 1
 fi

 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt."
         # Attempt emergency thaw
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         # Resume the logwriter as the backup is no longer consistent
         su -m $OSUSER -c "dbmcli -d $DBSID $MAXDB_KEY -uUTL -c util_execute resume logwriter"
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh

 # 1. Configuration
 DBSID="DBSID"
 OSUSER="OS_USER"
 MAXDB_KEY="-user DBM_USER,DBM_PASSWORD"

 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "MaxDB Full VM BYOS: Starting post-snapshot script for $DBSID."

 # 3. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done

 # 4. RESUME DATABASE
 logger "MaxDB Full VM BYOS: Resuming logwriter..."
 su -m $OSUSER -c "dbmcli -d $DBSID $MAXDB_KEY -uUTL -c util_execute resume logwriter"
 if [ $? -ne 0 ]; then
     logger "Error: Failed to resume MaxDB logwriter."
 else
     logger "MaxDB Full VM BYOS: Logwriter resumed successfully."
 fi

 logger "MaxDB Full VM BYOS: Cleanup complete."

次のように置き換えます。

  • DBSID: 大文字の SAP MaxDB システム識別子(SID)。
  • OS_USER: MaxDB を実行しているオペレーティング システム ユーザー(sdba など)。
  • DBM_USER: データベース マネージャー(DBM)ユーザー。
  • DBM_PASSWORD: DBM ユーザーのパスワード(または、保存された DBM キー -k KEY_NAME を使用)。

PostgreSQL

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # 1. Configuration
 OSUSER="OS_USER"
 PG_HOME="PG_HOME"
 DBUSER="DB_USER"
 PORT=PORT_NUMBER
 DBNAME="DB_NAME"
 FIFO="/tmp/pg_backup_fifo_$PORT"
 PID_FILE="/tmp/pg_backup_pid_$PORT"
 ACT_JOBNAME="SNAPSHOT_$(date +%Y%m%d%H%M%S)"

 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)
 export PATH=$PG_HOME/bin:$PATH

 logger "PostgreSQL Full VM BYOS: Starting pre-snapshot script."

 # 3. QUIESCE DATABASE (Session-Bound)
 rm -f "$FIFO"
 mkfifo "$FIFO"
 chown "$OSUSER" "$FIFO"

 su "$OSUSER" -c "psql -p $PORT -U $DBUSER -d $DBNAME -f $FIFO" > /tmp/pg_backup_output.log 2>&1 &
 echo $! > "$PID_FILE"

 psql_version=$(su "$OSUSER" -c "psql --version" | awk '{print $3}' | cut -d'.' -f1)
 if [ "$psql_version" -ge 15 ]; then
     CMD="SELECT pg_backup_start('$ACT_JOBNAME');"
 else
     CMD="SELECT pg_start_backup('$ACT_JOBNAME');"
 fi

 echo "$CMD" > "$FIFO"
 sleep 2

 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt. Cleaning up..."
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         echo "SELECT pg_backup_stop(); exit;" > "$FIFO"
         rm -f "$FIFO" "$PID_FILE"
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 PORT=PORT_NUMBER
 FIFO="/tmp/pg_backup_fifo_$PORT"
 PID_FILE="/tmp/pg_backup_pid_$PORT"

 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)
 logger "PostgreSQL Full VM BYOS: Starting post-snapshot script."

 # 1. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done

 # 2. RESUME DATABASE (Close Session)
 if [ -p "$FIFO" ]; then
     logger "PostgreSQL Full VM BYOS: Closing backup session via FIFO..."
     echo "SELECT pg_backup_stop(); SELECT pg_stop_backup(); exit;" > "$FIFO"
     if [ -f "$PID_FILE" ]; then
         wait "$(cat "$PID_FILE")" 2>/dev/null
     fi
     rm -f "$FIFO" "$PID_FILE"
     logger "PostgreSQL Full VM BYOS: Database session closed."
 else
     logger "Error: FIFO not found. Session may have terminated unexpectedly."
 fi
 logger "PostgreSQL Full VM BYOS: Cleanup complete."

次のように置き換えます。

  • OS_USER: PostgreSQL を実行しているオペレーティング システム ユーザー(postgres など)。
  • PG_HOME: PostgreSQL のインストール ディレクトリのパス。
  • DB_USER: スーパーユーザー権限を持つ PostgreSQL データベース ユーザー。
  • PORT_NUMBER: PostgreSQL がリッスンするポート番号(デフォルト: 5432)。
  • DB_NAME: 接続先のデータベースの名前。

MySQL

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # 1. Configuration
 DBUSER="DB_USER"
 DBPASSWORD="DB_PASSWORD"
 PORTNO=PORT_NUMBER
 SOCKET_FILE="/var/run/mysqld/mysqld.sock"
 MYSQL_PATH="/usr/bin/mysql"
 FIFO="/tmp/mysql_backup_fifo_$PORTNO"
 PID_FILE="/tmp/mysql_backup_pid_$PORTNO"

 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "MySQL Full VM BYOS: Starting pre-snapshot script."

 # 3. QUIESCE DATABASE (Session-Bound Lock)
 rm -f "$FIFO"
 mkfifo "$FIFO"

 $MYSQL_PATH -u"$DBUSER" -p"$DBPASSWORD" -S"$SOCKET_FILE" -P"$PORTNO" < "$FIFO" > /tmp/mysql_backup_output.log 2>&1 &
 echo $! > "$PID_FILE"

 logger "MySQL Full VM BYOS: Issuing FLUSH TABLES WITH READ LOCK..."
 echo "FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400);" > "$FIFO"
 sleep 2

 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt. Cleaning up..."
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         kill $(cat "$PID_FILE") 2>/dev/null
         rm -f "$FIFO" "$PID_FILE"
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 PORTNO=PORT_NUMBER
 FIFO="/tmp/mysql_backup_fifo_$PORTNO"
 PID_FILE="/tmp/mysql_backup_pid_$PORTNO"

 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)
 logger "MySQL Full VM BYOS: Starting post-snapshot script."

 # 1. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done

 # 2. RESUME DATABASE (Unlock)
 if [ -f "$PID_FILE" ]; then
     logger "MySQL Full VM BYOS: Releasing locks..."
     kill $(cat "$PID_FILE") 2>/dev/null
     rm -f "$FIFO" "$PID_FILE"
     logger "MySQL Full VM BYOS: Locks released and session closed."
 else
     logger "Error: PID file not found. Lock may have been lost prematurely."
 fi
 logger "MySQL Full VM BYOS: Cleanup complete."

次のように置き換えます。

  • DB_USER: 管理権限を持つ MySQL データベース ユーザー。
  • DB_PASSWORD: MySQL データベースのパスワード(または Secret Manager で動的に取得)。
  • PORT_NUMBER: MySQL がリッスンするポート番号(デフォルト: 3306)。

MariaDB

スナップショット前のスクリプト(/etc/google/snapshots/pre.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/pre.sh

 # 1. Configuration
 DBUSER="DB_USER"
 DBPASSWORD="DB_PASSWORD"
 PORTNO=PORT_NUMBER
 SOCKET_FILE="/var/run/mysqld/mysqld.sock"
 MARIADB_PATH="/usr/bin/mariadb" # or /usr/bin/mysql
 SRV_TYPE="Master" # Set to "Slave" for standby nodes
 FIFO="/tmp/mariadb_backup_fifo_$PORTNO"
 PID_FILE="/tmp/mariadb_backup_pid_$PORTNO"
 STARTPOS_FILE="/tmp/STARTPOS_FILE_$PORTNO.txt"

 # 2. Discovery
 # Dynamically discover all local writeable mount points for full VM consistency
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)

 logger "MariaDB Full VM BYOS: Starting pre-snapshot script."

 # 3. QUIESCE DATABASE (Session-Bound)
 # Create a FIFO to hold the session open
 rm -f "$FIFO"
 mkfifo "$FIFO"

 # Start a background mariadb session that reads from the FIFO
 # This keeps the session (and locks) active until the process is killed
 $MARIADB_PATH -u"$DBUSER" -p"$DBPASSWORD" -S"$SOCKET_FILE" -P"$PORTNO" < "$FIFO" > /tmp/mariadb_backup_output.log 2>&1 &
 echo $! > "$PID_FILE"

 # Prepare quiesce query (Logic from act_mariadb_pre.sh)
 if [ "$SRV_TYPE" != "Slave" ]; then
     # Primary node: lock all tables
     logger "MariaDB Full VM BYOS: Issuing FLUSH TABLES WITH READ LOCK..."
     echo "FLUSH TABLES WITH READ LOCK; SELECT SLEEP(86400);" > "$FIFO"

     # Capture master status for PITR/replication info
     $MARIADB_PATH -u"$DBUSER" -p"$DBPASSWORD" -S"$SOCKET_FILE" -P"$PORTNO" -e "SHOW MASTER STATUS;" > "$STARTPOS_FILE"
 else
     # Replica node: stop the slave thread
     logger "MariaDB Full VM BYOS: Issuing STOP SLAVE..."
     echo "STOP SLAVE; SELECT SLEEP(86400);" > "$FIFO"

     # Capture slave status
     $MARIADB_PATH -u"$DBUSER" -p"$DBPASSWORD" -S"$SOCKET_FILE" -P"$PORTNO" -e "SHOW SLAVE STATUS \G;" > "$STARTPOS_FILE"
 fi

 # Wait a brief moment to ensure the command is processed
 sleep 2
 # 4. FREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     if ! sudo fsfreeze -f "$mnt"; then
         logger "Error: Failed to freeze $mnt. Cleaning up..."
         # Attempt emergency thaw
         for thaw_mnt in $MOUNT_POINTS; do sudo fsfreeze -u "$thaw_mnt" 2>/dev/null; done
         # Kill the background session to release locks
         kill $(cat "$PID_FILE") 2>/dev/null
         rm -f "$FIFO" "$PID_FILE"
         exit 1
     fi
     logger "Filesystem $mnt is frozen."
 done

スナップショット後のスクリプト(/etc/google/snapshots/post.sh

 #!/bin/bash
 # Location: /etc/google/snapshots/post.sh
 # 1. Configuration
 PORTNO=PORT_NUMBER
 SRV_TYPE="Master"
 DBUSER="DB_USER"
 DBPASSWORD="DB_PASSWORD"
 SOCKET_FILE="/var/run/mysqld/mysqld.sock"
 MARIADB_PATH="/usr/bin/mariadb"
 FIFO="/tmp/mariadb_backup_fifo_$PORTNO"
 PID_FILE="/tmp/mariadb_backup_pid_$PORTNO"
 # 2. Discovery
 MOUNT_POINTS=$(findmnt -n -l -o TARGET -t xfs,ext4,ext3,ext2,btrfs)
 logger "MariaDB Full VM BYOS: Starting post-snapshot script."
 # 3. UNFREEZE FILESYSTEMS (Optional)
 for mnt in $MOUNT_POINTS; do
     sudo fsfreeze -u "$mnt"
     logger "Filesystem $mnt is unfrozen."
 done
 # 4. RESUME DATABASE
 if [ -f "$PID_FILE" ]; then
     logger "MariaDB Full VM BYOS: Resuming database operations..."
     # Kill the background sleep process to automatically release session-bound locks
     kill $(cat "$PID_FILE") 2>/dev/null
     # For slave nodes, explicitly ensure replication is started
     if [ "$SRV_TYPE" = "Slave" ]; then
         $MARIADB_PATH -u"$DBUSER" -p"$DBPASSWORD" -S"$SOCKET_FILE" -P"$PORTNO" -e "START SLAVE;"
     fi
     rm -f "$FIFO" "$PID_FILE"
     logger "MariaDB Full VM BYOS: Cleanup complete."
 else
     logger "Error: PID file not found. Database state might be inconsistent."
 fi

次のように置き換えます。

  • DB_USER: 管理権限を持つ MariaDB データベース ユーザー。
  • DB_PASSWORD: MariaDB データベースのパスワード(または Secret Manager を使用して動的に取得)。
  • PORT_NUMBER: MariaDB がリッスンするポート番号(デフォルト: 3306)。

ゲスト フラッシュ スクリプトをデプロイする

データベース用の pre.sh スクリプトと post.sh スクリプトを準備したら、Linux VM インスタンスにデプロイします。

  1. SSH を使用して、セルフマネージド データベースを実行している Linux VM インスタンスに接続します。

  2. /etc/google/snapshots/ ディレクトリが存在しない場合は作成します。

    sudo mkdir -p /etc/google/snapshots
    
  3. カスタムの pre.sh スクリプトと post.sh スクリプトを VM インスタンスの /etc/google/snapshots/ ディレクトリに保存します。

  4. スクリプトに実行権限があることを確認します。

    sudo chmod 755 /etc/google/snapshots/pre.sh /etc/google/snapshots/post.sh
    

スナップショットのゲスト エージェントを有効にする

Backup and DR でスナップショット取得前スクリプトとスナップショット取得後スクリプトを実行できるようにするには、Linux VM インスタンスの Compute Engine ゲスト環境でスナップショット統合を有効にします。

  1. SSH を使用して、セルフマネージド データベースを実行している Linux VM インスタンスに接続します(まだ接続していない場合)。

  2. テキスト エディタでゲスト環境構成ファイルを開きます。

    sudo nano /etc/default/instance_configs.cfg
    
  3. [Snapshots] セクションで次の設定を追加または変更して、スナップショットを有効にします。

    [Snapshots]
    enabled = true
    timeout_in_seconds = 120
    
  4. VM インスタンスでゲスト エージェントを再起動して、変更を適用します。

    sudo systemctl restart google-guest-agent
    

バックアップ プランを構成する

VM インスタンスが guest-flush スクリプトで構成され、スナップショット用にゲスト エージェントが有効になったので、 Google Cloud コンソールでバックアップ プランを構成します。

  1. Google Cloud コンソールで、[Backup and DR] ページに移動します。

    Backup and DR に移動

  2. ナビゲーション メニューから [バックアップ プラン] を選択します。

  3. [バックアップ プランを作成] をクリックするか、既存のバックアップ プランを選択して [編集] をクリックします。

  4. [インスタンス バックアップ] の構成手順で、整合性オプションを見つけます。

  5. [アプリケーション整合性を有効にする] オプションを選択します。

  6. バックアップ プランを保存して VM インスタンスに適用します。スケジュールに従って、バックアップ プランはゲスト エージェントをトリガーして pre.sh スクリプトを実行し、スナップショットを取得して post.sh スクリプトを実行します。

データベースのポイントインタイム リカバリ用に Persistent Disk バックアップを構成する

Db2 や SAP HANA などのセルフマネージド データベースでは、スタンドアロンの Persistent Disk バックアップを構成してデータベース アーカイブ ログをキャプチャし、ポイントインタイム リカバリを有効にできます。ポイントインタイム リカバリが必要ない場合は、ゲスト フラッシュ スクリプトを無効にするに進みます。

ポイントインタイム リカバリ ログのバックアップに関するベスト プラクティス

  • 頻度: この専用ログディスクのバックアップ プランのスケジュールを、ポイントインタイム リカバリ ログの粒度(15 分ごとや 1 時間ごとなど)と同じになるように構成します。

  • 費用の最適化: スナップショットの保存頻度が高いと、ストレージ費用が増加する可能性があります。オーバーヘッドを最小限に抑えるには、最短保持期間と対応する不変性 Vault 期間を、ポイントインタイム リカバリ ウィンドウを満たす最小許容時間に構成します。

セルフマネージド データベースを特定の時点に復元する

専用の Persistent Disk ログバックアップとともに定期的な VM バックアップを構成している場合は、次の手順に沿ってデータベースを特定の時点に復元します。専用ログ バックアップを構成していない場合や、ポイントインタイム リカバリが必要ない場合は、Backup Vault から Compute Engine インスタンスを復元するを参照して VM を直接復元し、復元後のタスクを実行するに進みます。

復元ワークフロー

  1. ベース VM を復元する: 目標復元時間より前のバックアップ ボールトからインスタンス バックアップ(マシンイメージ)を選択します。標準の Compute Engine 復元手順に沿って復元します。手順については、Backup Vault から Compute Engine インスタンスを復元するをご覧ください。

    専用のログ バックアップを構成していない場合や、ポイントインタイム リカバリが必要ない場合は、ステップ 4 に進みます。

  2. ログディスクをアタッチする: 目標復元時間までにキャプチャされた関連するログディスク スナップショットを特定して復元します。新しく作成したディスクを復元したインスタンスにアタッチします。

  3. データベースをロールフォワードする: SSH を使用して復元されたインスタンスに接続し、新しくアタッチされた永続ディスクにあるログを使用して、データベース固有のロールフォワード コマンド(Db2 の ROLLFORWARD DATABASE など)を実行します。

  4. 復元後のタスクを実行する: アプリケーションをオンラインにするために必要なデータベース固有の手順を実行します。

ゲストフラッシュ スクリプトを無効にする

カスタム ゲスト フラッシュ スクリプトを削除して、アプリケーション整合性を無効にするには:

  1. インスタンスからバックアップ プランの割り当てを解除する: Google Cloud コンソールで [Backup and DR] ページに移動し、[保護されたリソース] で VM インスタンスを見つけて、バックアップ プランの関連付けの割り当てを解除または削除します。

  2. ゲスト フラッシュ スクリプトを削除する: SSH を使用して Linux VM インスタンスに接続し、カスタム ゲスト フラッシュ スクリプトを削除します。

    sudo rm -f /etc/google/snapshots/pre.sh /etc/google/snapshots/post.sh
    
  3. ゲスト エージェントでスナップショット統合を無効にします。VM インスタンスで /etc/default/instance_configs.cfg を開き、[Snapshots]enabled = false を設定して、ゲスト エージェントを再起動します。

    sudo systemctl restart google-guest-agent
    

次のステップ