docker容器技術(shù)學(xué)習(xí)筆記(7、docker存儲)

Docker 存儲

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

storage driver

Docker 鏡像的分層結(jié)構(gòu),簡單回顧一下:

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

分層結(jié)構(gòu)使鏡像和容器的創(chuàng)建、共享以及分發(fā)變得非常高效,而這些都要歸功于 Docker storage driver。正是 storage driver 實現(xiàn)了多層數(shù)據(jù)的堆疊并為用戶提供一個單一的合并之后的統(tǒng)一視圖

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

不過 Docker 官方給出了一個簡單的答案:
優(yōu)先使用 Linux 發(fā)行版默認(rèn)的 storage driver。Docker 安裝時會根據(jù)當(dāng)前系統(tǒng)的配置選擇默認(rèn)的 driver。默認(rèn) driver 具有最好的穩(wěn)定性,因為默認(rèn) driver 在發(fā)行版上經(jīng)過了嚴(yán)格的測試。

運(yùn)行docker info可以查看默認(rèn) driver。
Ubuntu 用的 AUFS,底層文件系統(tǒng)是 extfs,各層數(shù)據(jù)存放在 /var/lib/docker/aufs。
Redhat/CentOS 的默認(rèn) driver 是 Device Mapper,SUSE 則是 Btrfs。

對于某些容器,直接將數(shù)據(jù)放在由 storage driver 維護(hù)的層中是很好的選擇,比如那些無狀態(tài)的應(yīng)用。無狀態(tài)意味著容器沒有需要持久化的數(shù)據(jù),隨時可以從鏡像直接創(chuàng)建。

Data Volume

有持久化數(shù)據(jù)的需求,容器啟動時需要加載已有的數(shù)據(jù),容器銷毀時希望保留產(chǎn)生的新數(shù)據(jù),也就是說,這類容器是有狀態(tài)的。這就要用到 Docker 的另一種存儲機(jī)制:Data Volume。

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

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

相信大家會做出這樣的選擇:
1、前者放在數(shù)據(jù)層中。因為這部分內(nèi)容是無狀態(tài)的,應(yīng)該作為鏡像的一部分。
2、后者放在 Data Volume 中。這是需要持久化的數(shù)據(jù),并且應(yīng)該與鏡像分開存放

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

  • bind mount

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

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

  • docker managed volume

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

docker managed volume 的創(chuàng)建過程:
1、容器啟動時,簡單的告訴 docker "我需要一個 volume 存放數(shù)據(jù),幫我 mount 到目錄 /abc"。
2、docker 在 /var/lib/docker/volumes 中生成一個隨機(jī)目錄作為 mount 源。
3、如果 /abc 已經(jīng)存在,則將數(shù)據(jù)復(fù)制到 mount 源,
4、將 volume mount 到 /abc
除了通過 docker inspect 查看 volume,我們也可以用 docker volume 命令

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

共享數(shù)據(jù)

  • 容器與 host 共享數(shù)據(jù)

我們有兩種類型的 data volume,它們均可實現(xiàn)在容器與 host 之間共享數(shù)據(jù),但方式有所區(qū)別。

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

docker cp 可以在容器和 host 之間拷貝數(shù)據(jù),當(dāng)然我們也可以直接通過 Linux 的 cp 命令復(fù)制到 /var/lib/docker/volumes/xxx。

  • 容器之間共享數(shù)據(jù)

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

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

下面我們創(chuàng)建一個 volume container:

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

我們將容器命名為 vc_data(vc 是 volume container 的縮寫)。注意這里執(zhí)行的是 docker create 命令,這是因為 volume container 的作用只是提供數(shù)據(jù),它本身不需要處于運(yùn)行狀態(tài)。容器 mount 了兩個 volume:

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

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

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

容器已經(jīng)成功共享了 volume container 中的 volume。

下面我們討論一下 volume container 的特點:
1、與 bind mount 相比,不必為每一個容器指定 host path,所有 path 都在 volume container 中定義好了,容器只需與 volume container 關(guān)聯(lián),實現(xiàn)了容器與 host 的解耦。
2、使用 volume container 的容器其 mount point 是一致的,有利于配置的規(guī)范和標(biāo)準(zhǔn)化,但也帶來一定的局限,使用時需要綜合考慮。

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

當(dāng)然可以,通常我們稱這種容器為 data-packed volume container。其原理是將數(shù)據(jù)打包到鏡像中,然后通過 docker managed volume 共享。

volume 生命周期管理

Data Volume 中存放的是重要的應(yīng)用數(shù)據(jù),如何管理 volume 對應(yīng)用至關(guān)重要。

  • 備份

因為 volume 實際上是 host 文件系統(tǒng)中的目錄和文件,所以 volume 的備份實際上是對文件系統(tǒng)的備份。

  • 恢復(fù)

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

  • 遷移

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

當(dāng)然,在啟用新容器前要確保新版本的默認(rèn)數(shù)據(jù)路徑是否發(fā)生變化。

  • 銷毀

docker 不會銷毀 bind mount,刪除數(shù)據(jù)的工作只能由 host 負(fù)責(zé)。對于 docker managed volume,在執(zhí)行 docker rm 刪除容器時可以帶上 -v 參數(shù),docker 會將容器使用到的 volume 一并刪除,但前提是沒有其他容器 mount 該 volume,目的是保護(hù)數(shù)據(jù),非常合理。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容