天天看點

Docker筆記(八):資料管理

前面(哪個前面我也忘了)有說過,如果我們需要對資料進行持久化儲存,不應使其存儲在容器中,因為容器中的資料會随着容器的删除而丢失,而因通過将資料存儲于主控端檔案系統的形式來持久化。在Docker容器中管理資料主要有資料卷、主控端目錄挂載兩種方式。

1. 資料卷的方式

資料卷是一個特殊的檔案目錄(或檔案),具備如下特性:

  1. 可以在容器之間共享和重用
  2. 對資料卷的修改會立馬生效
  3. 資料卷的更新,不會影響到鏡像
  4. 資料卷預設會一直存在,不會随容器的删除而消亡

1.1 建立資料卷

可以使用

docker volume create 資料卷名稱

的指令來建立一個資料卷,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume create volume1
volume1      

1.2 檢視資料卷

建立完後,這個資料卷具體對應主控端哪個檔案目錄在上面是沒法得知的,可以通過 

docker volume inspect 資料卷名稱

來檢視,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume inspect volume1
[
    {
        "CreatedAt": "2019-08-12T19:43:47+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/volume1/_data",
        "Name": "volume1",
        "Options": {},
        "Scope": "local"
    }
]      
可以看到資料卷volume1對應的檔案目錄是“/var/lib/docker/volumes/volume1/_data”。           

docker inspect xxx

這個指令挺有用的,不論是檢視鏡像相關資訊(

docker image inspect 鏡像名/鏡像ID

),還是檢視容器相關資訊(

docker container inspect 容器名/容器ID

),都可以使用,其中的image,container,volume是可以省略的,隻要xxx部分不沖突就行。

可以通過

docker volume ls

 指令來檢視所有資料卷,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker volume ls
DRIVER              VOLUME NAME
local               volume1      

1.3 使用資料卷

可以在啟動容器時通過 -v 或 –mount 的方式将一個資料卷挂載到容器的某個目錄

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu1 -v volume1:/vol1 ubuntu:18.04
b060e793d44de2ca871da257b47598334658952943a13d1c478df5c3ae91a01c      

按照 

-v 資料卷名:容器目錄

 的格式,也可以使用 –mount 按照 

--mount source=資料卷名,target=容器目錄

 的格式,如我們再啟動一個挂載相同資料卷的容器 ubuntu2,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount source=volume1,target=/vol2 ubuntu:18.04
b30971f8a4bbadee10774fce0b4568b5b7b1c9cde36f4bf84ac911a4cdaf6c8d      

可以在資料卷所在目錄中建立一個檔案來看看效果,先建立檔案 hello.txt

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# cd /var/lib/docker/volumes/volume1/_data
[root@iZwz9dbodbaqxj1gxhpnjxZ _data]# touch hello.txt
[root@iZwz9dbodbaqxj1gxhpnjxZ _data]# ls
hello.txt      

然後通過

docker exec

來檢視容器ubuntu1目錄/vol1,及容器ubuntu2目錄/vol2的内容

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu1 ls /vol1
hello.txt
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu2 ls /vol2
hello.txt      

可以看到通過挂載目錄 /vol1, /vol2 都可以通路到資料卷volume1對應目錄下的内容。這就像linux的軟連結一樣,将容器目錄連結到了資料卷目錄。并且上述示例也說明,同一個資料卷是可以在被多個容器共享的。

資料卷的共享也可以通過 

volumes-from 容器名稱/容器ID

 參數來實作,如

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu3 --volumes-from ubuntu2 ubuntu:18.04
bb5c6d61a1e6eeb18ba8c889e471b2f3215f97efca79b311eeca5968b2700df8
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu3 ls /vol2
hello.txt      

通過

--volumes-from ubuntu2

來直接使用ubuntu2挂載的容器配置。

1.4 删除資料卷

資料卷不會随着容器的删除而自動删除。如果一個資料卷還被某個容器使用,則不能删除;如果一個資料卷隻被一個容器使用,則可在删除容器時通過指定 

-v

 參數同時删除其挂載的資料卷;

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker rm -v ubuntu3
ubuntu3      

可以通過 

docker volume rm 資料卷名稱

 來删除某個資料卷;

可以通過 

docker volume prune

 清理掉所有未被任何容器使用的資料卷。

2. 主控端目錄挂載方式

在容器啟動時,使用 

-v 主控端目錄:容器目錄

 或 

--mount type=bind,source=主控端目錄,target=容器目錄

的參數格式指定将主控端目錄挂載到容器目錄上。主控端目錄必須是絕對路徑。兩者之間的差別是 

-v

 如果在主控端目錄不存在時會自動建立目錄,而

--mount

不會。如,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu1 -v /root/v1:/vol1 ubuntu:18.04
25c91911709eebc9290b47b483666f7b7be840df947117f7cad323583905b9f1
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount type=bind,source=/root/v2,target=/vol1 ubuntu:18.04
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /root/v2.
See 'docker run --help'.
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# mkdir /root/v2
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu2 --mount type=bind,source=/root/v2,target=/vol1 ubuntu:18.04
5a57285e9261d048dc71cf0476055a290f80538afff2cefd2a24f8b4468b5171      

/root/v1,/root/v2都沒有事先建立,用 

-v

 不會報錯,會自動建立; 

--mount

則會報錯,目錄必須先存在。docker不僅支援目錄的挂載,也支援檔案的挂載,如,

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run --rm -it -v $HOME/.bash_history:/root/.bash_history ubuntu:18.04 bash
root@3ae4ed4e687d:/# history
    1  ll webapps/
    2  ll confluence/images/      

通過将主控端目前使用者的曆史操作檔案挂載到容器的root使用者下的曆史操作檔案,可在容器中通過

history

指令檢視到主控端的操作曆史。可通過 

docker inspect

來檢視容器的挂載情況

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker inspect ubuntu1
--省略了其它資訊--
"Mounts": [
            {
                "Type": "bind",
                "Source": "/root/v1",
                "Destination": "/vol1",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
--省略了其它資訊--      
可在“Mounts”部分看到挂載資訊。      

3. 隻讀控制

有時候,為了資料安全,我們不允許容器對挂載目錄的内容進行修改,即對容器來說,挂載目錄是隻讀的,這可以通過在挂載參數後面加限制實作。

[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker run -dit --name ubuntu3 -v /root/v1:/vol1:ro ubuntu:18.04
25eca348ed307afcbef92bc03f0a1304b31b52e6db1fa07772b5dbd1040ff7b6
[root@iZwz9dbodbaqxj1gxhpnjxZ ~]# docker exec -it ubuntu3 bash
root@25eca348ed30:/# touch /vol1/hello.txt
touch: cannot touch '/vol1/hello.txt': Read-only file system      
-v                是在後面加         ro                (read-only),         --mount                則是形如         --mount type=bind,source=主控端目錄,target=容器目錄,read only                的格式,可自行試驗。      

加了read only的挂載我們再通過

docker inspect

指令檢視,可看到兩者之間的差異 —— Mode與RW的值。

"Mounts": [
            {
                "Type": "bind",
                "Source": "/root/v1",
                "Destination": "/vol1",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            }
        ],      

4. 總結

如果要對資料進行持久化管理或在容器之間共享資料,則需要将資料通過資料卷或主控端目錄(或檔案)挂載的方式來将資料存儲于主控端上,使得資料的生命周期獨立于容器的生命周期。這類似于我們不要把重要檔案放在系統盤,而應放在其它資料盤一樣,因為系統盤會由于重裝系統或系統故障導緻檔案丢失。本文對Docker的資料管理進行了整理,後續對Docker的網絡配置管理部分進行整理,歡迎持續關注。

相關閱讀

Docker筆記(一):什麼是Docker

Docker筆記(二):Docker管理的對象

Docker筆記(三):Docker安裝與配置

Docker筆記(四):Docker鏡像管理

Docker筆記(五):整一個自己的鏡像

Docker筆記(六):容器管理

Docker筆記(七):常用服務安裝——Nginx、MySql、Redis

本文發表于微信公衆号:“空山新雨的技術空間”

作者:空山新雨

歡迎關注,轉發,推薦,你的支援是我持續創作的動力