docker容器技術學習筆記(7、docker存儲)

Docker 存儲

Docker 爲容器提供了兩種存放數據的資源:
1、由 storage driver 管理的鏡像層和容器層。
2、Data Volume。

storage driver

Docker 鏡像的分層結構,簡單回顧一下:

容器由最上面一個可寫的容器層,以及若干只讀的鏡像層組成,容器的數據就存放在這些層中。這樣的分層結構最大的特性是 Copy-on-Write:
1、新數據會直接存放在最上面的容器層。
2、修改現有數據會先從鏡像層將數據複製到容器層,修改後的數據直接保存在容器層中,鏡像層保持不變。
3、如果多個層中有命名相同的文件,用戶只能看到最上面那層中的文件。

分層結構使鏡像和容器的創建、共享以及分發變得非常高效,而這些都要歸功於 Docker storage driver。正是 storage driver 實現了多層數據的堆疊併爲用戶提供一個單一的合併之後的統一視圖

Docker 支持多種 storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它們都能實現分層的架構,同時又有各自的特性。對於 Docker 用戶來說,具體選擇使用哪個 storage driver 是一個難題,因爲:
1、沒有哪個 driver 能夠適應所有的場景。
2、driver 本身在快速發展和迭代。

不過 Docker 官方給出了一個簡單的答案:
優先使用 Linux 發行版默認的 storage driver。Docker 安裝時會根據當前系統的配置選擇默認的 driver。默認 driver 具有最好的穩定性,因爲默認 driver 在發行版上經過了嚴格的測試。

運行docker info可以查看默認 driver。
Ubuntu 用的 AUFS,底層文件系統是 extfs,各層數據存放在 /var/lib/docker/aufs。
Redhat/CentOS 的默認 driver 是 Device Mapper,SUSE 則是 Btrfs。

對於某些容器,直接將數據放在由 storage driver 維護的層中是很好的選擇,比如那些無狀態的應用。無狀態意味着容器沒有需要持久化的數據,隨時可以從鏡像直接創建

Data Volume

有持久化數據的需求,容器啓動時需要加載已有的數據,容器銷燬時希望保留產生的新數據,也就是說,這類容器是有狀態的。這就要用到 Docker 的另一種存儲機制:Data Volume。

Data Volume 本質上是 Docker Host 文件系統中的目錄或文件,能夠直接被 mount 到容器的文件系統中。Data Volume 有以下特點:
1、Data Volume 是目錄或文件,而非沒有格式化的磁盤(塊設備)。
2、容器可以讀寫 volume 中的數據。
3、volume 數據可以被永久的保存,即使使用它的容器已經銷燬。

現在我們有數據層(鏡像層和容器層)和 volume 都可以用來存放數據,具體使用的時候要怎樣選擇呢?考慮下面幾個場景:
1、Database 軟件 vs Database 數據
2、Web 應用 vs 應用產生的日誌
3、數據分析軟件 vs input/output 數據
4、Apache Server vs 靜態 HTML 文件

相信大家會做出這樣的選擇:
1、前者放在數據層中。因爲這部分內容是無狀態的,應該作爲鏡像的一部分。
2、後者放在 Data Volume 中。這是需要持久化的數據,並且應該與鏡像分開存放

docker 提供了兩種類型的 volume:bind mount 和 docker managed volume。

  • bind mount

bind mount 是將 host 上已存在的目錄或文件 mount 到容器。
通過 -v 將其 mount 到容器,-v 的格式爲 <host path>:<container path>。
bind mount 時還可以指定數據的讀寫權限,默認是可讀可寫,可指定爲只讀。
除了 bind mount 目錄,還可以單獨指定一個文件。使用 bind mount 單個文件的場景是:只需要向容器添加文件,不希望覆蓋整個目錄。

bind mount 的使用直觀高效,易於理解,但它也有不足的地方:bind mount 需要指定 host 文件系統的特定路徑,這就限制了容器的可移植性,當需要將容器遷移到其他 host,而該 host 沒有要 mount 的數據或者數據不在相同的路徑時,操作會失敗。移植性更好的方式是 docker managed volume。

  • docker managed volume

docker managed volume 與 bind mount 在使用上的最大區別是不需要指定 mount 源,指明 mount point 就行了。

docker managed volume 的創建過程:
1、容器啓動時,簡單的告訴 docker "我需要一個 volume 存放數據,幫我 mount 到目錄 /abc"。
2、docker 在 /var/lib/docker/volumes 中生成一個隨機目錄作爲 mount 源。
3、如果 /abc 已經存在,則將數據複製到 mount 源,
4、將 volume mount 到 /abc
除了通過 docker inspect 查看 volume,我們也可以用 docker volume 命令

兩種 data volume 的原理和基本使用方法,下面做個對比:
1、相同點:兩者都是 host 文件系統中的某個路徑。
2、不同點:

共享數據

  • 容器與 host 共享數據

我們有兩種類型的 data volume,它們均可實現在容器與 host 之間共享數據,但方式有所區別。

對於 bind mount 是非常明確的:直接將要共享的目錄 mount 到容器。
docker managed volume 就要麻煩點。由於 volume 位於 host 中的目錄,是在容器啓動時才生成,所以需要將共享數據拷貝到 volume 中。

docker cp 可以在容器和 host 之間拷貝數據,當然我們也可以直接通過 Linux 的 cp 命令複製到 /var/lib/docker/volumes/xxx。

  • 容器之間共享數據

1、用bind mount共享數據
第一種方法是將共享數據放在 bind mount 中,然後將其 mount 到多個容器。

2、用volume container共享數據
另一種在容器之間共享數據的方式是使用 volume container。volume container 是專門爲其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume。

下面我們創建一個 volume container:

docker create --name vc_data -v ~/htdocs:/usr/local/apache2/htdocs -v /other/useful/tools busybox

我們將容器命名爲 vc_data(vc 是 volume container 的縮寫)。注意這裏執行的是 docker create 命令,這是因爲 volume container 的作用只是提供數據,它本身不需要處於運行狀態。容器 mount 了兩個 volume:

1、bind mount,存放 web server 的靜態文件。
2、docker managed volume,存放一些實用工具(當然現在是空的,這裏只是做個示例)。
通過 docker inspect 可以查看到這兩個 volume

其他容器可以通過 --volumes-from 使用 vc_data 這個 volume container:

docker run --name web1 -d -p 80 --volumes-from vc_data httpd

容器已經成功共享了 volume container 中的 volume。

下面我們討論一下 volume container 的特點:
1、與 bind mount 相比,不必爲每一個容器指定 host path,所有 path 都在 volume container 中定義好了,容器只需與 volume container 關聯,實現了容器與 host 的解耦。
2、使用 volume container 的容器其 mount point 是一致的,有利於配置的規範和標準化,但也帶來一定的侷限,使用時需要綜合考慮。

3、用data-packed volume container共享數據
volume container 的數據歸根到底還是在 host 裏,有沒有辦法將數據完全放到 volume container 中,同時又能與其他容器共享呢?

當然可以,通常我們稱這種容器爲 data-packed volume container。其原理是將數據打包到鏡像中,然後通過 docker managed volume 共享。

volume 生命週期管理

Data Volume 中存放的是重要的應用數據,如何管理 volume 對應用至關重要。

  • 備份

因爲 volume 實際上是 host 文件系統中的目錄和文件,所以 volume 的備份實際上是對文件系統的備份。

  • 恢復

volume 的恢復也很簡單,如果數據損壞了,直接用之前備份的數據拷貝到 /myregistry 就可以了。

  • 遷移

如果我們想使用更新版本的 Registry,這就涉及到數據遷移,方法是:
1、docker stop 當前 Registry 容器。
2、啓動新版本容器並 mount 原有 volume。
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest

當然,在啓用新容器前要確保新版本的默認數據路徑是否發生變化。

  • 銷燬

docker 不會銷燬 bind mount,刪除數據的工作只能由 host 負責。對於 docker managed volume,在執行 docker rm 刪除容器時可以帶上 -v 參數,docker 會將容器使用到的 volume 一併刪除,但前提是沒有其他容器 mount 該 volume,目的是保護數據,非常合理。

刪除容器時沒有帶 -v 呢?這樣就會產生孤兒 volume,可以用 docker volume rm 刪除。如果想批量刪除孤兒 volume,可以執行:
docker volume rm $(docker volume ls -q)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章