1. 程式人生 > >docker容器技術之儲存卷(五)

docker容器技術之儲存卷(五)

上一篇文章連結:docker容器技術之虛擬化網路概述(四)


目錄

 

一、Docker底層儲存機制介紹

二、儲存卷介紹

2.1、容器內的檔案系統存在的問題

2.2、volume的好處

2.3、volume的種類

三、Docker容器使用volume

3.1、docker managed volume

1、通過-v  /data指定了myweb容器的volume。

2、檢視容器的詳細資訊

3、在宿主機上向掛載點目錄寫入資料後在容器內驗證

4、在容器內刪除volume中的檔案

5、刪除容器後重新啟動驗證檔案是否存在

3.2、Bind mount volume

我們可以使用go模板來過濾結果

3.3、容器間的資料共享

3.4、通過複製其他容器的卷設定來啟動新的容器,讓多個容器間共享資料


一、Docker底層儲存機制介紹

對於Docker來講,它作為容器執行的底層引擎,在組織和執行其容器時,每個容器內執行一個程式及子程式,容器啟動時依賴於底層可能不止一層的只讀映象聯合掛載啟動而成。它底層能夠儲存此類分層構建並聯合掛載映象的檔案系統包含AUFS、Overlayfs2、devmapper檔案系統。最後一定要在最上層構建一個可寫層。對於此可寫層來說,所有在容器中所執行的寫操作(對資料的修改、對內容的修改),都是儲存在最上層的可寫層。對下層內容的增刪改操作我們需要使用“寫時複製”(COW)機制來實現

 

寫時複製機制是:如果一個檔案在最底層是存在的,在任意層中被標記為刪除,那麼使用者最上層就看不到這個檔案了。使用者能看到的只能是沒被標記為刪除的或者被標記為刪除而使用者在最上層又自己建立了同名的檔案。

對於這種方式來說,我們去訪問一個檔案(修改刪除等一類的操作),在訪問和使用時,效率會非常的低。尤其是那些對I/O要求較高的應用比如redis、mysql。如mysql本身就對I/O要求就較高,如果mysql執行又是將資料寫在容器內的聯合掛載的最上層的可寫層檔案系統上,那麼在容器停止時,資料將被刪除。而且在實現資料存取時其效率的低下也是必然的情形。要想繞過這種使用的限制,我們可以通過使用儲存卷的機制來實現。

二、儲存卷介紹

所謂儲存卷可以簡單想象成在特權級的名稱空間(宿主機)當中找一個本地檔案系統之上存在某一個目錄,把這個目錄直接與容器內部的檔案系統之上的某一個目錄建立繫結關係,隨後,容器內的程序向這個目錄中寫資料時,是直接被寫在宿主機的目錄上的,這和使用mount --bind命令的功能非常相似,這樣就使得我們容器內部程序在實現資料儲存時,能繞過容器內部檔案系統的限制,從而與宿主機的檔案系統建立了關聯關係。這使得我們可以在宿主機和容器內共享資料和內容。可以讓我們的容器直接訪問宿主機的內容。同樣的,也可以讓宿主機直接向容器供給內容。這就相當於說讓兩個本來是隔離的mount名稱空間在某個子路徑上建立一定程度的繫結關係,從而使得在兩個容器之間的檔案系統的某個子路徑上不在是隔離的,而且能夠實現共享的效果。這種關聯關係能夠讓容器之間在跨檔案系統共享資料時,變得容易了,而在宿主機上的這個目錄(與容器內的檔案系統建立繫結關係的)對於容器來說,就被稱作volume(儲存卷)。儲存卷帶來的好處是當容器關閉甚至是刪除時。我們都不用 擔心資料丟失了,只要不刪除繫結的在宿主機上的目錄(儲存卷)就可以。隨後再次重建這個容器時,我們能讓它關聯到同一個儲存捲上,就可以使用相同的資料。因此就能夠資料持久脫離容器的生命週期而持久。

docker預設的儲存卷是在本地的宿主機的檔案系統之上,如果容器要在多個docker host之間遷移(使用docker 叢集),我們還可以新增共享儲存,如NFS檔案系統使得容器內的有狀態應用可以將遷移變的容易

2.1、容器內的檔案系統存在的問題

  • 關閉並重啟容器,其資料不受影響,但刪除容器,將同時刪除容器資料

  • 儲存於聯合掛載檔案系統中,不易於宿主機訪問

  • 容器間資料共享不便

 

2.2、volume的好處

volume的初衷是獨立於容器的生命週期實現資料持久化,因此刪除容器時,不會刪除其資料,也不會對未被引用的卷做垃圾回收工作。因此我們使用儲存卷就是為了解決容器內的聯合掛載檔案系統所帶來的問題。

2.3、volume的種類

Docker有兩種型別的卷,每種型別都在容器中存在一個掛載點,但在宿主機上的位置有所不同

  • Bind mount volume(繫結掛載卷):在宿主機和容器內的路徑都需要人工分別指定一個特定路徑,讓兩個已知路徑建立繫結關係

    docker run --name web1 -it -v HOSTDIR:VOLUMEDIR nginx:latest

     

  • Docker managed volume(docker管理的卷):只需要在容器內指定容器內的掛載點是哪裡,而被繫結的是宿主機上的哪個路徑下的目錄由Docker的daemon自行建立一個空目錄或者使用一個已存在的目錄與儲存卷建立繫結關係。這種方式在第一次啟動容器時非常方便,他會自動為容器在宿主機上的一個路徑下建立volumen,但是在該容器刪除且重新啟動時,它有可能會重新生成一個新的volume。

    docker run --name web1 -it -v /data nginx:latest

        簡單的的說:我們只需要指定容器內的目錄,宿主機上的目錄由他在某一特定路徑下自動建立一個並自動關聯使用者無需指定(案例請看3.1章節)

三、Docker容器使用volume

3.1、docker managed volume

1、通過-v  /data指定了myweb容器的volume。

[[email protected] ~]# docker container run -d -v /data --rm --name myweb httpd:1.1
54b7acd21f2a8bafeaa9bf2653828a54be0c8190fb53216423e9aca6f1da6be4
[[email protected] ~]# 
[[email protected] ~]# docker container exec -it myweb /bin/sh
sh-4.1# ls
bin  boot  data  dev  etc  home  lib  lib64  lost+found  media	mnt  opt  proc	root  sbin  selinux  srv  sys  tmp  usr  var
sh-4.1#

 可以看到多了一個data目錄

2、檢視容器的詳細資訊

可以看到Mounts中Volume的掛載點是/data,在宿主機上的位置等資訊。

那麼這個Volume是於誰建立的關聯?

在Mounts中有說明。

Destination:目標路徑,就是我們的容器路徑

Name:卷的名稱或者叫卷id

Source:卷的位置,是真正關聯的路徑

[[email protected] ~]# docker container inspect myweb
[
   
        "Mounts": [
            {
                "Type": "volume",
                "Name": "0905db81948a0d09d2c1f811eb113a72356f7d73e6085e0b513e6fcabd26dc1b",
                "Source": "/var/lib/docker/volumes/0905db81948a0d09d2c1f811eb113a72356f7d73e6085e0b513e6fcabd26dc1b/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
            "ArgsEscaped": true,
            "Image": "httpd:1.1",
            "Volumes": {
                "/data": {}
    }
]

 

3、在宿主機上向掛載點目錄寫入資料後在容器內驗證

[[email protected] ~]# cd /var/lib/docker/volumes/0905db81948a0d09d2c1f811eb113a72356f7d73e6085e0b513e6fcabd26dc1b/_data
[[email protected] _data]# ls
index.html

[[email protected] ~]# docker container exec -it myweb /bin/sh
sh-4.1# ls /data/
index.html

[[email protected] _data]# echo "welcome to my container." >hello.html
[[email protected] _data]# ls
hello.html  index.html

[[email protected] ~]# docker container exec -it myweb /bin/sh
sh-4.1# ls /data/
hello.html  index.html
sh-4.1# cat /data/hello.html 
welcome to my container.

4、在容器內刪除volume中的檔案

[[email protected] ~]# docker container exec -it myweb /bin/sh
sh-4.1# rm -f /data/hello.html 
sh-4.1# ls /data/
index.html

[[email protected] _data]# ls
index.html

5、刪除容器後重新啟動驗證檔案是否存在

[[email protected] _data]# docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
54b7acd21f2a        httpd:1.1           "/usr/sbin/apachectl??   23 minutes ago      Up 23 minutes       5000/tcp            myweb
[[email protected] _data]# docker container kill myweb
myweb
[[email protected] _data]# docker container rm myweb
Error: No such container: myweb
[[email protected] _data]# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[[email protected] _data]# 

[[email protected] _data]# docker container run -it -v /data --name myweb2 httpd:1.1 /bin/sh
sh-4.1# ls /data/
index.html
sh-4.1# cat /data/index.html 
<h1>Welcom To My Httpd</h1>

 

3.2、Bind mount volume

繫結卷的功能和docker managed volume的功能一樣,只不過在啟動容器時需要同時指定宿主機的路徑和容器內的路徑

如果宿主機路徑不存在會自動在啟動容器的時候建立,注意!必須明確指定宿主機路徑,這是跟docker管理卷所不同的。

[[email protected] myweb3]# docker container inspect myweb3
[
    
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/data/volumes/myweb3",
                "Destination": "/data/httpd/index",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
    }
]
[[email protected] myweb3]# 

[[email protected] _data]# docker container run -d -v /data/volumes/myweb3/:/data/httpd/index/ --name myweb3  httpd:1.1
c5828deffb5b8413c80841b3f2e9675565f7f20125311778df5c3123d867f07f
[[email protected] _data]# 
[[email protected] _data]# ll /data/volumes/myweb3/
total 0

sh-4.1# [[email protected] ~]# docker container exec -it myweb3 /bin/sh
sh-4.1# ls /data/httpd/index/
sh-4.1#

 

在宿主機的路徑建立檔案後驗證容器內是否存在

[[email protected] myweb3]# echo 333 >hello.html
[[email protected] myweb3]# cat hello.html 
333

sh-4.1# ls /data/httpd/index/
hello.html
sh-4.1# cat /data/httpd/index/hello.html 
333

我們可以使用go模板來過濾結果

最外層的{}是模板的意思 

.一次就是裡面的一層

3.3、容器間的資料共享

通過將兩個容器使用同一個宿主機的目錄,可以實現容器間的資料共享

再啟動一個容器叫myweb4

[[email protected] myweb3]# docker container run -d -v /data/volumes/myweb3/:/data/httpd/index/ --name myweb4  httpd:1.1
e9b6509c14436e8b23c45cadd447bab00f61f871525a07907563d09c807ef4e3

[[email protected] myweb3]# docker container exec -it myweb4 /bin/sh
sh-4.1# cd /data/httpd/index/
sh-4.1# cat hello.html 
333

這種方式可以讓多個容器間共享資料

 

3.4、通過複製其他容器的卷設定來啟動新的容器,讓多個容器間共享資料

[[email protected] myweb3]# docker container run -d  --name myweb5 --volumes-from myweb4 httpd:1.1
24b378251586371aade5232ba55ed16ba093ea5800c80562ae3863ab694f2116
[[email protected] myweb3]# 
[[email protected] myweb3]# 
[[email protected] myweb3]# docker container inspect -f {{.Mounts}} myweb5
[{bind  /data/volumes/myweb3 /data/httpd/index   true rprivate}]

通過複製其他容器的卷設定來啟動新的容器,為我們省掉了每次啟動新容器都需要指定很長的volume路徑,我們也可以製作一個底層基礎支撐容器叫basedcontainer,這個容器不需要執行,根據這個底層基礎支撐容器,我們可以隨意的組合一個架構,比如啟動nginx、mysql、tomcat這三個容器,這三個容器都使用--network  container:basedcontainer 加入這個底層基礎支撐容器的網路,並且使用--volumes-from來使用這個基礎容器的卷設定。

注意上述的b3容器在docker inspect b3的時候是看不到網路的因為是join進來的。需要在b3容器內使用ifconfig才能看到。但是儲存卷是可以看到的。

網際網路上有專門做基礎架構支援的容器,他不需要啟動。只要創建出來就行。

 

容器間的依賴關係就叫做容器編排

docker上有專門的容器編排工具叫docker-compose,他是做單機上的容器編排。docker-compose他不但可以編排容器還能幫助我們做映象。比如要啟動這個容器但是映象沒有現成的,但是沒關係,我們可以先寫,然後這個映象根據某個指令可以現做出來。我們用的k8s比它更強大!


下一篇文章的連線:docker容器技術之Dockerfile詳解(六)