前言

前陣子因為專案需求,需要把某個 docker 的 PostgreSQL container 資料備份到另一台 docker container 內,因此紀錄一下整體過程

簡例

首先,先拉取 postgresql 14.6 版的 image

docker pull postgres:14.6
docker image | grep postgres  # 取得image id

再來準備一份測試的 seed.csv,等等要匯入 postgresql 中

title,content
Eric,Hello
Madi,Hi
Danny,GoAhead
Kyle,Looks grood

將 postgresql 的 container 跑起來,並 bind mount 掛載剛剛的 csv 檔

docker run -itd --rm --name example -p 5432:5432 -v "$(pwd)"/seed.csv:/seed.csv -e POSTGRES_PASSWORD=postgres <image_id>

接著,跳進去 container 內,把 csv 的內容匯入 postgresql 中

docker exec -it example psql -U postgres -d postgres
/* 要先依照csv的內容建立table */
CREATE TABLE article(title text, content text);

/* 將csv匯入table */
COPY article (title, content) FROM '/seed.csv' WITH (FORMAT CSV, HEADER TRUE);

/* 確認資料是否匯入成功 */
SELECT * FROM article;
 title |   content
-------+-------------
 Eric  | Hello
 Madi  | Hi
 Danny | GoAhead
 Kyle  | Looks grood
(4 rows)

確認資料匯入成功後,再來模擬需求,目標是把剛剛匯入的 posgresql 的資料 dump 出來,匯到另一個 container

Dump postgresql 資料的語法是

pg_dump -U <user> -h <host> -p <port> <DB name> >> /path/to/backup.sql

用 docker 一行指令完成,通常會在檔名上壓一個 timestamp

docker exec -it example pg_dump -U postgres -h localhost -p 5432 postgres >> dump_`date +%Y%m%d"_"%H%M%S`.sql

完成後,會在當前本機路徑生成一個 .sql 檔,這個就是等等要給另一個 container 匯入的資料

啟動另一個名為 example2 的 postgresql container

docker run -itd --rm --name example2 -p 5433:5432 -e POSTGRES_PASSWORD=postgres <image id>

啟動好之後,將剛剛的 .sql 檔匯給這個新 container

需注意 docker exec 不需要加上 -t 因為不是 TTY

cat ./<dumpfile>.sql | docker exec -i example2 psql -U postgres

撈一下資料看看是否匯入成功

docker exec -it example2 psql -U postgres -d postgres -c "SELECT * FROM article"
 title |   content
-------+-------------
 Eric  | Hello
 Madi  | Hi
 Danny | GoAhead
 Kyle  | Looks grood
(4 rows)

資料轉移成功!

除此之外,其實 restore 還有另一種方式,就是使用 psql 的 -f 參數來指定 file

psql -U postgres -h localhost -p 5433 -f <dumpfile>.sql

總結

去蕪存菁,總結就是以下指令:

# Backup
docker exec -it <container1> pg_dump -U postgres -h localhost -p 5432 <db_name> >> dump_`date +%Y%m%d"_"%H%M%S`.sql

# Create Database Before Restoring
docker exec -it <container2> psql -U postgres -c "CREATE DATABASE \"db_name\";"

# Restore - M1
cat ./<dumpfile>.sql | docker exec -i <container2> psql -U postgres -d <db_name>
# Restore - M2
psql -U <user> -h <host> -p <port> -f <dumpfile>.sql

除此之外,也可以用 volumes 的備份方式,可以參考 Docker 官網的文件