理解Docker(8):Docker 儲存之卷(Volume)

weixin_34120274發表於2016-10-06

(1)Docker 安裝及基本用法

(2)Docker 映象

(3)Docker 容器的隔離性 - 使用 Linux namespace 隔離容器的執行環境

(4)Docker 容器的隔離性 - 使用 cgroups 限制容器使用的資源

(5)Docker 網路

(6)若干企業生產環境中的容器網路方案

(7)Docker 儲存 - AUFS

(8)Docker 儲存 - Volume

 

1. Docker volume 的幾種形態

    有狀態容器都有資料持久化需求。前一篇文章中提到過,Docker 採用 AFUS 分層檔案系統時,檔案系統的改動都是發生在最上面的容器層。在容器的生命週期內,它是持續的,包括容器在被停止後。但是,當容器被刪除後,該資料層也隨之被刪除了。因此,Docker 採用 volume (卷)的形式來向容器提供持久化儲存。Docker volume 有如下幾種形態。

1.1 無 - 不使用 Docker volume

預設情況下,容器不使用任何 volume,此時,容器的資料被儲存在容器之內,它只在容器的生命週期記憶體在,會隨著容器的被刪除而被刪除。當然,也可以使用 docker commit 命令將它持久化為一個新的映象。

1.2 Data volume (資料卷)

一個 data volume 是容器中繞過 Union 檔案系統的一個特定的目錄。它被設計用來儲存資料,而不管容器的生命週期。因此,當你刪除一個容器時,Docker 肯定不會自動地刪除一個volume。有如下幾種方式來使用 data volume:

(1)使用 “-v 容器內目錄” 形式

docker run -d -P --name web -v /webapp training/webapp python app.py

使用 docker inspect 命令可以看出,Docker 將本地一個 _data 目錄 mount 為容器內的 webapp 目錄了:

"Mounts": [
            {
                "Name": "f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b",
                "Source": "/var/lib/docker/volumes/f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b/_data",
                "Destination": "/webapp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

其實,在 web 容器被刪除後,/var/lib/docker/volumes/f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b/_data 目錄及其中的內容都還會保留下來,但是,新啟動的容器無法再使用這個目錄,也就是說,已有的資料不能自動地被重複使用了。

(2)使用 -v 來掛載一個主機上的目錄到容器的目錄

docker run -d -P --name web2 -v /src/webapp:/webapp training/webapp python app.py

主機上的目錄可以是一個本地目錄,也可以在一個 NFS share 內,或者在一個已經格式化好了的塊裝置上。

其實這種形式和第一種沒有本質的區別,容器內對 /webapp 的操作都會反映到主機上的 /src/webapp 目錄內。只是,重新啟動容器時,可以再次使用同樣的方式來將 /src/webapp 目錄掛載到新的容器內,這樣就可以實現資料持久化的目標。

(3)使用 -v 來掛載主機上的一個檔案到容器內的一個檔案

docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash

1.3 使用 data container

如果要在容器之間共享資料,最好是使用 data container。這種 container 中不會跑應用,而只是掛載一個卷。比如:

建立一個 data container:

docker create -v /dbdata --name dbstore training/webapp  /bin/true

啟動一個 app container:

docker run -d -P --name web3 --volumes-from dbstore training/webapp python app.py

其實,對 web3 這個容器來說,volume 的本質沒變,它只是將 dbstore 容器的 /dbdata 目錄對映的主機上的目錄對映到自身的 /dbdata 目錄。

"Mounts": [
            {
                "Name": "5341c03f3b94f13f4c86d88ccb0f3b63487adf30dea7ae6b2d06e947235e7330",
                "Source": "/var/lib/docker/volumes/5341c03f3b94f13f4c86d88ccb0f3b63487adf30dea7ae6b2d06e947235e7330/_data",
                "Destination": "/dbdata",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

但是,其好處是,可以不管其目錄的臨時性而不斷地重複使用它。

1.4 使用 docker volume 命令

Docker 新版本中引入了 docker volume 命令來管理 Docker volume。

(1)使用預設的 ‘local’ driver 建立一個 volume

root@docker1:/home/sammy# docker volume create --name vol1
vol1
root@docker1:/home/sammy# docker volume inspect vol1
[
    {
        "Name": "vol1",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/vol1/_data",
        "Labels": {},
        "Scope": "local"
    }
]

(2)使用這個 volume

docker run -d -P --name web4 -v vol1:/volume training/webapp python app.p

結果還是一樣的,即將 vol1 對應的主機上的目錄掛載給容器內的 /volume 目錄。

"Mounts": [
            {
                "Name": "vol1",
                "Source": "/var/lib/docker/volumes/vol1/_data",
                "Destination": "/volume",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

1.5 Volume 刪除和孤單 volume 清理

1.5.1 在刪除容器時刪除 volume

可以使用 docker rm -v 命令在刪除容器時刪除該容器的卷。

root@docker1:/home/sammy# docker run -d -P --name web5 -v /webapp training/webapp python app.py
69199905a74cb360935e32f4e99f7f11319f6aa36033a920aa0bae25874f5c69
root@docker1:/home/sammy# docker volume ls
DRIVER              VOLUME NAME
local               5341c03f3b94f13f4c86d88ccb0f3b63487adf30dea7ae6b2d06e947235e7330
local               838f4dd99721a9445be22a6b42d35e04cb43ad145ecf26107a9025f428587f76
local               vol1
root@docker1:/home/sammy# docker rm -vf web5
web5
root@docker1:/home/sammy# docker volume ls
DRIVER              VOLUME NAME
local               5341c03f3b94f13f4c86d88ccb0f3b63487adf30dea7ae6b2d06e947235e7330
local               vol1

1.5.2 批量刪除孤單 volumes

從上面的介紹可以看出,使用 docker run -v 啟動的容器被刪除以後,在主機上會遺留下來孤單的卷。可以使用下面的簡單方法來做清理:

root@docker1:/home/sammy# docker volume ls -qf dangling=true
244a23f3ab11f17345a68e77f96bb46a8dbaf445760dd86ab0faa07dfbd84236
c864cfac232e8728b1805abc8c363d324124b38e6297544a8cbbf61d883c7e46
f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b
root@docker1:/home/sammy# docker volume rm $(docker volume ls -qf dangling=true)
244a23f3ab11f17345a68e77f96bb46a8dbaf445760dd86ab0faa07dfbd84236
c864cfac232e8728b1805abc8c363d324124b38e6297544a8cbbf61d883c7e46
f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b
root@docker1:/home/sammy# docker volume ls
DRIVER              VOLUME NAME
local               5341c03f3b94f13f4c86d88ccb0f3b63487adf30dea7ae6b2d06e947235e7330
local               vol1

github 上有很多指令碼可以自動化地清理孤單卷,比如:

1.6 小結

對以上內容的兩點小結:

  • 容器內的資料是臨時性的,它會隨著容器生命週期的結束而消失
  • 預設的 Docker volume (driver = ‘loclal’)不管是哪種形式,本質上都是將容器所在的主機上的一個目錄 mount 到容器內的一個目錄,因此,它不具備可移植性。

2. Flocker:容器的分散式儲存平臺

第一部分提到過,原生的 Docker volume 不具備可移植性。於是,出現了Docker 的分散式卷解決方案 Flocker。先來看看 Flocker volume 和 Docker 原生 volume 的對比:

啟動一個使用 Flocker 卷的容器:

docker run --volume-driver flocker -v flocker-volume:/container/dir --name=container-xyz

它帶來的好處包括:

  • 容器的資料會被寫入 Flocker 後端儲存而不是主機上,因此,在主機出現故障時可以保證資料不丟失
  • 在容器遷移時,Flocker 會自動地將卷從一個 host 移植到另一個 host

Flocker 的結構:

 

相關文章