ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

Home สำรองและกู้คืนข้อมูล Docker Volume

สำรองและกู้คืนข้อมูล Docker Volume

ข้อมูลสำคัญของแอปที่รันบน Docker เช่น ไฟล์อัปโหลดของเว็บไซต์หรือไฟล์ฐานข้อมูล มักเก็บอยู่ใน Docker Volume ซึ่งอยู่รอดแม้ลบ Container แต่ถ้าดิสก์เสีย ลบ Volume ผิดตัว หรือสั่ง docker compose down -v โดยไม่ตั้งใจ ข้อมูลจะหายทั้งหมด การสำรอง Volume ออกมาเป็นไฟล์แล้วเก็บไว้นอกเครื่องจึงจำเป็นเสมอ

บทความนี้แสดงวิธีสำรอง Volume เป็นไฟล์ .tar.gz ด้วย Container ชั่วคราว วิธีกู้คืนกลับ วิธีสำรองฐานข้อมูลใน Container อย่างถูกต้อง และการย้าย Volume ไปเครื่องใหม่

สิ่งที่ต้องเตรียม

  • Linux Server ที่ใช้ Docker Engine และ Docker Compose Plugin
  • สิทธิ์ sudo หรือผู้ใช้ในกลุ่ม docker
  • พื้นที่ดิสก์ว่างพอสำหรับไฟล์สำรอง ตรวจด้วย df -h
  • ที่เก็บไฟล์สำรองนอกเครื่อง เช่น เซิร์ฟเวอร์อีกเครื่อง

ขั้นตอนที่ 1: หาว่าข้อมูลอยู่ใน Volume ใด

docker volume ls
DRIVER    VOLUME NAME
local     wordpress_db_data
local     wordpress_wp_data

Volume ที่สร้างจาก Docker Compose จะมีชื่อโปรเจกต์ (ปกติคือชื่อโฟลเดอร์) นำหน้า ตรวจว่า Container ใด Mount Volume ไหนไว้ที่ path ใด

docker inspect -f '{{range .Mounts}}{{.Type}} {{.Name}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' wordpress-wordpress-1

คอลัมน์แรกบอกชนิด volume คือ Named Volume ที่ Docker จัดการ ส่วน bind คือโฟลเดอร์บนเครื่องที่ Mount เข้าไป ถ้าเป็น bind สามารถสำรองโฟลเดอร์นั้นด้วยเครื่องมือปกติ เช่น tar หรือ rsync ได้เลย ขั้นตอนต่อไปนี้ใช้กับชนิด volume

ข้อมูลใน Volumeวิธีสำรองที่แนะนำ
ไฟล์ทั่วไป (เว็บ, อัปโหลด, คอนฟิก)tar ผ่าน Container ชั่วคราว (ขั้นตอนที่ 2)
MySQL / MariaDBmariadb-dump หรือ mysqldump ผ่าน docker compose exec (ขั้นตอนที่ 3)
PostgreSQLpg_dump ผ่าน docker compose exec

ขั้นตอนที่ 2: สำรอง Volume เป็นไฟล์ tar

หลักการคือรัน Container ชั่วคราวจาก Image debian:bookworm-slim (มี GNU tar) ที่ Mount ทั้ง Volume และโฟลเดอร์สำรองบนเครื่อง แล้วใช้ tar บีบอัดข้อมูลออกมา

เพื่อให้ไฟล์สำรองสมบูรณ์ ควรหยุด Container ที่เขียนข้อมูลลง Volume ก่อน

cd /opt/wordpress
sudo docker compose stop
sudo mkdir -p /backup/docker
sudo docker run --rm \
  -v wordpress_wp_data:/data:ro \
  -v /backup/docker:/backup \
  debian:bookworm-slim tar --numeric-owner -czf /backup/wp_data-$(date +%F).tar.gz -C /data .
  • --rm ลบ Container ชั่วคราวทิ้งเมื่อเสร็จ
  • :ro Mount Volume แบบอ่านอย่างเดียว ป้องกันการแก้ข้อมูลโดยไม่ตั้งใจ
  • -C /data . ให้ tar เก็บ path แบบสัมพัทธ์ กู้คืนไปที่ Volume อื่นได้สะดวก
  • $(date +%F) ถูกแปลงบนเครื่องก่อนส่งเข้า Container ได้ชื่อไฟล์ เช่น wp_data-2026-09-19.tar.gz

เสร็จแล้วเริ่มระบบกลับ

sudo docker compose start

ตรวจเนื้อหาไฟล์สำรองโดยไม่ต้องแตกไฟล์

tar tzf /backup/docker/wp_data-2026-09-19.tar.gz | head

ควรเห็นรายการไฟล์ เช่น ./wp-config.php และ ./wp-content/

ขั้นตอนที่ 3: สำรองฐานข้อมูลใน Container ด้วย dump

การ tar โฟลเดอร์ข้อมูลของฐานข้อมูลขณะที่ยังทำงานอยู่ อาจได้ไฟล์ที่ไม่สอดคล้องกันและกู้คืนไม่ได้ วิธีที่ปลอดภัยกว่าคือ dump ข้อมูลออกมาเป็น SQL ขณะที่ระบบยังทำงาน ไม่ต้องหยุดเว็บ

MariaDB (Image รุ่น 11 ใช้คำสั่ง mariadb-dump)

cd /opt/wordpress
sudo docker compose exec -T db sh -c \
  'exec mariadb-dump --single-transaction --all-databases -uroot -p"$MARIADB_ROOT_PASSWORD"' \
  | gzip > /backup/docker/db-$(date +%F).sql.gz

MySQL 8 (Image mysql)

sudo docker compose exec -T db sh -c \
  'exec mysqldump --single-transaction --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' \
  | gzip > /backup/docker/db-$(date +%F).sql.gz

ใส่ -T ทุกครั้งเมื่อส่งผลลัพธ์ออกไปยังไฟล์ เพื่อไม่ให้ Docker จัดสรร TTY ซึ่งจะแทรกอักขระพิเศษลงในไฟล์ SQL ส่วน sh -c '...' ในเครื่องหมายคำพูดเดี่ยว ทำให้ตัวแปรรหัสผ่านถูกอ่านจาก Environment ภายใน Container ไม่ต้องพิมพ์รหัสผ่านบน Command Line ของเครื่อง

รายละเอียดตัวเลือกของ dump และการกู้คืนบางตาราง ดูที่ สำรองและกู้คืนฐานข้อมูล MySQL/MariaDB ด้วย mysqldump สำหรับ PostgreSQL ดู สำรองและกู้คืน PostgreSQL ด้วย pg_dump และ pg_restore

ขั้นตอนที่ 4: กู้คืน Volume จากไฟล์ tar

หมายเหตุ: การกู้คืนจะเขียนทับข้อมูลใน Volume ปลายทาง ถ้า Volume เดิมยังมีข้อมูลที่อาจต้องใช้ ให้สำรองมันอีกชุดตามขั้นตอนที่ 2 ก่อนเสมอ

หยุด Container ที่ใช้ Volume นั้นก่อน

cd /opt/wordpress
sudo docker compose stop wordpress

ถ้าต้องการกู้คืนให้ Volume สะอาดเหมือนตอนสำรอง ให้ลบไฟล์เดิมใน Volume แล้วแตกไฟล์สำรอง

sudo docker run --rm \
  -v wordpress_wp_data:/data \
  -v /backup/docker:/backup:ro \
  debian:bookworm-slim sh -c 'find /data -mindepth 1 -delete && tar --numeric-owner -xzf /backup/wp_data-2026-09-19.tar.gz -C /data'

ตรวจชื่อ Volume ปลายทางให้ถูกต้องก่อนกด Enter เพราะคำสั่ง find ... -delete ลบข้อมูลทั้งหมดใน Volume นั้นทันที ตัวเลือก --numeric-owner ทั้งตอนสำรองและกู้คืน ทำให้เจ้าของไฟล์ถูกเก็บและคืนเป็นหมายเลข UID/GID เดิม ไม่ถูกแปลงตามชื่อผู้ใช้ใน Container ชั่วคราว จึงไม่ต้องแก้สิทธิ์เพิ่มในกรณีส่วนใหญ่

sudo docker compose start wordpress

กู้คืนฐานข้อมูลจากไฟล์ dump

gunzip -c /backup/docker/db-2026-09-19.sql.gz | \
  sudo docker compose exec -T db sh -c 'exec mariadb -uroot -p"$MARIADB_ROOT_PASSWORD"'

สำหรับ Image mysql เปลี่ยน mariadb เป็น mysql และใช้ตัวแปร $MYSQL_ROOT_PASSWORD

ขั้นตอนที่ 5: ย้าย Volume ไปเครื่องใหม่

  1. สำรองไฟล์ตามขั้นตอนที่ 2 และ 3 บนเครื่องเดิม
  2. คัดลอกไฟล์ Compose, .env และไฟล์สำรองไปเครื่องใหม่ เช่น rsync -avP /backup/docker/ [email protected]:/backup/docker/ ดูเพิ่มที่ โอนไฟล์ระหว่างเครื่องด้วย scp และ sftp
  3. บนเครื่องใหม่ สั่ง sudo docker compose create เพื่อสร้าง Volume ว่างและ Container โดยยังไม่เริ่มทำงาน
  4. กู้คืน Volume ไฟล์ตามขั้นตอนที่ 4
  5. สำหรับฐานข้อมูล สั่ง sudo docker compose up -d db รอให้พร้อม แล้วนำเข้า dump
  6. สั่ง sudo docker compose up -d เพื่อเริ่มทุก Service

ขั้นตอนที่ 6: ตั้งสำรองอัตโนมัติ

สร้างสคริปต์ /usr/local/bin/docker-backup.sh

#!/bin/sh
set -e
cd /opt/wordpress
DATE=$(date +%F)
docker compose exec -T db sh -c \
  'exec mariadb-dump --single-transaction --all-databases -uroot -p"$MARIADB_ROOT_PASSWORD"' \
  | gzip > /backup/docker/db-$DATE.sql.gz
docker run --rm -v wordpress_wp_data:/data:ro -v /backup/docker:/backup \
  debian:bookworm-slim tar --numeric-owner -czf /backup/wp_data-$DATE.tar.gz -C /data .
find /backup/docker -name '*.gz' -mtime +14 -delete
sudo chmod 700 /usr/local/bin/docker-backup.sh
sudo crontab -e

เพิ่มบรรทัดให้รันทุกวันเวลา 02:30

30 2 * * * /usr/local/bin/docker-backup.sh >> /var/log/docker-backup.log 2>&1

สคริปต์นี้สำรองไฟล์ขณะ Container ยังทำงาน สำหรับเว็บ WordPress ทั่วไปถือว่ายอมรับได้เพราะฐานข้อมูลถูก dump แยกอย่างถูกต้องแล้ว บรรทัดสุดท้ายลบไฟล์ที่เก่ากว่า 14 วัน จากนั้นส่งไฟล์ออกนอกเครื่องตาม สำรองข้อมูลไปยังเซิร์ฟเวอร์อื่นด้วย rsync และ Cronjob

ตรวจสอบผลลัพธ์

  • ls -lh /backup/docker มีไฟล์ของวันนี้ และขนาดไม่เป็น 0 หรือเล็กผิดปกติ
  • gunzip -t /backup/docker/db-2026-09-19.sql.gz ไม่มี Error และ zcat ไฟล์ | tail -1 ขึ้นต้นด้วย -- Dump completed
  • ทดลองกู้คืนลง Volume ใหม่ชื่ออื่น เช่น test_restore แล้วดูไฟล์ด้วย sudo docker run --rm -v test_restore:/data debian:bookworm-slim ls -la /data ไฟล์สำรองที่ไม่เคยทดสอบกู้คืน ยังไม่นับว่าเป็นไฟล์สำรองที่ไว้ใจได้

ปัญหาที่พบบ่อย

ไฟล์สำรองว่างเปล่าหรือมีแค่โฟลเดอร์เดียว

พิมพ์ชื่อ Volume ผิด Docker จะสร้าง Volume ใหม่ที่ว่างเปล่าให้โดยอัตโนมัติ แทนที่จะแจ้ง Error ตรวจชื่อด้วย docker volume ls แล้วลบ Volume ที่สร้างผิดทิ้ง

ไฟล์ SQL มีข้อความแปลก ๆ หรือ Error ตอนนำเข้า

ลืมใส่ -T หรือรหัสผ่านผิดจนได้ข้อความ Error แทนข้อมูล เปิดดูต้นไฟล์ด้วย zcat ไฟล์ | head

หลังกู้คืน เว็บขึ้น Permission denied

ไฟล์ถูกแตกด้วยเจ้าของไม่ตรง ตรวจด้วย sudo docker compose exec wordpress ls -ln /var/www/html สำหรับ Image WordPress เจ้าของควรเป็น UID 33 (www-data) แก้ด้วย sudo docker compose exec wordpress chown -R www-data:www-data /var/www/html

MariaDB ไม่ยอมเริ่มหลังกู้คืนโฟลเดอร์ข้อมูลด้วย tar

เป็นผลจากสำรองขณะฐานข้อมูลยังเขียนอยู่ หรือกู้คืนไปยัง Image เวอร์ชันต่ำกว่าเดิม ให้เริ่มจาก Volume ว่างแล้วนำเข้าไฟล์ dump แทน

หากต้องการคำแนะนำในการวางแผนสำรองข้อมูล ติดต่อทีมงาน THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/ และสามารถใช้ร่วมกับ การ Backup Server บน Cloud ของ TDC เพื่อสำรองทั้งเครื่องอีกชั้นหนึ่ง

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security