Backup Django ง่ายกว่านี้ไม่มีอีกแล้วด้วย django-dbbackup
Tags: django, database, devops, python
Published: 2020-05-17 05:17:58

ช่วงนี้ผมต้องมาขึ้น Django project ใหม่กับทีมครับ ซึ่งพอขึ้น Project ใหม่ หนึ่งใน Development workflow ที่มาคู่กันคือ การต้องเอา Database จาก Production กลับมาใช้ที่ Local development ให้ได้ เพื่อที่จะ debug ปัญหาหลายๆ อย่างได้กับ Data บน Production หรือ เพื่อความสะดวกสบายในการ Development ครับ

ทีนี้ที่ผ่านมามันไม่ค่อยมีปัญหาเพราะ Database ผมมักจะใช้ PostgreSQL ซึ่งอาจจะอยู่ใน database Instance ของตัวเอง อยู่บน Container ของตัวเอง ฯลฯ ซึ่งก็ใช้ `pg_dump` กับ `pg_restore` คู่กันง่ายๆ มาตลอด ไม่มีปัญหายเว้นอัพเกรด PostgreSQL major version ที่ไฟล์ format เปลี่ยนนิดหน่อยก็ตามอัพเกรด client กัน

ปัญหามันอยู่ที่ Media files ครับ ซึ่งถ้าเลือกได้ ผมจะเลือกใช้ [django-storages](https://github.com/jschneier/django-storages) เพื่อที่จะ offload ตัว media file ไปเก็บไว้ใน object storage เช่น Amazon s3 หรือ Google Cloud Storage ครับ แต่ใน use case ที่เราเลือกไม่ได้ต้องเก็บไฟล์ลง server เท่านั้น เราจะทำยังไงหละ

พอมี Use case แบบนี้แวบแรกที่ผมคิดออกคือ `rsync` เลยครับ ง่ายๆ บ้านๆ sync directory ที่ต้องเก็บ Media กลับมาลงใน local  แต่ผมตั้งคำถามกับตัวเองว่ามันมีวิธีอื่นมั้ย มันเลยเกิด post นี้ขึ้นนี่แหละครับ

## Django Database Backup

ผมค้นไปเจอ [django-dbbackup](https://django-dbbackup.readthedocs.io/en/stable/index.html) เพราะคิดว่าจะทำยังไงถึงจะ backup database / media files ได้พร้อมกันเลย ไม่ต้องมานั่งทำทีละอย่าง เรียกได้ว่า รันคำสั่งเดียวปุ๊ปได้ Data พร้อมใช้งานใน local เลย ซึ่งสารภาพว่าแวบแรกก็นึกว่าจะเขียน Ansible playbook ไปเลย แต่ถ้าทีมไม่ได้มี Technical ลึกหละ

ตัว Django  Database Backup นี่เป็น Package ที่ไม่ได้ซับซ้อนอะไรเลยครับ ไม่ได้ Reinvent the wheel การ backup ขึ้นมาใหม่ เป็นไอเดียง่ายๆ แค่ dump / restore ไฟล์ อาจจะรวม compresion กับ encryption ขึ้นมานิดหน่อย แต่ไม่ได้สลับซับซ้อนอะไรเลย โดยตัว Package จะเป็น extension app ของ Django ที่ provide management command ต่างๆ มาให้เราทำงานได้ง่ายขึ้นครับ

วิธีลงไม่ยากแค่สั่ง pip install django-dbbackup หรือจะเพิ่ม dependencies ลงใน requirements.txt, Pipfile, pyproject.toml เอาที่สะดวกเลยครับ พอลงเสร็จแล้วมีจุดที่เราต้อง config เบื้องต้นเพิ่มใน Django settings file เรา 2 อย่าง

- อย่างแรกเลยคือให้เราเพิ่ม INSTALLED_APPS ชื่อ dbbackup ลงไปครับ ซึ่งจะเอาไว้ตรงไหนก็ได้ order ไม่สำคัญ

    ```python
    INSTALLED_APPS = (
        ...
        'dbbackup',  # django-dbbackup
    )
    ```

- อย่างที่สองคือ เราต้องเพิ่ม settings เพื่อที่จะบอกว่า Backup เราเนี่ยจะเก็บไว้ที่ไหน​ซึ่งสามารถเก็บไว้ได้ทั้ง Amazon S3, Dropbox, FTP แต่ในเคสง่ายๆ เราเก็บไว้ใน File System ในโปรเจ็คเราก็ได้ครับหน้าตาประมาณนี้

    ```python
    DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage'
    DBBACKUP_STORAGE_OPTIONS = {'location': '/app/backups'}
    ```

    ตรงจุดนี้ระวังนิดนึงนะครับมี bug ใน document ตรง DBBACKUP_STORAGE มันจะชี้ไปที่ `dbbackup.storage.filesystem_storage` ซึ่งที่ถูกต้องคือ `django.core.files.storage.FileSystemStorage` ครับ

## Usage

หลังจากที่เราติดตั้งเสร็จแล้ว config เสร็จแล้วทีนี้เราก็สามารถใช้งาน Django database backup ได้แล้วครับ ซึ่งมันไม่ได้แค่ backup database ตามชื่อ แต่ครอบคลุมไปถึง Media ด้วย

### Backup / restore Media

ถ้าเราจะ Backup ตัว Media file เราก็ใช้ management command `mediabackup` ได้เลยครับตัว output จะออกมาคล้ายๆ ตัวอย่างข้างล่างเลย คือเป็นไฟล์ compress ของ media ใน Django app เราครับ 

```bash
$ python manage.py mediabackup
Writing file to 7b23e710c576-2020-05-17-044731.tar
```

ส่วนถ้าเราอยากจะ restore ก็แค่ใช้ command `mediarestore` ครับ ซึ่งสามารถเลือกไฟล์เองก็ได้ แต่ถ้า structure ของไฟล์ไม่ต่างกันเราสามารถเรียกได้เลยครับ แล้วตัว Django dbbackup มันฉลาดพอจะเลือกไฟล์ล่าสุดมา restore ครับ รวมถึงถ้าไม่มี directory ก็จะสร้างให้หมดเลยด้วย

```bash
$ python manage.py mediarestore
Restoring backup for media files
Finding latest backup
Restoring: 7b23e710c576-2020-05-17-044843.tar
Are you sure you want to continue? [Y/n] Y
some_media_path/image1.png uploaded
some_media_path/image2.png uploaded
some_media_path/image3.png uploaded
```

### Backup / Restore Database

ในส่วนของ Backup database จะมีความยุ่งยากกว่า Media นิดนึงตรงที่เราต้องมี client ของ Database ตัวนั้นจริงๆ อยู่ในเครื่องที่เราจะรัน command นี้ด้วยครับเช่น เคสผมใช้ PostgreSQL ก็ต้องมี `postgresql-client` ในเครื่องก่อน มันถึงจะพาเพื่อนอย่าง `pg_dump`, `pg_restore` มาด้วย แต่ข้อควรระวังอีกอย่างคือ ลง postgrsql-client ให้มันตรงกับ version PosgreSQL ที่เราใช้ด้วยนะครับ ในเคสนี้ผมแค่สั่ง `apt install postgresql-client-12` ก็เรียบร้อยครับ 

พอเรามี client ในเครื่องแล้วที่เหลือก็ง่ายเลย แทนที่เราจะต้องมาสั่ง pg_dump ด้วย option ยาวๆ เราก็ใช้ management command `dbbackup` สั่ง โดยตัว Django dbbackup ก็จะไปดูด database settings 

ของเรามา fill ให้ไม่ต้องมาจำเอง

```bash
$ python [manage.py](http://manage.py/) dbbackup
Backing Up Database: postgres
Writing file to default-7b23e710c576-2020-05-17-050714.psql
```

ส่วนวิธี restore ก็จะเก่งเหมือน Media restore ที่รู้จักไฟล์ล่าสุดครับ ส่วน command ก็สั้นๆ แค่ `dbrestore` พอสั่งเสร็จเราก็ได้ database backup มาใช้ละ

```bash
$ python manage.py dbrestore
Finding latest backup
Restoring backup for database 'default' and server 'None'
Restoring: default-7b23e710c576-2020-05-17-050714.psql
Restore tempfile created: 62.2 KiB
Are you sure you want to continue? [Y/n] Y
```

จบแล้วครับ ง่ายๆ แค่นี้เลย จริงๆ ตัว Django dbbackup ยังทำอย่างอื่นได้อีกทั้ง encryption , filename prefix หรือ จะตั้ง limit ให้เก็บแค่กี่ไฟล์ล่าสุดก็ได้ ก็ลองอ่านได้ใน Documentation ครับเขียนไว้ค่อนข้างอ่านง่ายเลย ก็หวังว่าชีวิตจะง่ายขึ้นกันนะครับ หลังจากนี้ 🐍🐮

## Reference

- [https://github.com/django-dbbackup/django-dbbackup](https://github.com/django-dbbackup/django-dbbackup)
- [https://django-dbbackup.readthedocs.io/en/stable/](https://django-dbbackup.readthedocs.io/en/stable/)