بکاپ و ریستور MySQL داخل Docker و Docker Compose

وقتی MySQL داخل کانتینر است، mysqldump را با docker exec یا docker compose exec اجرا می‌کنید و خروجی را روی میزبان ذخیره می‌کنید. نکتهٔ مهم گزینهٔ -T در compose و استفاده از volume برای ماندگاری داده است.

دیتابیس و بکاپمتوسط8 دقیقه

۱نمونهٔ docker-compose برای MySQL با volume

بدون volume با حذف کانتینر همهٔ داده‌ها از بین می‌رود. رمز را از فایل .env بخوانید.

yaml
services:
  db:
    image: mysql:8.4
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: appdb
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "127.0.0.1:3306:3306"
volumes:
  mysql_data:

پورت را فقط روی 127.0.0.1 منتشر کنید تا از بیرون سرور در دسترس نباشد.

۲بکاپ با docker compose exec

گزینهٔ -T لازم است، وگرنه compose ترمینال تعاملی می‌سازد و خروجی فایل خراب می‌شود. رمز را از متغیر محیطی داخل کانتینر بخوانید.

bash
docker compose exec -T db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" \
  --single-transaction --routines --events --no-tablespaces appdb' \
  | gzip > appdb_$(date +%F_%H-%M).sql.gz

۳بکاپ با docker exec (بدون compose)

اگر کانتینر را با docker run ساخته‌اید:

bash
docker exec mysql-container sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction appdb' \
  > appdb.sql

۴ریستور داخل کانتینر

خروجی فایل را با ورودی استاندارد به mysql داخل کانتینر بدهید. اینجا هم از -T و نه -it استفاده کنید.

bash
zcat appdb_2026-09-29_03-00.sql.gz | docker compose exec -T db sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" appdb'

ریستور جدول‌های همنام را بازنویسی می‌کند؛ اول روی یک دیتابیس آزمایشی امتحان کنید.

۵بکاپ مستقیم از volume (فیزیکی)

برای بکاپ فایل‌های داده، ابتدا کانتینر را متوقف کنید تا داده‌ها سازگار باشند، سپس محتوای volume را در یک tar بریزید.

bash
docker compose stop db
docker run --rm -v mysql_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/mysql_data_$(date +%F).tgz -C /data .
docker compose start db

بکاپ فیزیکی فقط وقتی معتبر است که MySQL خاموش باشد. برای بکاپ بدون توقف از mysqldump استفاده کنید.

۶زمان‌بندی با cron

یک اسکریپت کوچک بنویسید و آن را با cron اجرا کنید.

bash
#!/usr/bin/env bash
set -euo pipefail
cd /opt/myapp
OUT=/var/backups/mysql/appdb_$(date +%F_%H-%M).sql.gz
docker compose exec -T db sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction --routines --events --no-tablespaces appdb' | gzip > "$OUT"
find /var/backups/mysql -name 'appdb_*.sql.gz' -mtime +14 -delete

# crontab -e :
# 0 3 * * * /usr/local/bin/mysql-docker-backup.sh >> /var/log/mysql-backup.log 2>&1

پرسش‌های پرتکرار دربارهٔ بکاپ و ریستور MySQL داخل Docker و Docker Compose

چرا فایل بکاپ خالی یا خراب شد؟

معمولاً به‌خاطر نبودن گزینهٔ -T در docker compose exec است (ترمینال تعاملی به خروجی اضافه می‌کند) یا اشتباه بودن رمز. خروجی خطا را قبل از فشرده‌سازی بررسی کنید.