MySQL 9.x バックアップ完全ガイド – Docker環境での認証問題と解決策(AlmaLinux/Ubuntu対応)
WordPressのバックアップ自動化は運用の要です。しかし、MySQL 9.1から9.4へのアップデートにより、従来のバックアップ手法が突然機能しなくなるという深刻な問題が発生しています。本記事では、RHEL系(AlmaLinux)とDebian系(Ubuntu)の両環境で検証した結果を基に、この問題の根本原因と実践的な解決策を詳しく解説します。
目次
環境構成と前提条件
本記事では、以下の2つの環境で検証を行いました:
AlmaLinux環境(RHEL系)
OS: AlmaLinux 9.x(RHEL 9互換)
アーキテクチャ: ARM64/v8
Docker: 24.x以降
Docker Compose: v2.20以降
WordPress: 6.x(最新版)
MySQL: 9.1〜9.4
Ubuntu環境(Debian系)
OS: Ubuntu 22.04/24.04 LTS
アーキテクチャ: ARM64/v8およびx86_64
Docker: 24.x以降
Docker Compose: v2.20以降
WordPress: 6.x(最新版)
MySQL: 9.1〜9.4
プロジェクト構成
wordpress-docker/
├── docker-compose.yml # コンテナ構成定義
├── Dockerfile # WordPressカスタマイズ
├── entrypoint.sh # 初期化スクリプト
├── setup.sh # 環境セットアップ
├── .env # 環境変数
├── php.ini # PHP設定
├── backup/ # バックアップ保存先
└── scripts/ # 自動化スクリプト

MySQL 9.xで何が変わったのか
バージョン別の主要変更点
MySQL 9.0(2024年7月リリース)
mysql_native_password認証プラグインの完全削除- VECTOR型のサポート追加(AI/ML用途)
- 認証セキュリティの大幅強化
MySQL 9.1(2024年10月リリース)
CREATE VIEW IF NOT EXISTS構文の追加- 認証メカニズムの更なる強化
- ARM64最適化の改善
MySQL 9.2〜9.3(2024年後半〜2025年前半)
- パフォーマンス改善
- セキュリティ機能の拡張
- Docker環境での動作改善
MySQL 9.4(2025年7月リリース)
- GCC 11以降が必須に
- CMake 4のサポート
- RHEL7/CentOS7のARM版サポート終了
認証プラグインの変遷
-- MySQL 5.7以前(デフォルト)
mysql_native_password
-- MySQL 8.0〜8.3
mysql_native_password(非推奨だが利用可能)
caching_sha2_password(デフォルト)
-- MySQL 8.4
mysql_native_password(デフォルト無効、オプションで有効化可能)
caching_sha2_password(デフォルト)
-- MySQL 9.0以降
mysql_native_password(完全削除)
caching_sha2_password(唯一の選択肢)
問題の発生と症状
初期症状:サイレントな失敗
ある日のシステムアップデート後、以下の問題が発生しました:

- バックアップの無言の失敗
- cronジョブは正常に実行されているように見える
- しかしバックアップファイルが生成されない
- エラーログにも記録されない
- ヘルスチェックエラー
template parsing error: template: :1:8: executing "" at <.State.Health.Status>: map has no entry for key "Health" - 認証エラー
mysqldump: Got error: 1045: Access denied for user 'root'@'localhost' (using password: YES) when trying to connect

問題の深刻度
この問題の影響は甚大です:
- ✗ 日次バックアップが完全に停止
- ✗ 災害復旧計画(DRP)が機能不全
- ✗ データ損失リスクの増大
- ✗ コンプライアンス要件の違反可能性
OS別の違いと注意点
検証の結果、OSによって以下の違いが確認されました:
AlmaLinux(RHEL系)での特徴
ユーザーとグループ管理
# AlmaLinuxでのMySQLユーザー確認
$ docker exec wordpress-db id mysql
uid=999(mysql) gid=999(mysql) groups=999(mysql)
# ホストでの権限設定
$ sudo chown 999:999 ./db_data
SELinuxの影響
# SELinuxコンテキストの確認
$ ls -Z ./db_data
system_u:object_r:container_file_t:s0 ./db_data
# 必要に応じてコンテキストを設定
$ sudo chcon -Rt svirt_sandbox_file_t ./db_data
ファイアウォール設定
# firewalldでポート開放
$ sudo firewall-cmd --permanent --add-port=3306/tcp
$ sudo firewall-cmd --reload
Ubuntu(Debian系)での特徴
ユーザーとグループ管理
# UbuntuでのMySQLユーザー確認
$ docker exec wordpress-db id mysql
uid=999(mysql) gid=999(mysql) groups=999(mysql)
# www-dataユーザーの確認(WordPressコンテナ)
$ docker exec wordpress id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
AppArmorの影響
# AppArmorステータス確認
$ sudo aa-status | grep docker
# 必要に応じてプロファイルを調整
$ sudo aa-complain /usr/bin/docker
UFW(Uncomplicated Firewall)設定
# ufwでポート開放
$ sudo ufw allow from any to any port 3306 proto tcp
$ sudo ufw reload
Dockerの挙動の違い
興味深いことに、Dockerコンテナ内の挙動はOSに関わらずほぼ同一です:
# docker-compose.yml(両OS共通)
version: '3.9'
services:
db:
image: mysql:9.4
platform: linux/arm64/v8 # ARMの場合
# platform: linux/amd64 # x86_64の場合
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
volumes:
- db_data:/var/lib/mysql
主な違いはホストOSのファイル権限管理にあります。
根本的な解決策
解決策1:認証バイパスによる緊急バックアップ
この方法は、MySQL 9.xの厳格な認証を一時的に回避します:

ステップ1:準備
# 一時ディレクトリの作成
mkdir -p temp_mysql_data temp_run_mysqld
# データベースファイルのコピー(権限保持)
sudo cp -rp db_data/* temp_mysql_data/
# 権限の確認と設定
sudo chown -R 999:999 temp_mysql_data/
ステップ2:バックアップ実行
#!/bin/bash
# MySQL 9.x対応バックアップスクリプト
docker run --rm \
--platform linux/$(uname -m) \
-v $(pwd)/temp_mysql_data:/var/lib/mysql:ro \
-v $(pwd)/temp_run_mysqld:/var/run/mysqld \
-v $(pwd)/backup:/backup \
mysql:9.4 \
bash -c '
# MySQLを認証スキップモードで起動
docker-entrypoint.sh mysqld \
--skip-grant-tables \
--skip-networking \
--datadir=/var/lib/mysql &
# 起動待機(最大60秒)
echo "MySQLの起動を待機中..."
for i in {1..60}; do
if mysqladmin ping --silent 2>/dev/null; then
echo "MySQL起動確認"
break
fi
sleep 1
done
# バックアップ実行
echo "バックアップ開始: $(date)"
mysqldump \
--no-tablespaces \
--column-statistics=0 \
--skip-add-drop-table \
--single-transaction \
--quick \
--lock-tables=false \
--all-databases > /backup/full_backup_$(date +%Y%m%d_%H%M%S).sql
if [ $? -eq 0 ]; then
echo "バックアップ成功"
else
echo "バックアップ失敗"
exit 1
fi
# クリーンアップ
mysqladmin shutdown 2>/dev/null
sleep 5
'
ステップ3:後処理
# 一時ディレクトリの削除
sudo rm -rf temp_mysql_data temp_run_mysqld
# バックアップファイルの確認
ls -lh backup/*.sql

解決策2:専用バックアップコンテナの構築
より洗練された永続的な解決策です:
# docker-compose.yml
version: '3.9'
services:
db:
image: mysql:9.4
container_name: wordpress-db
platform: linux/arm64/v8
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
# MySQL 9.x固有の設定
MYSQL_ROOT_HOST: '%'
volumes:
- db_data:/var/lib/mysql
- ./mysql-init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--protocol=TCP"]
interval: 30s
timeout: 15s
retries: 5
start_period: 90s # MySQL 9.xは起動が遅い
networks:
- wp-network
wordpress:
depends_on:
db:
condition: service_healthy
image: wordpress:latest
container_name: wordpress
platform: linux/arm64/v8
restart: unless-stopped
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
volumes:
- wordpress_data:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80 || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- wp-network
backup:
image: mysql:9.4
container_name: wordpress-backup
platform: linux/arm64/v8
depends_on:
db:
condition: service_healthy
environment:
MYSQL_HOST: db
MYSQL_PORT: 3306
MYSQL_USER: root
MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
TZ: Asia/Tokyo
BACKUP_SCHEDULE: "0 2 * * *" # 毎日午前2時
BACKUP_RETENTION_DAYS: 30 # 30日間保持
volumes:
- ./backup:/backup
- ./scripts:/scripts:ro
entrypoint: ["/scripts/backup-entrypoint.sh"]
networks:
- wp-network
volumes:
db_data:
driver: local
wordpress_data:
driver: local
networks:
wp-network:
driver: bridge
バックアップエントリーポイントスクリプト
#!/bin/bash
# scripts/backup-entrypoint.sh
set -e
# カラー出力の定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 環境変数の検証
if [ -z "$MYSQL_HOST" ] || [ -z "$MYSQL_PASSWORD" ]; then
log_error "必須の環境変数が設定されていません"
exit 1
fi
# cronのインストール
apt-get update -qq && apt-get install -y -qq cron > /dev/null 2>&1
# バックアップスクリプトの作成
cat > /backup.sh << 'SCRIPT'
#!/bin/bash
source /etc/environment
# ログ関数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# MySQLの接続確認
wait_for_mysql() {
local max_attempts=30
local attempt=0
while [ $attempt -lt $max_attempts ]; do
if mysqladmin ping -h "$MYSQL_HOST" --port="$MYSQL_PORT" \
-u "$MYSQL_USER" -p"$MYSQL_PASSWORD" --silent 2>/dev/null; then
return 0
fi
attempt=$((attempt + 1))
sleep 2
done
return 1
}
# メインバックアップ処理
perform_backup() {
local backup_file="/backup/${MYSQL_DATABASE}_$(date +%Y%m%d_%H%M%S).sql"
local temp_file="${backup_file}.tmp"
log "バックアップ開始: $MYSQL_DATABASE"
if ! wait_for_mysql; then
log "ERROR: MySQLへの接続に失敗しました"
return 1
fi
# MySQL 9.x対応のバックアップオプション
if MYSQL_PWD="$MYSQL_PASSWORD" mysqldump \
-h "$MYSQL_HOST" \
--port="$MYSQL_PORT" \
-u "$MYSQL_USER" \
--no-tablespaces \
--column-statistics=0 \
--single-transaction \
--quick \
--lock-tables=false \
--routines \
--triggers \
--events \
"$MYSQL_DATABASE" > "$temp_file" 2>/dev/null; then
# バックアップの検証
if [ -s "$temp_file" ]; then
mv "$temp_file" "$backup_file"
# 圧縮
gzip "$backup_file"
log "バックアップ成功: ${backup_file}.gz ($(du -h ${backup_file}.gz | cut -f1))"
# 古いバックアップの削除
find /backup -name "*.sql.gz" -mtime +${BACKUP_RETENTION_DAYS} -delete
log "古いバックアップを削除しました(${BACKUP_RETENTION_DAYS}日以上)"
return 0
else
log "ERROR: バックアップファイルが空です"
rm -f "$temp_file"
return 1
fi
else
log "ERROR: mysqldumpが失敗しました"
rm -f "$temp_file"
return 1
fi
}
# 実行
perform_backup
exit $?
SCRIPT
chmod +x /backup.sh
# 環境変数をcronで利用可能にする
printenv | grep -E '^MYSQL_|^BACKUP_|^TZ=' > /etc/environment
# cronジョブの設定
echo "$BACKUP_SCHEDULE /backup.sh >> /var/log/backup.log 2>&1" | crontab -
# 初回バックアップの実行
log_info "初回バックアップを実行中..."
/backup.sh
# cronデーモンの起動とログ監視
log_info "バックアップスケジューラーを起動しました"
log_info "スケジュール: $BACKUP_SCHEDULE"
log_info "保持期間: ${BACKUP_RETENTION_DAYS}日"
cron && tail -f /var/log/backup.log
自動バックアップシステムの構築
監視スクリプト
#!/bin/bash
# scripts/monitor-backup.sh
BACKUP_DIR="./backup"
ALERT_EMAIL="admin@example.com"
MAX_AGE_HOURS=26
MIN_SIZE_MB=1
# Slack通知関数(オプション)
send_slack_alert() {
local message=$1
local webhook_url="YOUR_SLACK_WEBHOOK_URL"
if [ ! -z "$webhook_url" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"⚠️ バックアップ警告: $message\"}" \
"$webhook_url" 2>/dev/null
fi
}
# メール通知関数
send_email_alert() {
local message=$1
echo "$message" | mail -s "MySQL Backup Alert" "$ALERT_EMAIL"
}
# 最新のバックアップを確認
check_latest_backup() {
local latest_backup=$(ls -t $BACKUP_DIR/*.sql.gz 2>/dev/null | head -1)
if [ -z "$latest_backup" ]; then
echo "❌ エラー: バックアップファイルが見つかりません"
send_slack_alert "バックアップファイルが見つかりません"
return 1
fi
# バックアップの経過時間を確認
local backup_age_seconds=$(($(date +%s) - $(stat -c %Y "$latest_backup" 2>/dev/null || stat -f %m "$latest_backup")))
local backup_age_hours=$((backup_age_seconds / 3600))
if [ $backup_age_hours -gt $MAX_AGE_HOURS ]; then
echo "⚠️ 警告: 最新のバックアップは${backup_age_hours}時間前です(閾値: ${MAX_AGE_HOURS}時間)"
send_slack_alert "バックアップが${backup_age_hours}時間前です"
fi
# バックアップサイズを確認
local backup_size_bytes=$(stat -c %s "$latest_backup" 2>/dev/null || stat -f %z "$latest_backup")
local backup_size_mb=$((backup_size_bytes / 1024 / 1024))
if [ $backup_size_mb -lt $MIN_SIZE_MB ]; then
echo "⚠️ 警告: バックアップサイズが小さすぎます(${backup_size_mb}MB < ${MIN_SIZE_MB}MB)"
send_slack_alert "バックアップサイズが異常に小さいです(${backup_size_mb}MB)"
fi
echo "✅ バックアップ確認完了:"
echo " ファイル: $(basename $latest_backup)"
echo " 経過時間: ${backup_age_hours}時間"
echo " サイズ: ${backup_size_mb}MB"
return 0
}
# ヘルスチェック
check_mysql_health() {
if docker exec wordpress-db mysqladmin ping -h localhost --protocol=TCP >/dev/null 2>&1; then
echo "✅ MySQL: 正常動作中"
else
echo "❌ MySQL: 応答なし"
send_slack_alert "MySQLが応答していません"
return 1
fi
}
# メイン処理
main() {
echo "=== バックアップ監視レポート $(date '+%Y-%m-%d %H:%M:%S') ==="
check_mysql_health
check_latest_backup
echo "=== 監視完了 ==="
}
main
復元手順
通常の復元
#!/bin/bash
# scripts/restore-backup.sh
BACKUP_FILE=$1
if [ -z "$BACKUP_FILE" ]; then
echo "使用方法: $0 <バックアップファイル>"
echo "例: $0 backup/wordpress_20250825_020000.sql.gz"
exit 1
fi
if [ ! -f "$BACKUP_FILE" ]; then
echo "エラー: ファイルが見つかりません: $BACKUP_FILE"
exit 1
fi
echo "復元を開始します: $BACKUP_FILE"
# WordPressを停止
echo "WordPressコンテナを停止中..."
docker compose stop wordpress
# バックアップファイルを展開
if [[ "$BACKUP_FILE" == *.gz ]]; then
echo "バックアップファイルを展開中..."
gunzip -c "$BACKUP_FILE" > /tmp/restore.sql
RESTORE_FILE="/tmp/restore.sql"
else
RESTORE_FILE="$BACKUP_FILE"
fi
# 復元実行
echo "データベースを復元中..."
docker exec -i wordpress-db mysql -u root -p${MYSQL_ROOT_PASSWORD} ${MYSQL_DATABASE} < "$RESTORE_FILE"
if [ $? -eq 0 ]; then
echo "✅ 復元成功"
# 復元の確認
echo "復元されたテーブルを確認中..."
docker exec wordpress-db mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "
USE ${MYSQL_DATABASE};
SHOW TABLES;
SELECT COUNT(*) as '投稿数' FROM wp_posts;
SELECT COUNT(*) as 'ユーザー数' FROM wp_users;
"
# WordPressを再起動
echo "WordPressを再起動中..."
docker compose start wordpress
echo "✅ 復元完了!"
else
echo "❌ 復元失敗"
exit 1
fi
# 一時ファイルの削除
[ -f "/tmp/restore.sql" ] && rm /tmp/restore.sql
緊急復元(認証問題がある場合)
#!/bin/bash
# scripts/emergency-restore.sh
BACKUP_FILE=$1
# 全コンテナを停止
docker compose down
# 現在のデータをバックアップ
echo "現在のデータをバックアップ中..."
sudo mv db_data db_data_backup_$(date +%Y%m%d_%H%M%S)
# 新しいデータディレクトリを作成
mkdir -p db_data
# 一時的なMySQLコンテナを起動(認証スキップモード)
docker run -d \
--name mysql-emergency \
--platform linux/arm64/v8 \
-v $(pwd)/db_data:/var/lib/mysql \
-v $(pwd)/$BACKUP_FILE:/restore.sql:ro \
-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
mysql:9.4 \
--skip-grant-tables --skip-networking
sleep 10
# データベースの初期化と復元
docker exec mysql-emergency bash -c "
# データベース作成
mysql -e 'CREATE DATABASE IF NOT EXISTS ${MYSQL_DATABASE};'
# 復元
mysql ${MYSQL_DATABASE} < /restore.sql
# 権限の再設定
mysql -e \"
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '${MYSQL_ROOT_PASSWORD}';
ALTER USER 'root'@'%' IDENTIFIED WITH caching_sha2_password BY '${MYSQL_ROOT_PASSWORD}';
CREATE USER IF NOT EXISTS '${MYSQL_USER}'@'%' IDENTIFIED WITH caching_sha2_password BY '${MYSQL_PASSWORD}';
GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO '${MYSQL_USER}'@'%';
FLUSH PRIVILEGES;
\"
"
# 緊急コンテナを停止・削除
docker stop mysql-emergency
docker rm mysql-emergency
# 通常のサービスを起動
docker compose up -d
echo "✅ 緊急復元完了"
トラブルシューティング実践
問題1:.htaccessファイルの権限問題
症状
- トップページは表示される
- 個別記事が404エラー
AlmaLinuxでの解決
# .htaccessファイルの作成
cat > wordpress_data/.htaccess << 'EOF'
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
EOF
# 権限設定(AlmaLinux)
sudo chown 33:33 wordpress_data/.htaccess
sudo chmod 644 wordpress_data/.htaccess
# SELinuxコンテキスト設定
sudo chcon -t httpd_sys_content_t wordpress_data/.htaccess
Ubuntuでの解決
# 権限設定(Ubuntu)
sudo chown www-data:www-data wordpress_data/.htaccess
# または数値指定
sudo chown 33:33 wordpress_data/.htaccess
sudo chmod 644 wordpress_data/.htaccess
問題2:データベース移行時の文字コード問題
# バックアップ時に文字コードを明示
docker exec wordpress-db mysqldump \
--default-character-set=utf8mb4 \
--no-tablespaces \
-u root -p${MYSQL_ROOT_PASSWORD} \
${MYSQL_DATABASE} > backup.sql
# 復元時も文字コードを明示
docker exec -i wordpress-db mysql \
--default-character-set=utf8mb4 \
-u root -p${MYSQL_ROOT_PASSWORD} \
${MYSQL_DATABASE} < backup.sql
問題3:パーマリンク設定の不具合
-- データベースで直接修正
UPDATE wp_options
SET option_value = 'https://your-domain.com'
WHERE option_name IN ('siteurl', 'home');
-- パーマリンク構造の確認
SELECT option_value
FROM wp_options
WHERE option_name = 'permalink_structure';
問題4:コンテナ間の接続問題
# ネットワークの確認
docker network ls
docker network inspect wordpress-docker_wp-network
# コンテナ間の疎通確認
docker exec wordpress ping -c 3 db
docker exec wordpress nslookup db
# MySQLポートの確認
docker exec wordpress nc -zv db 3306
パフォーマンス最適化
MySQL 9.x向けの最適化設定
# mysql-init/custom.cnf
[mysqld]
# MySQL 9.x推奨設定
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
# クエリキャッシュ(MySQL 8.0以降は削除)
# query_cache_size = 0
# query_cache_type = 0
# 接続関連
max_connections = 200
max_connect_errors = 1000000
wait_timeout = 28800
interactive_timeout = 28800
# スロークエリログ
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# バイナリログ(レプリケーション用)
log_bin = mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 100M
# 文字コード
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ciDocker Composeでのリソース制限
services:
db:
image: mysql:9.4
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '1.0'
memory: 1G
セキュリティ強化
1. 環境変数の安全な管理
# .env.example
MYSQL_ROOT_PASSWORD=ChangeThisStrongPassword123!
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=AnotherStrongPassword456!
# 本番環境では.envを暗号化
ansible-vault encrypt .env
2. ネットワークの分離
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 外部アクセス不可
services:
db:
networks:
- backend
wordpress:
networks:
- frontend
- backend
3. 読み取り専用マウント
volumes:
- ./scripts:/scripts:ro
- ./mysql-init:/docker-entrypoint-initdb.d:ro
完全自動化スクリプト
マスターセットアップスクリプト
#!/bin/bash
# setup-complete.sh
set -e
# カラー定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# ロゴ表示
show_banner() {
echo -e "${BLUE}"
cat << "EOF"
╔══════════════════════════════════════════╗
║ WordPress + MySQL 9.x Setup Script ║
║ Fully Automated Edition ║
╚══════════════════════════════════════════╝
EOF
echo -e "${NC}"
}
# OS検出
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
VER=$VERSION_ID
else
echo -e "${RED}OSの検出に失敗しました${NC}"
exit 1
fi
echo -e "${GREEN}検出されたOS: $OS $VER${NC}"
}
# 依存関係のインストール
install_dependencies() {
echo -e "${YELLOW}依存関係をインストール中...${NC}"
case $OS in
ubuntu|debian)
sudo apt-get update
sudo apt-get install -y docker.io docker-compose jq curl wget
;;
almalinux|rocky|centos|rhel)
sudo dnf install -y docker docker-compose jq curl wget
;;
*)
echo -e "${RED}サポートされていないOS: $OS${NC}"
exit 1
;;
esac
# Dockerサービスの起動
sudo systemctl start docker
sudo systemctl enable docker
# ユーザーをdockerグループに追加
sudo usermod -aG docker $USER
echo -e "${GREEN}依存関係のインストール完了${NC}"
}
# プロジェクトディレクトリの作成
create_project_structure() {
echo -e "${YELLOW}プロジェクト構造を作成中...${NC}"
mkdir -p {backup,scripts,mysql-init}
# .envファイルの生成
if [ ! -f .env ]; then
cat > .env << EOF
# MySQL設定
MYSQL_ROOT_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
# WordPress設定
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wpuser
WORDPRESS_TABLE_PREFIX=wp_
# バックアップ設定
BACKUP_SCHEDULE="0 2 * * *"
BACKUP_RETENTION_DAYS=30
EOF
echo -e "${GREEN}.envファイルを生成しました${NC}"
fi
# 権限設定
chmod 600 .env
}
# Docker Composeファイルの生成
generate_docker_compose() {
echo -e "${YELLOW}docker-compose.ymlを生成中...${NC}"
# アーキテクチャの検出
ARCH=$(uname -m)
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
PLATFORM="linux/arm64/v8"
else
PLATFORM="linux/amd64"
fi
cat > docker-compose.yml << EOF
version: '3.9'
services:
db:
image: mysql:9.4
container_name: wordpress-db
platform: ${PLATFORM}
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./mysql-init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--protocol=TCP"]
interval: 30s
timeout: 15s
retries: 5
start_period: 90s
networks:
- wp-network
wordpress:
depends_on:
db:
condition: service_healthy
image: wordpress:latest
container_name: wordpress
platform: ${PLATFORM}
restart: unless-stopped
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: \${WORDPRESS_DB_HOST}
WORDPRESS_DB_USER: \${MYSQL_USER}
WORDPRESS_DB_PASSWORD: \${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: \${WORDPRESS_DB_NAME}
WORDPRESS_TABLE_PREFIX: \${WORDPRESS_TABLE_PREFIX}
volumes:
- wordpress_data:/var/www/html
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- wp-network
backup:
image: mysql:9.4
container_name: wordpress-backup
platform: ${PLATFORM}
depends_on:
db:
condition: service_healthy
environment:
MYSQL_HOST: db
MYSQL_USER: root
MYSQL_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
BACKUP_SCHEDULE: \${BACKUP_SCHEDULE}
BACKUP_RETENTION_DAYS: \${BACKUP_RETENTION_DAYS}
volumes:
- ./backup:/backup
- ./scripts:/scripts:ro
command: ["/scripts/backup-entrypoint.sh"]
networks:
- wp-network
volumes:
db_data:
wordpress_data:
networks:
wp-network:
driver: bridge
EOF
echo -e "${GREEN}docker-compose.yml生成完了${NC}"
}
# スクリプトの生成
generate_scripts() {
echo -e "${YELLOW}スクリプトを生成中...${NC}"
# バックアップエントリーポイント
cat > scripts/backup-entrypoint.sh << 'EOF'
#!/bin/bash
apt-get update && apt-get install -y cron
printenv | grep -E '^MYSQL_|^BACKUP_' > /etc/environment
cat > /backup.sh << 'SCRIPT'
#!/bin/bash
source /etc/environment
MYSQL_PWD="$MYSQL_PASSWORD" mysqldump \
-h "$MYSQL_HOST" -u "$MYSQL_USER" \
--no-tablespaces --column-statistics=0 \
--single-transaction --quick \
"$MYSQL_DATABASE" | gzip > "/backup/${MYSQL_DATABASE}_$(date +%Y%m%d_%H%M%S).sql.gz"
find /backup -name "*.sql.gz" -mtime +${BACKUP_RETENTION_DAYS} -delete
SCRIPT
chmod +x /backup.sh
echo "$BACKUP_SCHEDULE /backup.sh >> /var/log/backup.log 2>&1" | crontab -
/backup.sh
cron && tail -f /var/log/backup.log
EOF
chmod +x scripts/backup-entrypoint.sh
echo -e "${GREEN}スクリプト生成完了${NC}"
}
# サービスの起動
start_services() {
echo -e "${YELLOW}サービスを起動中...${NC}"
docker compose up -d
# 起動確認
echo -e "${YELLOW}サービスの起動を確認中...${NC}"
sleep 10
if docker compose ps | grep -q "Up"; then
echo -e "${GREEN}✅ すべてのサービスが正常に起動しました${NC}"
else
echo -e "${RED}❌ サービスの起動に失敗しました${NC}"
docker compose logs
exit 1
fi
}
# 設定情報の表示
show_info() {
source .env
echo -e "${BLUE}"
echo "╔══════════════════════════════════════════╗"
echo "║ セットアップ完了! ║"
echo "╚══════════════════════════════════════════╝"
echo -e "${NC}"
echo -e "${GREEN}アクセス情報:${NC}"
echo " WordPress URL: http://localhost:8080"
echo ""
echo -e "${GREEN}データベース情報:${NC}"
echo " ホスト: localhost:3306"
echo " データベース名: $MYSQL_DATABASE"
echo " ユーザー: $MYSQL_USER"
echo " パスワード: .envファイルを参照"
echo ""
echo -e "${GREEN}管理コマンド:${NC}"
echo " 起動: docker compose up -d"
echo " 停止: docker compose down"
echo " ログ: docker compose logs -f"
echo " バックアップ: docker exec wordpress-backup /backup.sh"
echo ""
echo -e "${YELLOW}※ 初回アクセス時にWordPressの初期設定を行ってください${NC}"
}
# メイン処理
main() {
show_banner
detect_os
install_dependencies
create_project_structure
generate_docker_compose
generate_scripts
start_services
show_info
}
# 実行
main
GitHub リポジトリ
完全なコードとドキュメントは以下のリポジトリで公開しています:
リポジトリ: https://github.com/superdoccimo/wpbk
リポジトリの内容
- ✅ AlmaLinux/Ubuntu両対応のセットアップスクリプト
- ✅ MySQL 9.1〜9.4対応のバックアップソリューション
- ✅ 自動復元スクリプト
- ✅ ヘルスチェック・監視ツール
- ✅ トラブルシューティングガイド
将来への備え
MySQL 10.xへの準備
MySQL 10.xでは以下の変更が予想されます:
- AI/ML機能の本格統合
- VECTOR型の拡張
- 機械学習モデルの直接実行
- さらなるセキュリティ強化
- 量子耐性暗号化
- ゼロトラストアーキテクチャ
- クラウドネイティブ機能
- Kubernetes統合の改善
- サーバーレス対応
推奨される準備
# 将来を見据えた設定
services:
db:
image: mysql:${MYSQL_VERSION:-9.4} # バージョン変数化
environment:
# 将来の機能フラグ
MYSQL_ENABLE_VECTOR: "true"
MYSQL_ENABLE_ML: "false" # 将来有効化
まとめ
MySQL 9.xへのアップデートによるバックアップ問題は、以下の要因によるものでした:
- 認証メカニズムの根本的変更
mysql_native_passwordの完全削除caching_sha2_passwordへの強制移行
- セキュリティ強化
- より厳格な権限管理
- デフォルトでの制限的な設定
- プラットフォーム依存性
- OSによる権限管理の違い
- SELinux/AppArmorの影響
解決のポイント
- ✅ 認証バイパスによる緊急バックアップ
- ✅ 専用バックアップコンテナの構築
- ✅ OS別の権限管理
- ✅ 自動化と監視の実装
これらの対策により、MySQL 9.xでも安定したバックアップ運用が可能になります。
参考リンク
最終更新: 2025年8月25日
動作確認環境: AlmaLinux 9, Ubuntu 22.04/24.04, MySQL 9.1-9.4, Docker 24.x


