add wp-mirror nightly sync CT101 to CT600
Read-only mysqldump and tar pull; safe for production WordPress on CT101.
This commit is contained in:
parent
c9bfa8dbd0
commit
e41bb43024
2 changed files with 162 additions and 0 deletions
42
arakava-news/scripts/README-mirror-sync.md
Normal file
42
arakava-news/scripts/README-mirror-sync.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# CT600 wp-mirror Sync
|
||||
|
||||
Nächtlicher Pull **CT101 → CT600** auf **pve-mu-3**.
|
||||
|
||||
## CT101-Sicherheit
|
||||
|
||||
| Operation | Auswirkung auf CT101 |
|
||||
|-----------|----------------------|
|
||||
| `mysqldump --single-transaction --quick` | Read-only Snapshot, ~10 s, keine Table-Locks (InnoDB) |
|
||||
| `tar` aus Docker-Volume | Nur Lesen, kein Container-Restart |
|
||||
| Health-Check vor/nach Sync | Abbruch wenn Primary down |
|
||||
|
||||
**Nicht** gemacht: `docker restart`, `mysqladmin flush`, Schreibzugriffe, Plugin-Updates.
|
||||
|
||||
## Deployment
|
||||
|
||||
| Ort | Pfad |
|
||||
|-----|------|
|
||||
| Git | `arakava-news/scripts/wp-mirror-sync.sh` |
|
||||
| pve-mu-3 | `/opt/wp-mirror-sync/sync-from-101.sh` |
|
||||
| Log | `/var/log/wp-mirror-sync.log` |
|
||||
| Staging | `/opt/wp-mirror-sync/staging/` |
|
||||
|
||||
## Cron (pve-mu-3)
|
||||
|
||||
```
|
||||
0 4 * * * root /opt/wp-mirror-sync/sync-from-101.sh >> /var/log/wp-mirror-sync.log 2>&1
|
||||
```
|
||||
|
||||
## Failover pausieren
|
||||
|
||||
```bash
|
||||
touch /opt/wp-mirror-sync/FAILOVER_ACTIVE
|
||||
# nach Failback:
|
||||
rm /opt/wp-mirror-sync/FAILOVER_ACTIVE
|
||||
```
|
||||
|
||||
## Manuell
|
||||
|
||||
```bash
|
||||
ssh pve-mu-3 '/opt/wp-mirror-sync/sync-from-101.sh'
|
||||
```
|
||||
120
arakava-news/scripts/wp-mirror-sync.sh
Executable file
120
arakava-news/scripts/wp-mirror-sync.sh
Executable file
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/env bash
|
||||
# Pull WordPress CT101 (pve-hetzner) → CT600 wp-mirror (pve-mu-3)
|
||||
# CT101 impact: read-only mysqldump (--single-transaction) + read-only tar. No restarts.
|
||||
set -euo pipefail
|
||||
|
||||
HETZNER_HOST="${HETZNER_HOST:-root@100.88.230.59}"
|
||||
HETZNER_CT="${HETZNER_CT:-101}"
|
||||
MIRROR_CT="${MIRROR_CT:-600}"
|
||||
STAGING="${STAGING:-/opt/wp-mirror-sync/staging}"
|
||||
LOG="${LOG:-/var/log/wp-mirror-sync.log}"
|
||||
LOCK_FILE="/var/run/wp-mirror-sync.lock"
|
||||
FAILOVER_FLAG="/opt/wp-mirror-sync/FAILOVER_ACTIVE"
|
||||
MIRROR_SITEURL="http://192.168.178.142"
|
||||
MYSQL_USER="wordpress"
|
||||
MYSQL_PASS="astral66"
|
||||
MYSQL_DB="wordpress"
|
||||
WP_VOL="/var/lib/docker/volumes/wordpress_wp_data/_data"
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"
|
||||
}
|
||||
|
||||
tar_sync_files() {
|
||||
rm -rf "${STAGING}/wpfiles"
|
||||
mkdir -p "${STAGING}/wpfiles"
|
||||
ssh -o BatchMode=yes -o ConnectTimeout=30 "$HETZNER_HOST" \
|
||||
"ionice -c3 nice -n 19 pct exec ${HETZNER_CT} -- tar c -C ${WP_VOL} \
|
||||
--exclude=wp-content/cache \
|
||||
--exclude=wp-content/debug.log \
|
||||
--exclude=wp-content/upgrade \
|
||||
. 2>/dev/null" | tar x -C "${STAGING}/wpfiles"
|
||||
}
|
||||
|
||||
exec 9>"$LOCK_FILE"
|
||||
if ! flock -n 9; then
|
||||
log "SKIP: another sync is running"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f "$FAILOVER_FLAG" ]]; then
|
||||
log "SKIP: ${FAILOVER_FLAG} present (manual failover)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v pct >/dev/null 2>&1; then
|
||||
log "ABORT: must run on Proxmox host with pct (pve-mu-3)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$STAGING" "$(dirname "$LOG")"
|
||||
|
||||
log "Checking CT101 health..."
|
||||
if ! ssh -o BatchMode=yes -o ConnectTimeout=15 "$HETZNER_HOST" \
|
||||
"pct exec ${HETZNER_CT} -- curl -sf -o /dev/null --max-time 15 http://127.0.0.1/"; then
|
||||
log "ABORT: CT101 does not respond on http://127.0.0.1/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "START sync CT101 → CT600"
|
||||
|
||||
DB_FILE="${STAGING}/wordpress.sql.gz"
|
||||
log "DB dump (single-transaction, read-only)..."
|
||||
if ! ssh -o BatchMode=yes -o ConnectTimeout=30 "$HETZNER_HOST" \
|
||||
"ionice -c3 nice -n 19 pct exec ${HETZNER_CT} -- docker exec wordpress-mysql mysqldump \
|
||||
-u${MYSQL_USER} -p${MYSQL_PASS} \
|
||||
--single-transaction --quick --skip-lock-tables \
|
||||
--add-drop-table ${MYSQL_DB} 2>/dev/null" | gzip > "${DB_FILE}.tmp"; then
|
||||
log "ABORT: mysqldump failed"
|
||||
rm -f "${DB_FILE}.tmp"
|
||||
exit 1
|
||||
fi
|
||||
mv "${DB_FILE}.tmp" "$DB_FILE"
|
||||
log "DB dump size: $(du -h "$DB_FILE" | awk '{print $1}')"
|
||||
|
||||
log "File sync via tar (read-only, ~5–8 min)..."
|
||||
tar_sync_files
|
||||
log "Files staged: $(du -sh "${STAGING}/wpfiles" | awk '{print $1}')"
|
||||
|
||||
log "Starting CT600 for import..."
|
||||
if [[ "$(pct status "$MIRROR_CT" | awk '{print $2}')" != "running" ]]; then
|
||||
pct start "$MIRROR_CT"
|
||||
fi
|
||||
for _ in $(seq 1 45); do
|
||||
if pct exec "$MIRROR_CT" -- docker info >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
pct exec "$MIRROR_CT" -- docker stop wordpress-app 2>/dev/null || true
|
||||
|
||||
log "Import DB into CT600..."
|
||||
gunzip -c "$DB_FILE" | pct exec "$MIRROR_CT" -- docker exec -i wordpress-mysql \
|
||||
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB"
|
||||
|
||||
log "Import files into CT600..."
|
||||
tar c -C "${STAGING}/wpfiles" . 2>/dev/null | pct exec "$MIRROR_CT" -- tar x -C "$WP_VOL"
|
||||
|
||||
log "Reset mirror idle siteurl/home..."
|
||||
pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB" -e \
|
||||
"UPDATE wp_options SET option_value='${MIRROR_SITEURL}' WHERE option_name IN ('siteurl','home');"
|
||||
|
||||
pct exec "$MIRROR_CT" -- docker start wordpress-app
|
||||
sleep 5
|
||||
|
||||
POSTS="$(pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -N -e \
|
||||
"SELECT COUNT(*) FROM wp_posts WHERE post_status='publish' AND post_type='post';" "$MYSQL_DB" 2>/dev/null)"
|
||||
LAST="$(pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -N -e \
|
||||
"SELECT MAX(post_date) FROM wp_posts WHERE post_type='post';" "$MYSQL_DB" 2>/dev/null)"
|
||||
log "Mirror verified: ${POSTS} published posts, latest ${LAST}"
|
||||
|
||||
if ! ssh -o BatchMode=yes -o ConnectTimeout=15 "$HETZNER_HOST" \
|
||||
"pct exec ${HETZNER_CT} -- curl -sf -o /dev/null --max-time 15 http://127.0.0.1/"; then
|
||||
log "WARN: CT101 health check failed AFTER sync — investigate immediately"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Stopping CT600 (standby)..."
|
||||
pct stop "$MIRROR_CT"
|
||||
log "DONE"
|
||||
Loading…
Add table
Reference in a new issue