Backup ฐานข้อมูลด้วย Laravel อย่างง่าย ๆ ด้วย Spatie DB Snapshots
14 มีนาคม 2566
ใน Laravel รองรับ การสร้าง Schema ฐานข้อมูล ด้วย migration อยู่แล้ว ช่วยให้เราสามารถ เพิ่ม/ลด field หรือตารางใน database ของเราตาม feature ที่เรามีการพัฒนาขึ้นบนเวป ทีนี้ถ้าเราต้องการจะ backup ฐานข้อมูลเราสามารถใช้ package ของ Spatie ที่ชื่อว่า Laravel DB Snapshots เพื่อ ทำการ back up ฐานข้อมูลไว้ได้
จุดเด่นของ Package นี้มีตามนี้เลยครับ:
- สามารถ back up database แต่ละ environment ที่เรามีได้ ไม่ว่าจะเป็น local, develop, หรือ production ตามที่เรา set ไว้ ใน .env
- สามารถ back up หลาย ๆ database ได้ตามแต่ละ connection
- สามารถ back up ให้เก็บข้อมูลย้อนหลังรายวันได้ และมี Artisan command ให้เคลียร์ไฟล์ back up เก่า ๆ ที่ไม่ต้องการแล้วได้อีกด้วย
- รองรับหลากหลาย DBMS ทั้ง mysql, mariadb, และ postgres อย่างน้อย 3 DB นี้ที่ผมเคยใช้มาโดยตรงจาก project ที่พัฒนา
- สามารถ เก็บเป็นไฟล์ SQL หรือให้ compress เป็น .zip เพื่อลดขนาดไฟล์ได้
- สามารถ Restore โหลดไฟล์ backup กลับเข้า database ได้ง่าย ๆ เหมาะสำหรับต้องการ backup ข้อมูลจาก production เพื่อเอากลับมาทดสอบใน Local ก่อนได้
วิธีการติดตั้ง package:
composer require spatie/laravel-db-snapshots
ทำการ สร้างไฟล์ config ด้วยคำสั่ง vendor:publish
php artisan vendor:publish --provider="Spatie\DbSnapshots\DbSnapshotsServiceProvider"
โดย default package นี้จะสร้าง ไฟล์ back up ไว้ใน disk ที่ชื่อว่า snapshots
ซึ่งแน่นอนว่าไม่ได้มี disk นี้ใน config เริ่มต้นของ Laravel ไปยัง app/config/filesystems.php
เพื่อเพิ่ม disk snapshots และระบุ path ที่เราต้องการเก็บไฟล์ไว้
// ...
'disks' => [
// ...
'snapshots' => [
'driver' => 'local',
'root' => database_path('snapshots'),
],
// ...
เมื่อเรา config เรียบร้อยแล้ว สามารถ run คำสั่ง artisan เพื่อ backup ฐานข้อมูลได้เลย
// default ชื่อไฟล์จะเป็น Y-m-d H:i:s `2023-03-17 14:31.sql`
php artisan snapshot:create
โดย package ทำการ back up ตารางทั้งหมด ใน default database connection ใน project ของเรา
ถ้าอยากตั้งชื่อไฟล์ backup สามารถระบุชื่อไฟล์ไว้เป็น parameter ในคำสั่งได้เลย
// ได้ไฟล์ชื่อ backup-1.sql
php artisan snapshot:create backup-1
หากฐานข้อมูลเรามีขนาดใหญ่ เราสามารถสั่งให้ command zip ไฟล์ backup ให้เราได้ โดยระบุ parameter --compress
// `2023-03-17 14:31.zip`
php artisan snapshot:create --compress
ถ้าไม่อยากต้องระบุ parameter นี้ทุกครั้งสามารถ กำหนดใน ไฟล์ config app/config/db-snapshots.php
ได้เลย
return [
'disk' => 'snapshots',
/*
* Create dump files that are gzipped
*/
'compress' => true,
// ....
];
โดยปกติเวลา run คำสั่ง schema:create บ่อย ๆ จะมีชื่อไฟล์ backup เกิดขึ้น ตาม วันที่และเวลาที่ run คำสั่งนั้นไว้ package นี้ก็มีคำสั่งช่วยให้เราเคลียร์ไฟล์ backup เก่า ๆ ที่ไม่ต้องการใช้แล้วออกไปได้
php artisan snapshot:cleanup --keep=2
จากคำสั่งด้านบน จะลบไฟล์ back up เก่า ๆ ออกทั้งหมดเหลือไว้เพียง 2 ไฟล์ล่าสุดที่เราเพิ่งสร้างขึ้นมา
เมื่อเรามีไฟล์ backup เรียบร้อยแล้ว เราสามารถทำการ restore database ได้ด้วยคำสั่ง
php artisan snapshot:load
ถ้าเรามีไฟล์ backup เก็บไว้หลายไฟล์ package นี้จะถามไฟล์ back up ที่เราต้องการ restore ไปยัง default database connection ที่ set ไว้ใน project ของเรา
ถ้าเราต้องการ restore ไปยังคนละ database จากที่เรา back up มา เราสามารถสั่งให้ restore ไปยัง environment หรือ connection อื่นที่เราต้องการได้
php artisan snapshot:load --env=local
php artisan snapshot:load --connection=staging
จากคำสั่งทั้งหมดข้างต้น เราสามารถให้ package นี้ ทำ daily backup ฐานข้อมูลให้เราเป็นรายวันได้เลย เพียงแค่เราเพิ่มคำสั่ง snapshot:create ไว้ใน Schedule ของ Console Kernel ใน Project
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule)
{
$schedule->command('snapshot:create')->daily();
$schedule->command('snapshot:cleanup --keep 7')->daily();
// run back up ทุกวันตอนเที่ยงคืน โดยเก็บไฟล์ไว้ 7 วันล่าสุด
}
}
ศึกษาวิธีการ set cron และ Schedule เพิ่มเติมจาก Laravel Documentation
อีกประโยชน์หนึ่งของ package นี้นอกจากทำ Schedule back up แล้ว ถ้าใน project เรามีการทำ CI/CD หรือมีการใช้ migration ในการ update schema ฐานข้อมูล เราก็สามารถเพิ่ม คำสั่งนี้ไว้ใน deploy step ของเราได้ เพื่อป้องกัน การ run migrate ผิดพลาด ทำให้เรา restore database กลับมาได้ก่อนป้องกันข้อมูลเสียหายบน production นะครับ
สามารถศึกษารายละเอียดเพิ่มเติม package นี้จาก GitHub ได้โดยตรงครับ