在Docker內執行資料庫,不管是傳統的MySQL、MariaDB這些關聯式資料庫,或是NoSQL的MongoDB文件型資料庫都很方便。透過Docker的pull指令拉取image就可以執行,省了一些安裝的麻煩。在Docker裡面還可以隨時切換版本,透過Docker的隔離執行能力還能讓不同版本的資料庫同時在電腦裡面運作,非常方便。本篇文章將介紹如何備份在Docker內的資料庫,以及寫一個腳本讓電腦每天自動執行備份。

MySQL與MariaDB的備份還原

備份資料庫

docker exec CONTAINER_NAME sh -c "mysqldump -uroot -p DB_NAME" > db.dump

CONTAINER_NAME修改成你的資料庫的容器名稱,DB_NAME修改成要備份的資料庫名稱。最後db.dump是要備份的檔案名稱,這個檔案會儲存到HOST的硬碟上,而不是容器內的硬碟上。顯然dump.sql是一個相對位置,也可以輸入絕對位置,比如/backup/db.dump之類的。

還原資料庫

docker exec -i CONTAINER_NAME sh -c "mysql -uroot -p DB_NAME" < db.dump

還原時的作法跟之前差不多,箭頭從>變成<代表資料的流向。

docker exec -it CONTAINER_NAME mysql
use DB_NAME
set names utf8;
source dump.sql;

另一種還原方法是透過進入容器內的MySQL,使用source指令將資料還原進去,但這種方式db.dump要放在容器裡面也可以讀取到的地方。

還有一種方式是對新建立的MySQL、MariaDB容器,掛載需要的初始化資料到容器內的/docker-entrypoint-initdb.d/資料夾,例如dump.sql之類的檔案,MySQL與MariaDB在初次啟動時會自動建立資料庫,然後將/docker-entrypoint-initdb.d/資料夾內的SQL檔案載入資料庫內。

MongoDB的備份還原

備份資料庫

docker exec CONTAINER_NAME sh -c "exec mongodump -d DB_NAME --archive" > dump.archive

CONTAINER_NAME修改成你的資料庫的容器名稱DB_NAME修改成要備份的資料庫名稱。最後dump.archive是要備份的檔案名稱,備份的方法跟備份MySQL與MariaDB的方式差不多,指示指令稍稍換了。

還原資料庫

docker exec -i CONTAINER_NAME sh -c "exec mongorestore --drop --archive" < dump.archive

還原的時候可能會遇到編碼問題,可以在執行完元指令之前先設定一下編碼:
export LC_ALL="en_US.UTF-8"

上面的--drop代表還原前先將原本的資料庫刪除,如果不需要刪除舊資料庫可以移除--drop


在Linux與macOS上定時自動備份

crontab簡介

在Linux上我們使用crontab指令來執行自動備份,crontab會根據設定定時執行我們需要的程式。每個Linux使用者都有自己的crontab設定,只有使用root權限時才能編輯與查看其他使用者的設定。

crontab -l         # 查看目前設定
crontab -e         # 編輯設定
crontab -u user -l # 查看指定user的設定,需要加上sudo或是切換為root
crontab -u user -e # 編輯指定user的設定,需要加上sudo或是切換為root

建立備份腳本

建立一個bash腳本,讓crontab定時執行這個腳本即可完成自動備份。以下範例是備份MySQL或是MariaDB的腳本,使用時只需要修改前三行的參數,分別是容器名稱、資料庫名稱、儲存的位置即可使用,其中儲存位置使用的$(date),會使用執行當下的時間作為檔案名稱,因此產生出來的檔案會類似這樣:/backup/wordpress_20220802_210000.dump,可以自己依照需求做修改,例如不想存放在/backup資料夾的話直接改掉就可以囉。

CONTAINER=mysql
DB_NAME=wordpress
FILENAME=/backup/${DB_NAME}_$(date "+%Y%m%d_%H%M%S").dump

docker exec ${CONTAINER} sh -c "mysqldump -u root ${DB_NAME}" > ${FILENAME}
CONTAINER=mongodb
DB_NAME=wordpress
FILENAME=/backup/${DB_NAME}_$(date "+%Y%m%d_%H%M%S").archive

docker exec ${CONTAINER} sh -c "exec mongodump -d ${DB_NAME} --archive" > ${FILENAME}

使用時間作為檔案名稱的方法,可以參考我寫的另一篇:使用Linux Bash或是Windows Batch產生當前日期的檔案名稱

設定crontab執行時間

寫crontab的設定有好幾種方式,例如編輯/etc/crontab或是將設定檔放到/etc/cron.d裡面,在此我們使用的是下指令sudo crontab -e,將設定直接綁定root,好處是在這個情況下寫錯的話會無法儲存,並且告訴使用者哪裡寫錯了。在第一次使用時,系統可能會詢問使用者要使用哪一個編輯器,例如nano或是vim,選擇自己喜歡的就可以了。

crontab裡面一行文字代表一個設定,每行設定的開頭有五個數值,分別是「分 時 日 月 星期」,每個數值用半形空白分格,最後再一個空白就可以接著寫指令了。每個數值可以直接填上數字,或是打上星號*代表不限制,也可使用逗號寫好幾個數字,以下範例就是每天早上06:00與晚上18:00備份一次資料庫的寫法。

0 6,18 * * * sh /backup/dump_mysql.sh

存擋退出編輯器後就設定完成囉。

在Windows上定時自動備份

建立備份腳本

原理同Linux版本,從寫一個bash腳本變成寫一個batch腳本,只是Windows的上要使用時間作為檔名比較麻煩。使用時只需要修改CONTAINERDB_NAMEFILENAME即可使用囉。

set CONTAINER=mysql
set DB_NAME=wordpress
set NOW=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set FILENAME=C:/backup/%DB_NAME%_%NOW%.dump

docker exec %CONTAINER% sh -c "mysqldump -u root %DB_NAME%" > %FILENAME%
set CONTAINER=mongodb
set DB_NAME=wordpress
set NOW=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set FILENAME=C:/backup/%DB_NAME%_%NOW%.archive

docker exec %CONTAINER% sh -c "exec mongodump -d %DB_NAME% --archive" > %FILENAME%

使用時間作為檔案名稱的方法,可以參考我寫的另一篇:使用Linux Bash或是Windows Batch產生當前日期的檔案名稱

設定工作排程器

在Windows上會有一個叫做工作排程器的應用程式,放在「開始功能表/Windows 系統管理工具」裡面,也可以直接搜尋「工作排程器」即可找到。啟動後在左邊會有資料夾目錄,我習慣在「工作排程器程式庫」那邊按右鍵新增一個子料夾,我取名為My,很隨意的名字,獨立的資料夾比較方便管理。

在工作排程器程式庫點選「建立基本工作」,取個名字例如「Dump MySQL」之類的。按下「下一步」,觸發程序可以選擇「每天」,下圖的範例是每天早上六點整會備份一次。最後動作的部分選擇啟動程式,然後選擇我們剛才建立的Windows Batch腳本就可以囉。