docker容器持久化卷講解
docker容器自身存儲數據效率比較低,因此我們為了提高磁盤IO的性能等,需要在容器中掛載一個外部存儲設備。關於講解大致如下:
Docker中的數據可以存儲在類似於虛擬機磁盤的介質中,在Docker中稱為數據卷(Data Volume)。數據卷可以用來存儲Docker應用的數據,也可以用來在Docker容器間進行數據共享。 數據卷呈現給Docker容器的形式就是一個目錄,支持多個容器間共享,修改也不會影響鏡像。使用Docker的數據卷,類似在系統中使用 mount 掛載一個文件系統。 1)一個數據卷是一個特別指定的目錄,該目錄利用容器的UFS文件系統可以為容器提供一些穩定的特性或者數據共享。數據卷可以在多個容器之間共享。2)創建數據卷,只要在docker run命令後面跟上-v參數即可創建一個數據卷,當然也可以跟多個-v參數來創建多個數據卷,當創建好帶有數據卷的容器後, 就可以在其他容器中通過--volumes-froms參數來掛載該數據卷了,而不管該容器是否運行。也可以在Dockerfile中通過VOLUME指令來增加一個或者多個數據卷。 3)如果有一些數據想在多個容器間共享,或者想在一些臨時性的容器中使用該數據,那麽最好的方案就是你創建一個數據卷容器,然後從該臨時性的容器中掛載該數據卷容器的數據。 這樣,即使刪除了剛開始的第一個數據卷容器或者中間層的數據卷容器,只要有其他容器使用數據卷,數據卷都不會被刪除的。4)不能使用docker export、save、cp等命令來備份數據卷的內容,因為數據卷是存在於鏡像之外的。備份的方法可以是創建一個新容器,掛載數據卷容器,同時掛載一個本地目錄, 然後把遠程數據卷容器的數據卷通過備份命令備份到映射的本地目錄裏面。如下: # docker run -rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data 5)也可以把一個本地主機的目錄當做數據卷掛載在容器上,同樣是在docker run後面跟-v參數,不過-v後面跟的不再是單獨的目錄了,它是[host-dir]:[container-dir]:[rw|ro]這樣格式的, host-dir是一個絕對路徑的地址,如果host-dir不存在,則docker會創建一個新的數據卷,如果host-dir存在,但是指向的是一個不存在的目錄,則docker也會創建該目錄,然後使用該目錄做數據源。 Docker Volume數據卷可以實現: 1)繞過“拷貝寫”系統,以達到本地磁盤IO的性能,(比如運行一個容器,在容器中對數據卷修改內容,會直接改變宿主機上的數據卷中的內容,所以是本地磁盤IO的性能,而不是先在容器中寫一份,最後還要將容器中的修改的內容拷貝出來進行同步。) 2)繞過“拷貝寫”系統,有些文件不需要在docker commit打包進鏡像文件。 3)數據卷可以在容器間共享和重用數據 4)數據卷可以在宿主和容器間共享數據 5)數據卷數據改變是直接修改的 6)數據卷是持續性的,直到沒有容器使用它們。即便是初始的數據卷容器或中間層的數據卷容器刪除了,只要還有其他的容器使用數據卷,那麽裏面的數據都不會丟失。 Docker數據持久化: 容器在運行期間產生的數據是不會寫在鏡像裏面的,重新用此鏡像啟動新的容器就會初始化鏡像,會加一個全新的讀寫入層來保存數據。 如果想做到數據持久化,Docker提供數據卷(Data volume)或者數據容器卷來解決問題,另外還可以通過commit提交一個新的鏡像來保存產生的數據。
接下來我們講解一下案例:
1、docker有兩種卷管理的方式:
區別就是:第一種是容器內部指定保存的路徑並綁定物理卷的路徑映射,第二種是容器內部指定保存數據的路徑,但是外部存儲在磁盤的/var/lib/docker/volumes目錄下的路徑。相對來說第一種最好。
2、先講解第二種:
[root@ELK-chaofeng08 ~]# docker run --name bbox1 -v /opt/data -it busybox / # cd /opt/data /opt/data # ls/opt/data # echo "123" > 1.txt /opt/data # cat 1.txt 123
然後打開另外一個終端查看。
[root@ELK-chaofeng08 ~]# docker inspect bbox1 | grep /var/lib/docker/volumes "Source": "/var/lib/docker/volumes/2e7dddadd5ec5a261666735787bba3747abc1d767d8b680065781fa052e52946/_data", [root@ELK-chaofeng08 ~]# ls /var/lib/docker/volumes/2e7dddadd5ec5a261666735787bba3747abc1d767d8b680065781fa052e52946/_data 1.txt [root@ELK-chaofeng08 ~]# cat /var/lib/docker/volumes/2e7dddadd5ec5a261666735787bba3747abc1d767d8b680065781fa052e52946/_data/1.txt 123
此時即便你把容器刪除了,數據依然不會丟失,因為保存到了外部存儲設備。
刪除容器後查看之前的數據
[root@ELK-chaofeng08 ~]# cat /var/lib/docker/volumes/2e7dddadd5ec5a261666735787bba3747abc1d767d8b680065781fa052e52946/_data/1.txt 123
在 web 容器被刪除後,/var/lib/docker/volumes/f143b7f379fb6d012a08656fc950bf6df4bf5a5b90c72f310644aa997620122b/_data 目錄及其中的內容都還會保留下來,但是,新啟動的容器無法再使用這個目錄,也就是說,已有的數據不能自動地被重復使用了。因此我們一般都通過指定外部存儲設備的路徑來做。
3、看第一種方法,綁定外部路徑與docker容器內部路徑
可以直接掛載宿主機文件或目錄到容器裏,可以理解為目錄映射,這樣就可以讓所有的容器共享宿主機數據,從而只需要改變宿主機的數據源就能夠影響到所有的容器數據。 註意: -v後面的映射關系是"宿主機文件/目錄:容器裏對應的文件/目錄",其中,宿主機上的文件/目錄是要提前存在的,容器裏對應的文件/目錄會自動創建。 數據卷權限: 掛載的數據默認為可讀寫權限。 但也可以根據自己的需求,將容器裏掛載共享的數據設置為只讀,這樣數據修改就只能在宿主機上操作。
案例演示:
[root@ELK-chaofeng08 ~]# docker run --name bbox1 -v /tmp/test:/opt/data -it busybox / # cd /opt/data /opt/data # ls /opt/data # touch 1.txt /opt/data # echo "abcdefg" > 1.txt /opt/data # cat 1.txt abcdefg /opt/data #
然後再打開一個終端,不要進入容器,直接到/tmp/test目錄查看是否有1.txt這個文件和文件的內容
[root@ELK-chaofeng08 ~]# cd /tmp/test [root@ELK-chaofeng08 test]# cat 1.txt abcdefg
主機上的目錄可以是一個本地目錄,也可以在一個 NFS share 內,或者在一個已經格式化好了的塊設備上。
其實這種形式和第一種沒有本質的區別,容器內對 /opt/data 的操作都會反映到主機上的 /tmp/test 目錄內。只是,重新啟動容器時,可以再次使用同樣的方式來將 /tmp/test 目錄掛載到新的容器內,這樣就可以實現數據持久化的目標。
在容器的詳細信息中是這樣的:
"Mounts": [ { "Type": "bind", "Source": "/tmp/test", "Destination": "/opt/data", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
上面的這個是容器內創建文件並寫入內容,然後容器外查看。現在我們可以反過來操作,比如
[root@ELK-chaofeng08 test]# touch 2.txt && echo "abcdefghijklmn" > 2.txt [root@ELK-chaofeng08 test]# cat 2.txt abcdefghijklmn
然後此時回到容器中查看
/opt/data # ls 1.txt 2.txt /opt/data # cat 2.txt abcdefghijklmn
4、可以掛在多個目錄
docker run --name bbox1 -v /opt/data1:/var/www/data1 -v /opt/data2:/var/www/data2 -it busybox
5、掛載為只讀,就是在外部存儲卷掛載容器內時,在容器中是只讀的,只能查看內容,但是不能修改外部存儲卷上的文件
[root@localhost ~]# docker run -it --name bbox1 -v /etc/web.list:/etc/web.list:ro busybox
docker新版本引入 docker volumn命令使用方法
1、提前創建好volumn,然後在啟動容器中映射。
[root@ELK-chaofeng08 test]# docker volume create vol1 vol1 [root@ELK-chaofeng08 test]# docker volume inspect vol1 [ { "CreatedAt": "2019-03-21T10:52:59+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/vol1/_data", "Name": "vol1", "Options": {}, "Scope": "local" } ]
docker volumn默認創建的目錄是在/var/lib/docker/volumns目錄下。
2、使用這個volumn
[root@ELK-chaofeng08 test]# docker run -it --name bbox2 -v vol1:/volumn busybox / # ls bin dev etc home proc root sys tmp usr var volumn
查看這個容器的詳細信息
"Mounts": [ { "Type": "volume", "Name": "vol1", "Source": "/var/lib/docker/volumes/vol1/_data", "Destination": "/volumn", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ],
共享存儲卷
案例演示
1、首先是創建第一個容器
[root@ELK-chaofeng08 ~]# docker run -it --name bbox1 -v /tmp/test2:/opt/data busybox / # cd /opt/data /opt/data # ls
然後我們再打開一個終端,在物理卷下的/tmp/test2目錄創建一個文件
[root@ELK-chaofeng08 test2]# touch 1.txt [root@ELK-chaofeng08 test2]# ls 1.txt
然後回到容器bbox1中查看是否有這個文件
/opt/data # ls 1.txt
發現是有的,符合常理。我們看下容器bbox1的掛載信息,如下所示:
"Mounts": [ { "Type": "bind", "Source": "/tmp/test2", "Destination": "/opt/data", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
然後我們再啟動一個容器bbox2,這次是共享容器bbox1的存儲卷
[root@ELK-chaofeng08 test]# docker run -it --name bbox2 --volumes-from bbox1 busybox / # ls /opt/data 1.txt
然後查看一下容器bbox2的掛載信息
"Mounts": [ { "Type": "bind", "Source": "/tmp/test2", "Destination": "/opt/data", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
你會發現容器bbox1和容器bbox2的掛載信息是相同的,他們都是映射到物理卷/tmp/test2目錄下,這就是容器間的共享數據。
docker容器持久化卷講解