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ù)復制到容器層驰吓,修改后的數(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 能夠適應所有的場景程剥。
2劝枣、driver 本身在快速發(fā)展和迭代。
不過 Docker 官方給出了一個簡單的答案:
優(yōu)先使用 Linux 發(fā)行版默認的 storage driver织鲸。Docker 安裝時會根據(jù)當前系統(tǒng)的配置選擇默認的 driver舔腾。默認 driver 具有最好的穩(wěn)定性,因為默認 driver 在發(fā)行版上經(jīng)過了嚴格的測試搂擦。
運行docker info可以查看默認 driver稳诚。
Ubuntu 用的 AUFS,底層文件系統(tǒng)是 extfs瀑踢,各層數(shù)據(jù)存放在 /var/lib/docker/aufs扳还。
Redhat/CentOS 的默認 driver 是 Device Mapper,SUSE 則是 Btrfs橱夭。
對于某些容器氨距,直接將數(shù)據(jù)放在由 storage driver 維護的層中是很好的選擇,比如那些無狀態(tài)的應用棘劣。無狀態(tài)意味著容器沒有需要持久化的數(shù)據(jù)俏让,隨時可以從鏡像直接創(chuàng)建。
Data Volume
有持久化數(shù)據(jù)的需求,容器啟動時需要加載已有的數(shù)據(jù)首昔,容器銷毀時希望保留產(chǎn)生的新數(shù)據(jù)寡喝,也就是說,這類容器是有狀態(tài)的勒奇。這就要用到 Docker 的另一種存儲機制:Data Volume拘荡。
Data Volume 本質(zhì)上是 Docker Host 文件系統(tǒng)中的目錄或文件,能夠直接被 mount 到容器的文件系統(tǒng)中撬陵。Data Volume 有以下特點:
1珊皿、Data Volume 是目錄或文件,而非沒有格式化的磁盤(塊設備)巨税。
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 應用 vs 應用產(chǎn)生的日志
3肆资、數(shù)據(jù)分析軟件 vs input/output 數(shù)據(jù)
4、Apache Server vs 靜態(tài) HTML 文件
相信大家會做出這樣的選擇:
1灶芝、前者放在數(shù)據(jù)層中郑原。因為這部分內(nèi)容是無狀態(tài)的,應該作為鏡像的一部分夜涕。
2犯犁、后者放在 Data Volume 中。這是需要持久化的數(shù)據(jù)女器,并且應該與鏡像分開存放
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)限,默認是可讀可寫俏拱,可指定為只讀暑塑。
除了 bind mount 目錄,還可以單獨指定一個文件锅必。使用 bind mount 單個文件的場景是:只需要向容器添加文件,不希望覆蓋整個目錄。
bind mount 的使用直觀高效搞隐,易于理解驹愚,但它也有不足的地方:bind mount 需要指定 host 文件系統(tǒ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 中生成一個隨機目錄作為 mount 源嗜湃。
3奈应、如果 /abc 已經(jīng)存在,則將數(shù)據(jù)復制到 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ù)朵你,當然我們也可以直接通過 Linux 的 cp 命令復制到 /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ù),它本身不需要處于運行狀態(tài)秤标。容器 mount 了兩個 volume:
1绝淡、bind mount,存放 web server 的靜態(tài)文件苍姜。
2牢酵、docker managed volume,存放一些實用工具(當然現(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ī)范和標準化,但也帶來一定的局限算谈,使用時需要綜合考慮涩禀。
3、用data-packed volume container共享數(shù)據(jù)
volume container 的數(shù)據(jù)歸根到底還是在 host 里然眼,有沒有辦法將數(shù)據(jù)完全放到 volume container 中艾船,同時又能與其他容器共享呢?
當然可以高每,通常我們稱這種容器為 data-packed volume container屿岂。其原理是將數(shù)據(jù)打包到鏡像中,然后通過 docker managed volume 共享鲸匿。
volume 生命周期管理
Data Volume 中存放的是重要的應用數(shù)據(jù)爷怀,如何管理 volume 對應用至關(guān)重要。
- 備份
因為 volume 實際上是 host 文件系統(tǒng)中的目錄和文件带欢,所以 volume 的備份實際上是對文件系統(tǒng)的備份运授。
- 恢復
volume 的恢復也很簡單烤惊,如果數(shù)據(jù)損壞了,直接用之前備份的數(shù)據(jù)拷貝到 /myregistry 就可以了徒坡。
- 遷移
如果我們想使用更新版本的 Registry撕氧,這就涉及到數(shù)據(jù)遷移瘤缩,方法是:
1喇完、docker stop 當前 Registry 容器。
2剥啤、啟動新版本容器并 mount 原有 volume锦溪。
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest
當然,在啟用新容器前要確保新版本的默認數(shù)據(jù)路徑是否發(fā)生變化府怯。
- 銷毀
docker 不會銷毀 bind mount刻诊,刪除數(shù)據(jù)的工作只能由 host 負責。對于 docker managed volume牺丙,在執(zhí)行 docker rm 刪除容器時可以帶上 -v 參數(shù)则涯,docker 會將容器使用到的 volume 一并刪除,但前提是沒有其他容器 mount 該 volume冲簿,目的是保護數(shù)據(jù)粟判,非常合理。
刪除容器時沒有帶 -v 呢峦剔?這樣就會產(chǎn)生孤兒 volume档礁,可以用 docker volume rm 刪除。如果想批量刪除孤兒 volume吝沫,可以執(zhí)行:
docker volume rm $(docker volume ls -q)