2023 iT邦鐵人賽 Day 14 - 容器的資料儲存-約定掛載
前言
前幾天,我們不斷地在說明容器,對容器的熟悉度應該就像認識三十年的朋友一樣熟悉了。但這樣還是不夠的,我們必須要知道,你朋友的錢存在哪裡 (咦!?)。
今天我們就來談談朋友的錢存在哪(容器裡應用程式產生的資料存在哪)吧。
檔案系統
每個容器都有屬於自己的檔案系統,而最基本的檔案系統是由映像檔的共享層與容器內的可寫層所構成。
可寫層
映像檔本身是多個層 ( Layer ) 所組成,就像一份漢堡的組成一樣,一層又一層。
當容器建立並啟動時,容器的檔案系統除了有映像檔的各層以外,docker 會自動加入可寫層,以供容器有個暫時儲存資料與檔案的地方。
因此,可寫層是跟隨著容器的生命週期,可寫層會在容器被刪除後,也跟著消失,所以:
1 | 容器裡產生的資料 ---> 可寫層 ---> 容器被刪除 ---> 可寫層被刪除 ---> 資料消失 |
但這不是我們想要遇到的問題,在前一篇可知,容器的汰舊換新是常態。
除了前一篇提到的更替狀況,還有一種情況是,部署新版 (新的功能或是修復已知 bug) 的專案時,這時我們會一定是部署新的容器上去,並把舊的刪掉。敏感的你,是不是察覺不對勁?
Production 的資料是不是就啪一聲的不見了….?
我們當然不能因為更新就讓會員資料全部都消失殆盡,所以 docker 有提供了永續性的資料儲存方式: 約定掛載 與 Volume。
約定掛載 / 綁定掛載
說文解字。約定,即雙方意思合意,你心甘、我情願,因此在雙方認定的範圍內,互通有無; 掛載,也就是將元件、資料等與其他元件跟資料或系統連結。
在 docker 裡,就是透過設定 (約定),將本機資料與容器連結在一起 (掛載):
- 將本機的資料夾掛載到容器內,使資料雙向綁定。
- 當掛載的目標資料夾已存在檔案時,而使用約定掛載時,會被本機的資料夾所覆蓋,此時容器的資料只會有本機資料夾內的資料。
- 若在約定掛載時,掛載來源為單一檔案,此時會與容器內的資料互相合併。
指令
--mount type=bind,source="容器內資料儲存的目錄",target="本機資料夾目錄"
沒錯,你沒看錯,這一整串就是在做約定掛載,我們需要指定資料流通的兩端( source, target )。
type、source、target 之間必須要有逗號,且逗號間不能有空格。
什麼?好麻煩?OK, Docker 聽到你的心聲了,那就用 -v 容器內資料儲存的目錄:本機資料夾目錄
吧
範例
- 在目錄
/Users/mike/Desktop/bind
裡建立index.html
檔案 - 在
body
tag 裡面輸入任何你想要的畫面設計,這裡為了簡單示範,我在我的index.html
只輸入<h1>**This is new data</h1>
** - 輸入以下約定指令:
1 | docker container run --mount type=bind,source="/Users/mike/Desktop/bind",target="/usr/local/apache2/htdocs/" -p 8001:80 -d httpd |
原本在 http://localhost:8001/
應該會出現 It Works!
,現在變成**This is new data
。**
這代表,目前已經將我綁定的本機目錄與容器連上了,資料雙向流通。
那為什麼原本是 It Works!
,現在變了。那是因為在容器裡, /usr/local/apache2/htdocs/
底下,原本有 index.html
檔案,現在經過約定掛載後,將原本容器內的資料給覆蓋過去。如上面說明的第三點。
補充
大家可以嘗試建立一個無掛載的 httpd 跟有掛載的 httpd,並使用 inspect
看一下兩者容器內的 Mounts
。
總結
今天的東西可能會比較難一點,我們來做個總結吧。
現在我們知道,容器的資料可以存放在暫時性的可寫層,但可寫層會跟容器一起被刪掉,導致資料無法長存於世,這對 production 來說,不堪使用。
於是我們有掛載的方法,將資料長期存放。透過約定掛載,我們可以將容器的資料存放在本機的資料夾 (目錄) 中,同時我們也可以更改本機裡的資料。
因為內容有點龐大,用一篇寫完後發現,東西實在太多了 (汗),為了減輕讀者負擔,所以今天先只說明檔案系統跟約定掛載,明天我們會來講解另一個神秘空間 volume。
關於「層」,我們會在之後特別寫一篇文章為大家解釋。今天我們先暫時為了可寫層,間單對映像檔做個基本介紹。