跳至主要内容

5.1 無/有狀態的應用程式

這個章節將圍繞在使用容器時,如何保存資料,以及保存資料為什麼會成為一個問題呢?

過往印象中保存資料的方式不外乎就是以檔案的形式儲存在電腦中,或是將資料寫入資料庫 ( MySQL、PostgreSQL ... ),但這又為什麼會成為使用 Docker 的一個課題呢?

要知道使用容器時通常有兩個核心的概念,分別是 immutable ( 不可變動的 ) 以及 ephemeral ( 短暫的 )

雖然都是一些看起來很潮的字眼,但說穿了就是可以隨意的刪除容器並利用同一個映像檔在啟動一個相同的容器,且不會對整體的應用程式造成任何的副作用。

immutable 的概念

目的就是讓我們可以不斷地根據相同的映像檔啟動容器,且每次都是相同的,也可以說容器本身是無狀態的運作環境,而無狀態簡而言之就是每一次的執行都是獨立的,不會根據上一次的運作情況而有所改變。

所以容器也是,每一次根據相同的映像檔執行容器都是獨立的,上一次進入了容器安裝了 curl 這個套件,刪掉容器後,根據相同的映像檔再次執行容器時,裡面是不會有 curl 這個套件的。

而這麼做的好處在於維護性以及一致性,若是我們真的需要 curl 這個套件,那就應該從根本改變,把它寫入映像檔中,再重新根據映像檔執行容器,而不是進入容器中做這種一次性的改動。

試想看看,今天應用程式出了 Bug,第一種作法是進入容器中,修改檔案,讓它運作正常;第二種作法是更改程式碼,並重新建置映像檔然後在重啟容器,讓它運作正常。

以速度來說,第一種或許真的很快,但因為某種不明原因,容器掛了,我們在重新啟動之後,Bug 依然存在,那這樣到底要進入容器幾次呢?

而第二種方法就是把根基做好,當今天多花個 5 分鐘,修改程式碼,合併分支,重新建置映像檔,就可以根治這個 Bug,開心地去放假,而不是假日接到電話。

ephemeral 的概念

其實和 immutable 是密不可分的,因為容器本身是無狀態的,導致其生命週期非常短暫,而生命週期短暫的好處帶來的就是重新啟動的速度以及沒有任何的副作用。

既然都沒有狀態,那資料怎麼辦?

綜合以上兩個使用容器的核心概念,那應用程式所產生的資料該怎麼辦呢?不論是資料庫 ( MySQL、PostgreSQL ... )或是快取 ( Redis、Memcached ... ) 以及那些和映像檔的檔案系統分割開來的資料該怎麼處理呢?

當然,容器本身並不應該儲存這些額外的資料到映像檔之中,你能想像這樣映像檔會變得多麼的巨大嗎?每一次的部署會需要花費多少的時間呢?

而根據 關注點分離(Separation of concerns,SoC ) 的策略,Docker 提供了 Volume 以及 Bind Mount ( 掛載 ) 的方式來做到保存狀態這件事情。

每當更新應用程式的版本、重新啟動容器時,這些資料都會存在,所以在 Docker 中,容器和 Volume 本身就是兩個模組,也是兩個不同的物件,這是 Docker 為了實踐有狀態的應用程式所給出的答案。

Volume 則是在容器磁碟空間外的一個儲存空間,換言之,可以像使用 Docker 虛擬網路時一樣,把 Volume 連接到任何想要連接的容器上,而在容器自己看來,它不過就是磁碟空間中的一個路徑或是一個檔案目錄。

Bind Mount 則是將本機的檔案或檔案目錄掛載到容器內,Bind Mount 這個功能名字取得真的好,對於像我這種資質駑鈍的人來說,是很有畫面的。而對於容器本身來說,它也不會知道這檔案是不是掛載進來的,因為它也不過就是磁碟空間中的一個路徑或是一個檔案目錄。

當然這兩種用法在現在看來很相似,但在實際使用上卻有一些不一樣的地方。