【Docker】透過綁定掛載讓主機連通容器


https://unsplash.com/photos/dyu466BfWj8

容器中運行的軟體可能會產生資料,例如 log 檔。而這些資料都是存放於容器中,若刪除容器,這些資料也會連帶消失。為了做到資料的持久化,需對容器做「掛載」(mount)的動作。掛載能夠將主機的檔案空間,直通容器之內,方便我們管理當中的資料。

本文的目的是讓讀者認識什麼是掛載,以及使用起來的效果,並介紹相關的指令參數。而下一篇才會介紹「Volume 掛載」。

此篇內容轉載自本人在 iThome 的文章


一、為什麼要掛載

以筆者的工作經驗為例,Spring Boot 後端程式每天都會將當日的 log,獨立儲存成一份 log 檔。如果是發生 exception,或 ERROR 等級的 log,還會另外存一份。

這些檔案會隨著容器的刪除而消失。如果因為上版或其他原因,需重新建立容器,結果忘記備份重要資料,那就糟了!而備份時會透過指令,從容器內部複製資料出來,也比較不方便。

另一方面,使用 Spring Boot 時可能會由外部(獨立於 JAR 檔之外)提供如「application.properties」的 config 配置檔。若配置檔內容需要調整,也是要特地進入容器中進行修正。

基於這些列舉的情境,為了便於存取重要資料,並做到持久化,因此我們需要進行掛載。這樣就能在主機的檔案系統,管理容器中的資料。

為了示範,本文以前面「【Docker】映像檔與容器的操作」文章提到的「docker/getting-started」映像檔作為練習對象。這會是個 hello world 性質的範例。

docker image pull docker/getting-started:latest

二、掛載主機資料夾

筆者將以 Windows 系統的電腦當作主機來示範。本節最終想要做到的,是在 Windows 上,能夠對容器中的資料進行移入或移出。

在建立容器的指令中,可添加掛載相關的參數,指令寫法為:
docker container run -v {主機絕對路徑}:{容器路徑} {其他參數}

範例指令如下:

docker container run -d -v "C:\host-test-folder":"/container-test-folder" --name MyDockerTutorial -p 80:80 docker/getting-started:latest

此處會將主機的「C:\host-test-folder」資料夾,掛載到容器的「container-test-folder」資料夾。若雙方資料夾不存在,則 Docker 將自動建立。要注意的是,若容器在該路徑下,已存在相同名稱的資料夾,則會以主機資料夾覆蓋。

接著讀者可以在「host-test-folder」資料夾中隨意放一個檔案,例如文字檔。此時進入容器查看,會發現該檔案已經在容器中了。請參考下圖操作指令。


三、設定唯讀

在使用 -v 參數進行掛載時,除了主機路徑與容器路徑,還能提供「唯讀」或「可讀寫」的參數值。

再次以 Spring Boot 後端程式為例。假設掛載了兩個資料夾,一個存放產生的 log 檔,另一個存放讓程式讀取的 config 檔。那麼我們並不預期容器中運行的軟體,會對後者的資料夾新增檔案,甚至修改原資料。

掛載時,可以額外設定該資料夾是否為唯讀。參數寫法為 -v {主機絕對路徑}:{容器路徑}:{ro | rw}。其中 ro 代表唯讀(read only),rw 代表可讀寫(read write)。

建立容器的範例指令如下:

docker container run -d -v "C:\host-test-folder":"/container-test-folder":ro --name MyDockerTutorial -p 80:80 docker/getting-started:latest

讀者可進入容器,試著在「container-test-folder」路徑下新增資料夾、新增檔案或使用 vi 編輯器修改檔案,會得到「Read-only file system」的訊息。如此一來,我們只能單方面從主機端異動該資料夾了,達到了保護的效果。


四、使用 mount 參數

除了使用 -v 參數進行掛載,也能使用 --mount 參數。前者較簡潔,而後者的可讀性更好。

該參數的寫法為 --mount type={掛載方式},source={主機絕對路徑},destination={容器路徑},readonly

建立容器的範例指令如下:

docker container run -d --mount type=bind,source="C:\host-test-folder",destination="/container-test-folder",readonly --name MyDockerTutorial -p 80:80 docker/getting-started:latest

可以看到 --mount 參數會使用「key=value」的格式提供參數。

其中的 type 參數,由於此處是示範掛載主機資料夾,所以值固定傳入 bind。這種使用主機資料夾的做法,同時也被稱作本文標題的「綁定掛載」。另外,若省略 readonly 參數,則視為「可讀寫」。


五、掛載單一檔案

上面示範如何掛載整個資料夾到容器中,而檔案當然也行。

舉例來說,Redis 資料庫的配置檔叫做 redis.conf;而全文檢索引擎 Elasticsearch 的配置檔叫做 elasticsearch.yml。我們可以在主機準備好軟體所需的檔案,再單獨掛載到容器中。

指令的寫法與掛載資料夾並無不同,範例寫法如下。

docker container run -d -v "C:\test-config.json":"/container-app-config.json" --name MyDockerTutorial -p 80:80 docker/getting-started:latest

docker container run -d --mount type=bind,source="C:\test-config.json",destination="/container-app-config.json" --name MyDockerTutorial -p 80:80 docker/getting-started:latest

要注意的是,若容器的目的地資料夾已存在相同名稱的檔案,則會以主機的檔案進行覆蓋。而容器資料夾的其他檔案或子資料夾,則不受影響。

本文基於練習目的,掛載時是使用主機的檔案系統。因此在下指令時,掛載來源路徑的寫法,將依賴於主機的作業系統。若換成在 MacOS 或 Linux 系統上使用 Docker,則參數值就得隨之調整了。為了在操作上能保持一致,我們可改用 Docker 提供的「Volume」,於下一篇介紹。

上一篇:【Docker】使用環境變數建立容器(以 MySQL 為例)

下一篇:【Docker】透過 Volume 來處理掛載(以 MySQL 為例)

留言