https://unsplash.com/photos/dyu466BfWj8
上一篇認識了掛載,讓我們能夠將主機的資料夾連通到容器中。雖然單人在本地使用很方便,但缺點是下指令時,主機的路徑寫法會依賴於作業系統,導致寫法不能完全統一。例如 Windows 的絕對路徑表示方式,與 MacOS / Linux 就有很大的不同。
本文將介紹官方建議的「Volume」,它也是使用主機的空間來掛載,且儲存空間是被 Docker 管理的。所以在 Docker 指令中,能直接使用 volume 的名字作為參數值,不會受限於主機作業系統的差異。最後將以 MySQL 為例,簡單示範掛載的應用。
此篇內容轉載自本人在 iThome 的文章。
一、Volume 的操作
(一)建立
讓我們建立一個 volume,指令寫法為 docker volume create --name {名稱}。
假設取名為「my_space」,則範例指令如下:
docker volume create --name my_space
(二)查看
使用 docker volume ls 指令,可列出主機上現有的 volume。除了上面建立的「my_space」,讀者也許還會看到其他亂數名稱的 volume,那些是由其他 container 自行建立的。
例如 MySQL 資料庫的映像檔,會要求 Docker 在建立容器時,主動將儲存資料的路徑與 volume 進行掛載。
若要查看 volume 的詳細資訊,請使用 docker volume inspect {名稱} 指令。範例寫法如下。
docker volume inspect my_space
指令會回傳 JSON 格式的資料,範例結果如下。
[ { "CreatedAt": "2023-11-30T07:55:45Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/my_space/_data", "Name": "my_space", "Options": null, "Scope": "local" } ]
其中「Mountpoint」是 volume 對應主機的儲存位置。雖然筆者使用 Windows 系統,但 Docker Desktop 會安裝 Linux 子系統。該 volume 實際的空間便是在該 Linux 系統中。
(三)刪除
當 volume 不再需要了,可以將它們刪除。指令寫法為 docker volume rm {名稱}。範例指令如下:
docker volume rm my_space
要注意的是,當沒有任何容器在使用此 volume 時,才可以刪除。
二、使用 Volume 掛載
為了示範,本文以先前「【Docker】映像檔與容器的操作」文章提到的 docker/getting-started 映像檔作為練習對象。這會是個 hello world 性質的範例。
docker image pull docker/getting-started:latest
將 volume 掛載到容器的方式,與前面介紹的主機資料夾大同小異,只是把路徑換成 volume 名稱罷了。
docker container run -d -v my_space:"/container-test-folder" --name MyDockerTutorial -p 80:80 docker/getting-started:latest
或
docker container run -d -v my_space:"/container-test-folder" --name MyDockerTutorial -p 80:80 docker/getting-started:latest
docker container run -d --mount type=volume,source="my_space",destination="/container-volume-space" --name MyDockerTutorial -p 80:80 docker/getting-started:latest
要注意的是,如果掛載時選擇使用 --mount 參數,則 `type` 的值應給予「volume」。
三、搬遷資料
如果想要在 volume 進行資料的移入或移出,該怎麼做呢?其實 Docker 並沒有提供相關的指令。相對地,我們可使用「從容器複製資料到主機」及「從主機複製資料到容器」的指令,因為與 volume 是連通的。
將資料從主機複製到容器的指令寫法為 docker container cp {主機路徑} {容器名稱:容器路徑}。範例指令如下:
docker container cp ./test-host-image.png MyDockerTutorial:/test-container-image.png
若是要將資料從容器複製出來到主機,則先寫容器路徑,再寫主機路徑。
docker container cp MyDockerTutorial:/test-folder/test-image.png "C:\"
主機的路徑可使用相對路徑或絕對路徑。而容器即便未啟動,也可進行複製資料的動作。
四、在 MySQL 容器的應用
最後看看如何將掛載應用於 MySQL。本節使用以下的 MySQL 映像檔。
docker image pull mysql:8.2.0
(一)初始化資料庫
利用掛載,可以在建立資料庫容器後,做一些初始化。比方說我們希望資料庫中能夠預先準備好資料表(table)。
以下是一組範例 SQL 指令,可將其存為「.sql」檔。用途是在叫做「demo」的資料庫下,建立名為「student」的資料表。
CREATE TABLE `demo`.`student` ( `id` VARCHAR(20) NOT NULL, `studentId` VARCHAR(20) NOT NULL, `name` VARCHAR(20) NOT NULL, `birthday` DATE NOT NULL, PRIMARY KEY (`id`) );
在 MySQL 的容器中,有個叫做「docker-entrypoint-initdb.d」的資料夾。MySQL 會在容器初次啟動時,執行裡面的「.sql」檔。那麼要如何利用掛載,將想執行的 SQL 檔放入容器中的該資料夾呢?
首先示範綁定掛載。假設主機已準備好一個資料夾叫「db-init-scripts」,裡面有一至多個 SQL 檔。則建立 MySQL 容器時,可透過指令,將其掛載到容器的「docker-entrypoint-initdb.d」資料夾中。
docker container run -d -p 3306:3306 --name TestMySQL -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=demo -v "C:\db-init-scripts":"/docker-entrypoint-initdb.d" mysql:8.2.0
再來介紹檔案移入的做法。先把容器建立起來,但先不要立即啟動。
docker container create -p 3306:3306 --name TestMySQL -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=demo mysql:8.2.0
接著只要簡單地把要執行的檔案,都複製到容器中,即可啟動。
docker container cp . TestMySQL:"/docker-entrypoint-initdb.d"
(二)資料的備份
資料庫的初始化工作完成後,使用一陣子便會累積一些資料。本節使用的 MySQL 版本是 8.2.0,若我們想改用其他版,或者單純搬遷資料,則 DB 裡的資料就得備份出來,移動到新的容器。
MySQL 的容器會主動建立 volume,並掛載到「/var/lib/mysql」路徑。我們可以透過第一節第二段介紹的指令確認掛載資訊。
docker container inspect TestMySQL
在指令回傳的結果中,找到「Mounts」欄位,能看到容器的哪些資料夾被掛載到什麼地方。此處得知被掛載到叫做「bb8846...」的 volume。
[ { "...": "...", "Mounts": [ { "Type": "volume", "Name": "bb88460fef7dd96deae1692d8503add05f584ed3348c9e6c1c0dbe3fde340130", "Source": "/var/lib/docker/volumes/bb88460fef7dd96deae1692d8503add05f584ed3348c9e6c1c0dbe3fde340130/_data", "Destination": "/var/lib/mysql", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], "...": "..." } ]
備份資料時,正規的做法是採用「mysqldump」指令,它位於容器的「/usr/bin」路徑下。
mysqldump -h localhost -u root -p demo > /var/lib/mysql/demo_backup_20231205.sql
總之備份完成後,會得到一個 SQL 檔。我們可以選擇將其移動到上述的 volume 保存,或者起初就建立一個專門存放的 volume 掛載到容器。
待有需要使用還原時,再依照本節第一段的做法,將其複製到新容器的「docker-entrypoint-initdb.d」資料夾,達到初始化的目的。
那如果忘記備份資料就刪除容器怎麼辦?有一個比較 workaround 的做法,就是隨便建立一個容器,把 volume 掛載上去。再從容器中被掛載的資料夾,複製想要的資料出來。
留言
張貼留言