Open22

SynologyサーバーのGlacier Deep Archiveバックアップ設定

こっこさんこっこさん
$ /bin/sudo /usr/local/bin/docker run --rm -it -v ~/.aws:/root/.aws amazon/aws-c
li --version
$ which curl
/bin/curl
$ which bash
/bin/bash
こっこさんこっこさん

Container Manageramazon/aws-cliをダウンロード

docker run --rm -it amazon/aws-cli --version

# cron向けなら
/usr/local/bin/docker run --rm -it amazon/aws-cli --version

--rm:コマンド実行後、コンテナを自動削除してくれる
-it:対話的なシェルを立ち上げてくれる的な?

こっこさんこっこさん

管理者権限が必要なコマンドは、rootユーザーのcronとして登録する
(ベストプラクティスかはわからない)

こっこさんこっこさん
Container Manager のコンテナ dazzling_euler が予期せず停止しました。[コンテナ] ページで [dazzling_euler] を選択し、[詳細] ボタンをクリックし、[ログ] タブで詳細を確認してください。

という通知が毎回来る。

こっこさんこっこさん

コンソール
→ Identity and Access Management (IAM)
→ アクセス管理>ユーザー
→ ユーザーの作成
→ S3FullAccessを付与(グループを作成するなり、ポリシーを直接アタッチするなり)

作成したユーザーを選択
→ セキュリティ認証情報
→ アクセスキーを作成
→ アクセスキー、シークレットアクセスキーを大切な場所に保管しておく

こっこさんこっこさん

とてもうまくいきそうだが、コンテナ作成時のボリューム選択画面で homes ディレクトリが表示されない。

こっこさんこっこさん

Claude Codeに

Synology Glacier Deep Archiveバックアップ実装

1. 事前準備

1.1 S3バケットの作成

# バケット作成(リージョンは適宜変更)
/usr/local/bin/docker run --rm \
  -v ~/.aws:/root/.aws \
  -e AWS_PROFILE=default \
  amazon/aws-cli s3 mb s3://your-backup-bucket-name --region ap-northeast-1

1.2 AWS認証情報の設定

# ~/.aws/credentials に設定
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
region = ap-northeast-1

2. バックアップスクリプトの作成

2.1 メインバックアップスクリプト

/volume1/scripts/backup_to_glacier.sh を作成:

#!/bin/bash

# 設定
BACKUP_BUCKET="your-backup-bucket-name"
LOG_FILE="/volume1/logs/glacier_backup.log"
TEMP_DIR="/tmp/backup_$(date +%Y%m%d_%H%M%S)"
DATE_STAMP=$(date +%Y%m%d_%H%M%S)

# ログ関数
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}

# エラーハンドリング
error_exit() {
    log "ERROR: $1"
    cleanup
    exit 1
}

# クリーンアップ
cleanup() {
    log "クリーンアップ開始"
    rm -rf "$TEMP_DIR"
    log "クリーンアップ完了"
}

# バックアップ対象ディレクトリ
BACKUP_TARGETS=(
    "/var/services/homes"
    "/var/services/music"
)

# メイン処理開始
log "=== Glacier Deep Archive バックアップ開始 ==="

# 一時ディレクトリ作成
mkdir -p "$TEMP_DIR" || error_exit "一時ディレクトリの作成に失敗"
mkdir -p "$(dirname "$LOG_FILE")" || error_exit "ログディレクトリの作成に失敗"

for target in "${BACKUP_TARGETS[@]}"; do
    if [ ! -d "$target" ]; then
        log "WARNING: $target が存在しません。スキップします。"
        continue
    fi
    
    # ディレクトリ名取得(パスから最後の部分)
    dir_name=$(basename "$target")
    archive_name="${dir_name}_${DATE_STAMP}.tar.gz"
    archive_path="$TEMP_DIR/$archive_name"
    
    log "$target のアーカイブ作成開始: $archive_name"
    
    # tar.gz作成(進捗表示付き)
    tar -czf "$archive_path" -C "$(dirname "$target")" "$dir_name" 2>&1 | \
        while read line; do
            log "TAR: $line"
        done
    
    if [ ${PIPESTATUS[0]} -ne 0 ]; then
        error_exit "$target のアーカイブ作成に失敗"
    fi
    
    # ファイルサイズ確認
    file_size=$(stat -c%s "$archive_path")
    file_size_mb=$((file_size / 1024 / 1024))
    log "アーカイブサイズ: ${file_size_mb}MB"
    
    # S3にアップロード(Glacier Deep Archiveストレージクラス指定)
    log "S3へのアップロード開始: s3://$BACKUP_BUCKET/backups/$archive_name"
    
    /usr/local/bin/docker run --rm \
        -v ~/.aws:/root/.aws \
        -v "$TEMP_DIR:/backup" \
        -e AWS_PROFILE=default \
        amazon/aws-cli s3 cp "/backup/$archive_name" \
        "s3://$BACKUP_BUCKET/backups/$archive_name" \
        --storage-class DEEP_ARCHIVE \
        --progress 2>&1 | while read line; do
            log "S3: $line"
        done
    
    if [ ${PIPESTATUS[0]} -ne 0 ]; then
        error_exit "S3へのアップロードに失敗: $archive_name"
    fi
    
    log "$archive_name のアップロード完了"
    
    # 一時ファイル削除
    rm -f "$archive_path"
    log "$archive_name のローカルファイル削除完了"
done

cleanup
log "=== すべてのバックアップが正常に完了しました ==="

2.2 スクリプトに実行権限を付与

chmod +x /volume1/scripts/backup_to_glacier.sh

3. 動作検証

3.1 テスト用の小さなディレクトリでテスト

# テスト用ディレクトリ作成
mkdir -p /volume1/test_backup
echo "テストファイル $(date)" > /volume1/test_backup/test.txt

# テスト用スクリプトの実行(BACKUP_TARGETSを変更して)
/volume1/scripts/backup_to_glacier.sh

3.2 バックアップ確認

# S3内のファイル一覧確認
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3 ls s3://your-backup-bucket-name/backups/ --recursive

# 特定ファイルの詳細情報確認
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3api head-object \
    --bucket your-backup-bucket-name \
    --key backups/homes_20250702_120000.tar.gz

3.3 復元テスト(注意:Deep Archiveは復元に12時間かかります)

# 復元リクエスト(Expedited, Standard, Bulk から選択)
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3api restore-object \
    --bucket your-backup-bucket-name \
    --key backups/test_backup_20250702_120000.tar.gz \
    --restore-request Days=1,GlacierJobParameters='{Tier=Standard}'

# 復元状況確認
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3api head-object \
    --bucket your-backup-bucket-name \
    --key backups/test_backup_20250702_120000.tar.gz

4. Cron設定

4.1 ボリュームマウント問題の解決

Container Managerでhomesディレクトリが表示されない問題の解決策:

# コマンドライン版(推奨)
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -v /var/services/homes:/mnt/homes:ro \
    -v /var/services/music:/mnt/music:ro \
    -v /volume1/scripts:/scripts \
    -v /volume1/logs:/logs \
    -e AWS_PROFILE=default \
    amazon/aws-cli --version

4.2 最終バックアップスクリプト(マウント対応版)

/volume1/scripts/backup_to_glacier_container.sh

#!/bin/bash

BACKUP_BUCKET="your-backup-bucket-name"
DATE_STAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/volume1/logs/glacier_backup.log"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}

mkdir -p "$(dirname "$LOG_FILE")"

log "=== Glacier Deep Archive バックアップ開始 ==="

# Dockerコンテナ内でバックアップ実行
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -v /var/services/homes:/mnt/homes:ro \
    -v /var/services/music:/mnt/music:ro \
    -v /volume1/scripts:/scripts \
    -v /volume1/logs:/logs \
    -e AWS_PROFILE=default \
    -e BACKUP_BUCKET="$BACKUP_BUCKET" \
    -e DATE_STAMP="$DATE_STAMP" \
    --entrypoint /bin/bash \
    amazon/aws-cli /scripts/backup_inside_container.sh

log "=== バックアップ処理完了 ==="

4.3 コンテナ内実行スクリプト

/volume1/scripts/backup_inside_container.sh

#!/bin/bash

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "/logs/glacier_backup.log"
}

# バックアップ対象
TARGETS=(
    "homes:/mnt/homes"
    "music:/mnt/music"
)

TEMP_DIR="/tmp/backup_${DATE_STAMP}"
mkdir -p "$TEMP_DIR"

for target_info in "${TARGETS[@]}"; do
    target_name=$(echo "$target_info" | cut -d: -f1)
    target_path=$(echo "$target_info" | cut -d: -f2)
    
    if [ ! -d "$target_path" ]; then
        log "WARNING: $target_path が存在しません"
        continue
    fi
    
    archive_name="${target_name}_${DATE_STAMP}.tar.gz"
    archive_path="$TEMP_DIR/$archive_name"
    
    log "$target_path のアーカイブ作成開始"
    tar -czf "$archive_path" -C "$target_path" . || {
        log "ERROR: アーカイブ作成失敗 - $target_path"
        continue
    }
    
    file_size=$(stat -c%s "$archive_path")
    file_size_mb=$((file_size / 1024 / 1024))
    log "アーカイブサイズ: ${file_size_mb}MB"
    
    log "S3アップロード開始: $archive_name"
    aws s3 cp "$archive_path" \
        "s3://$BACKUP_BUCKET/backups/$archive_name" \
        --storage-class DEEP_ARCHIVE \
        --progress || {
        log "ERROR: S3アップロード失敗 - $archive_name"
        continue
    }
    
    log "$archive_name アップロード完了"
    rm -f "$archive_path"
done

rm -rf "$TEMP_DIR"
log "クリーンアップ完了"

4.4 実行権限付与

chmod +x /volume1/scripts/backup_to_glacier_container.sh
chmod +x /volume1/scripts/backup_inside_container.sh

4.5 Cron設定

# rootのcrontabを編集
sudo crontab -e

# 毎週日曜日の午前2時に実行
0 2 * * 0 /volume1/scripts/backup_to_glacier_container.sh >> /volume1/logs/cron_backup.log 2>&1

# 毎月1日の午前3時に実行(月次バックアップ)
0 3 1 * * /volume1/scripts/backup_to_glacier_container.sh >> /volume1/logs/cron_backup.log 2>&1

5. 監視・メンテナンス

5.1 バックアップ履歴確認

# 最近のバックアップ一覧
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3 ls s3://your-backup-bucket-name/backups/ \
    --human-readable --summarize

# ログ確認
tail -f /volume1/logs/glacier_backup.log

5.2 古いバックアップの削除(ライフサイクル設定)

# ライフサイクル設定JSONファイル作成
cat > /volume1/scripts/lifecycle.json << 'EOF'
{
    "Rules": [
        {
            "ID": "DeleteOldBackups",
            "Status": "Enabled",
            "Filter": {
                "Prefix": "backups/"
            },
            "Expiration": {
                "Days": 2555
            }
        }
    ]
}
EOF

# ライフサイクル設定適用(7年後に削除)
/usr/local/bin/docker run --rm \
    -v ~/.aws:/root/.aws \
    -v /volume1/scripts:/scripts \
    -e AWS_PROFILE=default \
    amazon/aws-cli s3api put-bucket-lifecycle-configuration \
    --bucket your-backup-bucket-name \
    --lifecycle-configuration file:///scripts/lifecycle.json

5.3 通知設定(オプション)

失敗時にメール通知する場合は、Synologyの通知機能を活用:

# バックアップスクリプトに追加
send_notification() {
    local message="$1"
    local subject="Glacier Backup Notification"
    
    # Synology通知機能を使用
    /usr/syno/bin/synonet --wake lan1 &
    echo "$message" | mail -s "$subject" admin@yourdomain.com
}

# エラー時に通知
error_exit() {
    log "ERROR: $1"
    send_notification "バックアップエラー: $1"
    cleanup
    exit 1
}

6. コスト最適化のTips

  1. 圧縮率の向上: tar -czf の代わりに tar -cJf (xz圧縮)を使用
  2. 重複排除: rsyncでの差分バックアップと組み合わせ
  3. バックアップ頻度の調整: 重要度に応じて日次/週次/月次を使い分け
  4. マルチパートアップロード: 大きなファイルの場合は aws s3 cp が自動で実施

7. トラブルシューティング

よくある問題と解決策

  1. 権限エラー: Dockerコンテナ内でのファイルアクセス権限
  2. 容量不足: 一時ディレクトリの容量確認
  3. ネットワークエラー: アップロード中断時の再開
  4. 認証エラー: AWS認証情報の確認

詳細な問題解決は実際の症状に応じて対応します。

こっこさんこっこさん

動作検証

# 最小限の検証
/usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli sts get-caller-identity && echo "✅ AWS認証OK" || echo "❌ AWS認証NG"

# バケットアクセス + アップロード権限確認
/usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli bash -c 'aws s3 ls s3://your-bucket/ && echo "test" | aws s3 cp - s3://your-bucket/test.txt && aws s3 rm s3://your-bucket/test.txt && echo "✅ S3操作OK"' || echo "❌ S3操作NG"

# パイプアップロード確認
/usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli bash -c 'echo "test" | tar -czf - -T - | aws s3 cp - s3://your-bucket/pipe-test.tar.gz --storage-class DEEP_ARCHIVE && aws s3 rm s3://your-bucket/pipe-test.tar.gz && echo "✅ パイプアップロードOK"' || echo "❌ パイプアップロードNG"
こっこさんこっこさん

ターミナルでの検証

****@****: ~$ sudo -i
Password:
root@****: ~# /usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli --version
aws-cli/2.27.47 Python/3.13.4 Linux/5.10.55+ docker/aarch64.amzn.2
root@****:~# /usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli sts get-caller-identity

Unable to locate credentials. You can configure credentials by running "aws configure".
root@8888:~# /usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli configure
こっこさんこっこさん

まずは認証情報を手動設定

****@****:~# cat > ~/.aws/credentials << 'EOF'
> [default]
> aws_access_key_id = xxxxxxxxx
> aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxx
> EOF
****@****:~# /usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli sts get-caller-identity
{
    "UserId": "xxxxxxxxxxxxxxxxxx",
    "Account": "xxxxxxxxx",
    "Arn": "arn:aws:iam::xxxxxxxxx:user/xxxxxxxxx"
}
こっこさんこっこさん

次に設定を手動設定
まずはレイテンシを犠牲にしても、安価なリージョンを選択

****@****:~# cat > ~/.aws/config << 'EOF'
> [default]
> region = us-east-1
> output = json
> EOF
****@****:~# /usr/local/bin/docker run --rm -v ~/.aws:/root/.aws amazon/aws-cli configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QQ7E shared-credentials-file
secret_key     ****************hRNE shared-credentials-file
    region                us-east-1      config-file    ~/.aws/config