中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Docker目錄掛載及文件共享的方法

發布時間:2022-03-19 15:25:33 來源:億速云 閱讀:3495 作者:iii 欄目:開發技術

這篇文章主要講解了“Docker目錄掛載及文件共享的方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Docker目錄掛載及文件共享的方法”吧!

前言

Docker中的數據可以存儲在類似于虛擬機磁盤的介質中,在Docker中稱為數據卷(Data Volume)。數據卷可以用來存儲Docker應用的數據,也可以用來在Docker容器間進行數據共享。數據卷呈現給Docker容器的形式就是一個目錄,支持多個容器間共享,修改也不會影響鏡像。使用Docker的數據卷,類似在系統中使用 mount 掛載一個文件系統。

Docker文件系統工作情況

想要了解Docker Volume,首先我們需要知道Docker的文件系統是如何工作的。Docker鏡像是由多個文件系統(只讀層)疊加而成。當我們啟動一個容器的時候,Docker會加載只讀鏡像層并在其上(鏡像棧頂部)添加一個讀寫層。如果運行中的容器修改了現有的一個已經存在的文件,那該文件將會從讀寫層下面的只讀層復制到讀寫層,該文件的只讀版本仍然存在,只是已經被讀寫層中該文件的副本所隱藏。當刪除Docker容器,并通過該鏡像重新啟動時,之前的更改將會丟失。在Docker中,只讀層及在頂部的讀寫層的組合被稱為Union File System(聯合文件系統)。

為了能夠保存(持久化)數據以及共享容器間的數據,Docker提出了Volume的概念。簡單來說,Volume就是目錄或者文件,它可以繞過默認的聯合文件系統,而以正常的文件或者目錄的形式存在于宿主機上。
最常用的其實就是目錄掛載文件共享的使用。

掛載本地目錄

Docker容器啟動的時候,如果要掛載宿主機的一個目錄,可以用-v參數指定,這個其實也是創建一個數據卷,只不過是把一個本地主機的目錄當做數據卷掛載在容器上。
譬如我要啟動一個 CentOS 容器,宿主機的 /hostTest 目錄掛載到容器的 /conainterTest 目錄,可通過以下方式指定:

1
docker run -it  -v /hostTest:/conainterTest --name centos-demo-1  centos

這樣在容器啟動后,容器內會自動創建 /conainterTest 的目錄。通過這種方式,我們可以明確一點,即-v參數中,冒號”:”前面的目錄是宿主機目錄,后面的目錄是容器內目錄。

基礎操作

下面我們來驗證一下: 我服務器上的docker 版本都是 18.09.2

1
2
3
[root@VM_156_200_centos ~]# docker version
Client:
 Version:           18.09.2

首先執行命令:

1
2
3
4
5
6
7
[root@VM_156_200_centos /]# docker run -it  -v /hostTest:/conainterTest --name centos-demo-1  centos 
[root@a8e50a72519e /]# cd conainterTest/
[root@a8e50a72519e conainterTest]# echo "123" > 123
[root@a8e50a72519e conainterTest]# ls
123
[root@a8e50a72519e conainterTest]# exit
exit

run 一個 centos 的鏡像,如果本地沒有的話,會去執行docker pull centos下載,并生成一個 centos-demo-1 的容器,并進入交互模式
這時候就可以看到容器里面已經有生成/conainterTest這個目錄了,接下來我們在這個目錄下創建了一個 123 的文件,然后退出容器。
回到宿主機之后,可以看到宿主機對應的目錄已經有/hostTest這個目錄了,并且也有 123 這個文件。

1
2
3
4
5
6
[root@VM_156_200_centos /]# cd /hostTest/
[root@VM_156_200_centos hostTest]# ls
123
[root@VM_156_200_centos hostTest]# echo "456" > 456
[root@VM_156_200_centos hostTest]# ls
123  456

而且我們還再新建了一個 456 文件,看看會不會同步到容器中,接下來啟動容器查看一下:

1
2
3
4
5
6
[root@VM_156_200_centos hostTest]# docker start -ai  centos-demo-1
[root@a8e50a72519e /]# cd conainterTest/
[root@a8e50a72519e conainterTest]# ls
123  456
[root@a8e50a72519e conainterTest]# cat 456
456

可以看到這個是有的,所以這兩個目錄其實就是共享的。接下來具體分析一下這個命令的幾種情況。

容器目錄不可以為相對路徑

具體指令如下:

1
2
3
[root@VM_156_200_centos /]# docker run -it  -v /hostTest:conainterTest --name centos-demo-1  centos 
docker: Error response from daemon: invalid volume specification: '/hostTest:conainterTest': invalid mount config for type "bind": invalid mount path: 'conainterTest' mount path must be absolute.
See 'docker run --help'.

直接報錯,提示 conainterTest 不是一個絕對路徑,所謂的絕對路徑,必須以下斜線“/”開頭。

宿主機目錄如果不存在,則會自動生成

先把宿主機的目錄刪掉:然后在run容器:
ps: 因為有為容器命名,但是因為相同名字的容器創建會報錯,所以這邊我有一個隱形操作,就是每次操作,都會先執行:

1
2
[root@VM_156_200_centos /]# docker rm centos-demo-1 
centos-demo-1

當然這個不是重點,所以后面我不會再把這個操作再說明,默認每次run的時候,如果名字相同,那么我就會先刪掉同名的容器。

1
2
3
4
[root@VM_156_200_centos /]# rm -rf  hostTest
[root@VM_156_200_centos /]# docker run -it  -v /hostTest:/conainterTest --name centos-demo-1  centos 
[root@e57a25c8f8e5 /]# ls
anaconda-post.log  bin  conainterTest  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

查看宿主機,發現新增了 /hostTest 這個目錄

1
2
3
[root@VM_156_200_centos /]# cd hostTest/
[root@VM_156_200_centos hostTest]# pwd
/hostTest

宿主機的目錄如果為相對路徑呢?

這次,我們換個目錄名 hostTest1 試試:

1
[root@VM_156_200_centos /]# docker run -it  -v hostTest1:/conainterTest --name centos-demo-1  centos

接下來去 / 查找有沒有增加 hostTest1 目錄:

1
[root@VM_156_200_centos /]# ll / | grep 'hostTest1'

發現找不到?? 那么 hostTest1 在哪里創建呢? 通過docker inspect命令,查看容器“Mounts”那一部分,我們可以得到這個問題的答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@VM_156_200_centos hostTest]# docker inspect centos-demo-1
[
    {
    ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "hostTest1",
                "Source": "/var/lib/docker/volumes/hostTest1/_data",
                "Destination": "/conainterTest",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],
    ...
    }
]

可以看出,容器內的 /conainterTest 目錄掛載的是宿主機上的 /var/lib/docker/volumes/hostTest1/_data 目錄。
原來,所謂的相對路徑指的是 /var/lib/docker/volumes/ ,與宿主機的當前目錄無關。

只是-v指定一個目錄的情況?

先啟動一個容器:

1
2
3
[root@VM_156_200_centos volumes]# docker run -it  -v /test2 --name centos-demo-1  centos 
[root@64e9d535b48c /]# ls
anaconda-post.log  bin  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  test2  tmp  usr  var

發現 /test2 在容器中有存在,那么宿主機的目錄在哪里呢?? 用 docker inspect 查看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@VM_156_200_centos hostTest]# docker inspect centos-demo-1
[
    {
    ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "43c602bf16cf87452499988cd4dbfad834e40e2f01e93d960ec01a557f40bc58",
                "Source": "/var/lib/docker/volumes/43c602bf16cf87452499988cd4dbfad834e40e2f01e93d960ec01a557f40bc58/_data",
                "Destination": "/test2",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
    ...
    }
]

可以看出,同上例中的結果類似,只不過,它不是相對路徑的目錄名,而是隨機生成的一個目錄名。

如果在容器內修改了目錄的屬主和屬組,那么對應的掛載點是否會修改呢?

首先開啟一個容器,并查看容器內 /conainterTest/ 的屬性

1
2
3
[root@VM_156_200_centos volumes]# docker run -it  -v /hostTest:/conainterTest --name centos-demo-1  centos 
[root@25d6613bcb81 /]# ll -d /conainterTest/
drwxr-xr-x 2 root root 4096 Feb 26 03:24 /conainterTest/

接下來查看宿主機內 /hostTest 目錄的屬性:

1
2
[root@VM_156_200_centos volumes]# ll -d /hostTest/
drwxr-xr-x 2 root root 4096 Feb 26 11:24 /hostTest/

可以看到都是 root。接下來我們在容器內新建用戶,修改 /conainterTest 的屬主和屬組:

1
2
3
4
5
[root@VM_156_200_centos volumes]# docker start -ai  centos-demo-1
[root@25d6613bcb81 /]# useradd kbz
[root@25d6613bcb81 /]# chown -R kbz.kbz /conainterTest/
[root@25d6613bcb81 /]# ll -d /conainterTest/
drwxr-xr-x 2 kbz kbz 4096 Feb 26 03:24 /conainterTest/

可以看到已經將屬主和屬組都變成 kbz 了。接下來查看宿主機 /hostTest 的屬主和屬組是否會改變??

1
2
[root@VM_156_200_centos volumes]# ll -d /hostTest/
drwxr-xr-x 2 privoxy privoxy 4096 Feb 26 11:24 /hostTest/

發現改變了,但是并不是 kbz,而是一個 privoxy ??
原來,這個與UID有關系,UID,即“用戶標識號”,是一個整數,系統內部用它來標識用戶。一般情況下它與用戶名是一一對應的。首先查看容器內victor對應的UID是多少:

1
2
3
[root@VM_156_200_centos volumes]# docker start -ai  centos-demo-1
[root@25d6613bcb81 /]# cat /etc/passwd | grep kbz
kbz:x:1000:1000::/home/kbz:/bin/bash

kbz 的 UID 為 1000,那么宿主機內 1000 對應的用戶是誰呢?

1
2
[root@VM_156_200_centos volumes]# cat /etc/passwd | grep 1000
privoxy:x:1000:1000::/home/privoxy:/bin/bash

果然是 privoxy, 那么就說的通了。

容器銷毀了,在宿主機上新建的掛載目錄是否會消失

在這里,主要驗證兩種情況:

  • 指定了宿主機目錄,即 -v /hostTest:/conainterTest。

  • 沒有指定宿主機目錄,即 -v /conainterTest

首先的第一種情況:

1
2
3
4
5
6
7
8
9
[root@VM_156_200_centos /]# rm -rf /hostTest/  
[root@VM_156_200_centos /]# ll | grep hostTest
[root@VM_156_200_centos /]# docker run -it  -v /hostTest:/conainterTest --name centos-demo-1  centos 
[root@a225da0f4576 /]# exit
exit
[root@VM_156_200_centos /]# docker rm centos-demo-1 
centos-demo-1
[root@VM_156_200_centos /]# ll | grep hostTest
drwxr-xr-x    2 root root     4096 Feb 26 14:10 hostTest

我們先把宿主機的 hostTest 目錄刪掉,然后進行掛載,再把容器刪掉,最后發現掛載時候建的 hostTest 還存在。
可以看出,即便容器銷毀了,新建的掛載目錄不會消失。進一步也可驗證,如果宿主機目錄的屬主和屬組發生了變化,容器銷毀后,宿主機目錄的屬主和屬組不會恢復到掛載之前的狀態。

第二種情況:
通過上面的驗證知道,如果沒有指定宿主機的目錄,則容器會在 /var/lib/docker/volumes/ 隨機配置一個目錄,那么我們看看這種情況下的容器銷毀是否會導致相應目錄的刪除:
首先啟動容器:

1
[root@VM_156_200_centos /]# docker run -it  -v conainterTest --name centos-demo-1  centos

然后通過 docker inspect 來查看掛載的宿主機的目錄:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@VM_156_200_centos ~]# docker inspect centos-demo-1
[
    {
    ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683",
                "Source": "/var/lib/docker/volumes/225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683/_data",
                "Destination": "conainterTest",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
    ...
    }
]

對應的是/var/lib/docker/volumes/22…83/_data目錄, 去查看一下這個目錄是否存在:

1
2
3
[root@VM_156_200_centos /]# ll /var/lib/docker/volumes/225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683/
total 4
drwxr-xr-x 2 root root 4096 Feb 26 14:14 _data

發現該目錄依然存在。而且即使重啟了docker服務,該目錄依舊存在。

掛載宿主機已存在目錄后,在容器內對其進行操作,報“Permission denied”

可通過兩種方式解決:

  • 關閉selinux。
    臨時關閉:# setenforce 0
    永久關閉:修改/etc/sysconfig/selinux文件,將SELINUX的值設置為disabled。

  • 以特權方式啟動容器
    指定–privileged參數

    1
    docker run -it --privileged=true -v /test:/soft centos /bin/bash

將掛載的路徑的權限設置為只讀

掛載的路徑權限默認為讀寫。如果指定為只讀可以用:ro

1
2
3
4
[root@VM_156_200_centos /]# docker run -it  -v /hostTest:/conainterTest:ro --name centos-demo-1  centos 
[root@c9c2a58bbfef /]# cd conainterTest/
[root@c9c2a58bbfef conainterTest]# echo "12" > 12
bash: 12: Read-only file system

這時候,如果在容器的掛載目錄下進行讀寫操作的話,就會報錯。

掛載文件

不僅可以掛載目錄,還可以掛載文件。如果掛載目錄可以理解為系統的目錄映射的話,那么掛載文件,也可以理解為文件映射。
語法跟掛載目錄差不多。不過有一點要注意的是,掛載宿主機文件的時候,該文件一定要存在,如果該文件不存在,就會跟上面例子說的一樣,docker會自動幫你創建,但是這時候它創建的時候,就是目錄了,而不是文件了
接下來嘗試一下:

1
2
3
4
[root@VM_156_200_centos ~]# vim web.list
[root@VM_156_200_centos ~]# cat web.list
1111111111
2222222222

我創建了一個 web.list 的文件,并且寫入了兩行,這時候就開始掛載這個文件了:

1
2
3
4
5
6
7
8
9
10
11
[root@VM_156_200_centos ~]# docker run -it  -v /root/web.list:/root/web.list --name centos-demo-1  centos 
[root@6c91b4f6b765 /]# cat /root/web.list 
1111111111
2222222222
[root@6c91b4f6b765 /]# echo "333333" >> /root/web.list 
[root@6c91b4f6b765 /]# cat /root/web.list 
1111111111
2222222222
333333
[root@6c91b4f6b765 /]# exit
exit

可以看到掛載成功了,并且在容器內又在 web.list 寫入新的一行,并退出容器

1
2
3
4
5
6
7
8
9
10
11
[root@VM_156_200_centos ~]# cat /root/web.list 
1111111111
2222222222
333333
[root@VM_156_200_centos ~]# echo "444444" >> /root/web.list 
[root@VM_156_200_centos ~]# docker start -ai  centos-demo-1
[root@6c91b4f6b765 /]# cat /root/web.list 
1111111111
2222222222
333333
444444

可以看到在宿主機,之前容器新寫的一行也同步過來了,而且之后宿主機也新加了一行,之后進入容器也一樣有。
掛載文件跟上述掛載目錄一樣,也是默認為讀寫的,如果設置為只讀的話,那么在容器里面就不能修改了,只能在宿主機修改:

1
2
3
4
5
6
7
8
9
10
11
12
[root@VM_156_200_centos ~]# docker run -it  -v /root/web.list:/root/web.list:ro --name centos-demo-1  centos 
[root@2a7e3a4ed710 /]# echo "5555" >> /root/web.list 
bash: /root/web.list: Read-only file system
[root@2a7e3a4ed710 /]# exit
exit
[root@VM_156_200_centos ~]# echo "666" >> /root/web.list 
[root@VM_156_200_centos ~]# cat web.list 
1111111111
2222222222
333333
444444
666

可以看到在容器內編輯是會報錯的,而在宿主機內就不會。

掛載數據卷容器

上述的掛載目錄和掛載文件,只是 Docker Volume 的使用方式。
而我們用的方式就是在docker run命令后面跟上-v參數即可創建一個數據卷,然后把本地目錄或者文件當做數據卷掛載到容器中。當然也可以跟多個-v參數來創建多個數據卷。
因此我們完全可以創建一個數據卷的容器,后面專門用來提供其他容器來掛載。
首先先創建一個專門用來提供數據的本地目錄,然后掛載到一個普通的容器,而這個容器就是其他容器要掛載的數據卷容器,這種方式主要就是用來做多個容器的共享數據存在的。

1
2
3
4
[root@VM_156_200_centos ~]# mkdir go-data
[root@VM_156_200_centos go-data]# cp -r  /root/go/src/goworker/ ./
[root@VM_156_200_centos go-data]# ls
goworker

go-data 這個目錄存放一些 golang 語言的項目,然后我們把它做成一個數據卷容器,并指向容器的 /go/src 目錄:

1
2
3
4
5
6
[root@VM_156_200_centos go-data]# docker run -it  -v /root/go-data/:/go/src/ --name centos-go-data  centos 
[root@10d5c4f11e77 /]# cd /go/src
[root@10d5c4f11e77 src]# ls
goworker
[root@10d5c4f11e77 src]# exit
exit

這樣這個就生成了一個名為 centos-go-data 的數據卷容器了,容器里面 /go/src 目錄含有一個叫做 goworker 的 go 程序。剛好我服務器上之前有一個 go-1.10 環境的鏡像。
接下來我們將這個鏡像 run 起來,并且掛載 centos-go-data 這個數據卷容器(通過 –volumes-from 可以掛載數據卷容器),看看原來 /go/src 里面應該為空的目錄,會不會有這個數據卷容器里面的go程序代碼?

1
2
3
4
5
6
7
[root@VM_156_200_centos go-data]# docker run -it --volumes-from centos-go-data --name golang-volume-demo kbz/golang-1.10
root@412ab80da79e:/app# cd /go/src 
root@412ab80da79e:/go/src# ls
goworker
root@412ab80da79e:/go/src# cd goworker/
root@412ab80da79e:/go/src/goworker# ls
hello_worker.go  worker  worker.go

可以看到原本應該有空的 src 目錄,竟然有代碼目錄存在了,說明這個數據卷掛載成功了。接下來將這個 goworker 添加一個文件,看會不會同步到掛載的那個本地目錄:

1
2
3
4
5
6
7
8
root@412ab80da79e:/go/src/goworker# echo "123" > 123
root@412ab80da79e:/go/src/goworker# ls
123  hello_worker.go  worker  worker.go
root@412ab80da79e:/go/src/goworker# exit
exit
[root@VM_156_200_centos go-data]# cd /root/go-data/goworker/
[root@VM_156_200_centos goworker]# ls
123  hello_worker.go  worker  worker.go

發現本地目錄也出現剛才在容器中出現的 123 文件了,說明還是共享成功了。 這時候我們再 run 一個新的 golang 環境的容器,然后也掛載這個數據卷看看數據會不會也有這個 123 文件?

1
2
3
4
[root@VM_156_200_centos goworker]# docker run -it --volumes-from centos-go-data --name golang-volume-demo-2 kbz/golang-1.10
root@25d7a8fd5da1:/app# cd /go/src/goworker/
root@25d7a8fd5da1:/go/src/goworker# ls
123  hello_worker.go  worker  worker.go

發現新的容器也有這個 123 文件。
其實很多時候這種數據卷容器都是用來做持久化的,舉個例子,比如我有一些golang的測試代碼,做成了一個數據卷容器,然后我本地有好幾個不同go環境的容器,每一個容器在 run 的時候,都會掛載這個數據卷容器。但是我們不希望在go環境的容器里面去修改這個數據卷容器里面的數據。所以剛開始我們在生成這個數據卷容器的時候,就要把權限設置為只讀才行,這樣這個數據卷就變成一個公共的掛載數據卷,別的容器只能掛載使用里面的數據,但是卻不能做修改:

1
2
3
4
5
6
7
8
9
10
11
[root@VM_156_200_centos goworker]# docker rm centos-go-data
centos-go-data
[root@VM_156_200_centos goworker]# docker run -it  -v /root/go-data/:/go/src/:ro --name centos-go-data  centos 
[root@851a09a40cb8 /]# exit
exit
[root@VM_156_200_centos goworker]# docker run -it --volumes-from centos-go-data --name golang-volume-demo-3 kbz/golang-1.10
root@c986955f5ee0:/app# cd /go/src/goworker/
root@c986955f5ee0:/go/src/goworker# ls
123  hello_worker.go  worker  worker.go
root@c986955f5ee0:/go/src/goworker# echo "456" > 456
bash: 456: Read-only file system

一旦進行修改,就會報錯。
而且這種數據卷容器可以掛好幾個的,就跟用 -v 掛載多個本地目錄一樣:

1
docker run --name data -v /opt/data1:/var/www/data1 -v /opt/data2:/var/www/data2:ro -it docker.io/ubuntu

這邊稍微說一下,沒有加-t和-i參數,所以這個容器創建好之后是沒有進行交互模式的。其中 -i 表示以“交互模式”運行容器。 -t 表示打開一個連接到容器的終端。

1
2
3
4
5
[root@VM_156_200_centos js-data]# docker run -it --volumes-from centos-go-data --volumes-from centos-js-data  --name golang-volume-demo-4 kbz/golang-1.10
root@94e9d5868711:/app# cd /go/src/ && ls
goworker
root@94e9d5868711:/go/src# cd /js && ls
test.js

這樣就掛載了兩個數據卷容器。
使用數據容器的兩個注意點:

  • 不要運行數據容器,這純粹是在浪費資源。

  • 不要為了數據容器而使用“最小的鏡像”,如busybox或scratch,只使用數據庫鏡像本身就可以了。你已經擁有該鏡像,所以并不需要占用額外的空間。

創建數據卷的其他方式

除了以上用 -v 來創建掛載數據卷之外,docker 還可以用以下方式來創建數據卷:

直接用docker volume 來管理

Docker 新版本中引入了 docker volume 命令來管理 Docker volume:
比如我創建一個名為 js-data 的數據卷:

1
2
[root@VM_156_200_centos js-data]# docker volume create --name js-data
js-data

這樣就創建成功了,可以通過 docker volume ls 來查看當前的數據卷:

1
2
3
4
5
[root@VM_156_200_centos js-data]# docker volume ls
DRIVER              VOLUME NAME
local               0e01f8abe89c9956609eed063c623536112525fb32cf4c0363255a953aa2d35d
...
local               js-data

然后我們可以通過docker volume inspect xxx來查看這個數據卷所對應的本地目錄是哪個?

1
2
3
4
5
6
7
8
9
10
11
12
[root@VM_156_200_centos js-data]# docker volume inspect js-data
[
    {
        "CreatedAt": "2019-02-26T16:12:28+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/js-data/_data",
        "Name": "js-data",
        "Options": {},
        "Scope": "local"
    }
]

可以看到對應的本地目錄就是 /var/lib/docker/volumes/js-data/_data 這個目錄。當然目前這個目錄是空的:

1
2
[root@VM_156_200_centos js-data]# ll /var/lib/docker/volumes/js-data/_data
total 0

接下來就可以將這個數據卷掛載上去:

1
2
3
4
5
6
7
8
[root@VM_156_200_centos js-data]# docker run -it -v js-data:/js  --name golang-volume-demo-3 kbz/golang-1.10
root@c55671066dec:/app# cd /js
root@c55671066dec:/js# ls
root@c55671066dec:/js# echo "123" > 123
root@c55671066dec:/js# ls
123
root@c55671066dec:/js# exit
exit

語法差不了多少,也是 -v 來指定,不過這時候“:”前面已經不是宿主機的目錄了,而是換成 js-data 這個數據卷了,當然這個目錄是空的。
然后我們給他添加了一個新的文件 123,看看宿主機目錄會不會也有?

1
2
3
4
5
[root@VM_156_200_centos js-data]# ll /var/lib/docker/volumes/js-data/_data
total 4
-rw-r--r-- 1 root root 4 Feb 26 16:29 123
[root@VM_156_200_centos js-data]# cat /var/lib/docker/volumes/js-data/_data/123
123

事實上肯定是有的。 而且這種方式其實就是上面那種當宿主機的目錄是相對目錄的處理方式,其實在docker處理過程中,如果宿主機目錄是相對的,這時候就會去判斷本地是否存在這個volume,如果不存在就創建一個(所以其實我們不太需要去顯示的創建一個 volume),所以我們還可以看到文章前面當當宿主機的目錄是相對目錄的處理方式那時候的相對目錄的 hostTest1,其實已經是一個 volume了:

1
2
3
4
5
6
7
8
9
10
11
12
[root@VM_156_200_centos js-data]# docker volume inspect hostTest1
[
    {
        "CreatedAt": "2019-02-26T11:30:34+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/hostTest1/_data",
        "Name": "hostTest1",
        "Options": null,
        "Scope": "local"
    }
]

但是有一點要注意的話,如果要指定具體的宿主機目錄的話,那就不能用這種方式,“:” 前面的宿主機目錄路徑還是得用絕對路徑。

通過dockerfile創建數據卷

除了用docker volume命令顯示或者用 -v 宿主機相對目錄隱示的創建數據卷之外,還可以在dockerfile設置volume數據卷。
ps: 注意上述[5 掛載數據卷容器]創建的數據卷容器,其實本質上是一個容器,即 Docker Container,而不是 Docker Volume。 Container 是可以在 docker ps -a 可以找到,而在 docker volume ls 這里面是找不到的:

1
2
3
4
[root@VM_156_200_centos js-data]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                           PORTS                                                                        NAMES
a559685d18ae        centos              "/bin/bash"              About an hour ago   Exited (0) About an hour ago                                                                                  centos-js-data
851a09a40cb8        centos              "/bin/bash"              About an hour ago   Exited (0) About an hour ago                                                                                  centos-go-data

在 dockerfile 設置 volume 數據卷,舉個例子:

1
2
3
4
5
6
[root@VM_156_200_centos ~]# mkdir docker-volume-centos
[root@VM_156_200_centos ~]# cd docker-volume-centos/
[root@VM_156_200_centos docker-volume-centos]# vim dockerfile
[root@VM_156_200_centos docker-volume-centos]# cat dockerfile 
FROM centos
VOLUME /js-data

可以看到這個 dockerfile 掛載了一個容器內的 js-data。 接下來 build 一下:

1
[root@VM_156_200_centos docker-volume-centos]# docker build --rm -t volume-centos .

然后 run 起來:

1
2
3
4
5
6
7
8
[root@VM_156_200_centos docker-volume-centos]# docker run -it --name volume-centos-demo  volume-centos
[root@eeb532993285 /]# cd /js-data
[root@eeb532993285 js-data]# ls
[root@eeb532993285 js-data]# echo "456" > 456
[root@eeb532993285 js-data]# ls
456
[root@eeb532993285 js-data]# exit
exit

可以看到跑起來之后,容器里面已經有一個 js-data, 但是這個目錄是空的,我們先在這個目錄創建一個 456 的文件。然后退出容器。
接下來我們看看這個共享目錄對應的宿主機的目錄是哪個:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@VM_156_200_centos docker-volume-centos]# docker inspect volume-centos-demo
[
    {
    ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304",
                "Source": "/var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data",
                "Destination": "/js-data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
    ...
    }
]

可以看到宿主目錄是這個:/var/lib/docker/volumes/b07…304/_data,接下來看看這個目錄是否有 456 這個文件:

1
2
3
4
5
[root@VM_156_200_centos docker-volume-centos]# ll /var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data
total 4
-rw-r--r-- 1 root root 4 Feb 26 16:56 456
[root@VM_156_200_centos docker-volume-centos]# cat /var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data/456 
456

是有的。 通過 dockerfile 設置 volume 也可以設置多個,不過這種方式都是相對目錄的方式,而且文件名還隨機,相當于上述的-v 只指定一個的情況

1
[root@VM_156_200_centos volumes]# docker run -it  -v /test2 --name centos-demo-1  centos

Volume 的刪除和清理

如果是屬于 volume,那么直接調用docker volume rm xxx 就可以刪除了:

1
2
3
4
5
6
[root@VM_156_200_centos docker-volume-centos]# docker volume ls
DRIVER              VOLUME NAME
...
local               js-data
[root@VM_156_200_centos docker-volume-centos]# docker volume rm js-data
js-data

如果是掛載的數據卷容器,就調用docker rm xxx 當做普通容器刪除即可:

1
2
[root@VM_156_200_centos docker-volume-centos]# docker rm centos-js-data 
centos-js-data

雖然容器刪除了,但是宿主機掛載的本地目錄的資料還是存在的。

dockerfile volume 的權限和許可

這是個很有意思的現象,就是如果dockerfile里面的volume命令前后對共享目錄進行操作的話,是會有差別的,舉個例子:

1
2
3
4
5
6
[root@VM_156_200_centos docker-volume-centos]# cat dockerfile
FROM centos
RUN useradd foo
VOLUME /data
RUN touch /data/x
RUN chown -R foo:foo /data

這個是一個dockerfile,我們的預期目錄是,當run起來之后,會有 /data/x 這個文件。 但是實際上沒有:

1
2
3
4
[root@VM_156_200_centos docker-volume-centos]# docker build --rm -t kbz/volume-test .
[root@VM_156_200_centos docker-volume-centos]# docker run -it --name volue-test-demo kbz/volume-test
[root@3d037af9a5ca /]# cd /data
[root@3d037af9a5ca data]# ls

可以看到,雖然有 /data 這個目錄,但是在目錄里面并沒有 x 這個文件??? 這個是怎回事呢???
這個就涉及到dockerfile的運行規則,在Dockerfile中的每個命令都會創建一個新的用于運行指定命令的容器,并將容器提交到鏡像,每一步都是在前一步的基礎上構建。
因此在Dockerfile中 ENV FOO=bar等同于:

1
2
cid=$(docker run -e FOO=bar <image>)
docker commit $cid

那么針對我們本例的dockerfile,他的執行順序應該是(真實過程可能不是這樣的,但是應該差不多):

1
2
3
4
5
6
7
8
cid=$(docker run centos useradd foo)
image_id=$(docker commit $cid)
cid=$(docker run -v /data centos)
image_id=$(docker commit $cid)
cid=$(docker run $image_id touch /data/x)
image_id=$(docker commit $cid)
cid=$(docker run $image_id chown -R foo:foo /data)
docker commit $(cid) volue-test-demo

那這個過程就很明顯了,因為每一行都會啟動一個新的容器,因此每次都會有一個新的 volume,也就是每次run的新容器, /data 都是新的。
所以其實我們的這個 touch 操作,就是在當前的 volume 的 data 目錄下操作的,而不是實際的容器或鏡像的文件系統內。所以當我們重新再run的時候,這時候新的 volume 又是一個空的 data 目錄。
所以如果要改的話,應該要把這個 touch 的操作,先存在鏡像的文件系統之內,然后最后在掛載目錄:

1
2
3
4
5
6
7
[root@VM_156_200_centos docker-volume-centos]# vim dockerfile
[root@VM_156_200_centos docker-volume-centos]# cat dockerfile 
FROM centos
RUN useradd foo
RUN touch /data/x
RUN chown -R foo:foo /data
VOLUME /data

這個是改完后的 dockerfile

1
2
3
4
5
[root@VM_156_200_centos docker-volume-centos]# docker build --rm -t kbz/volume-test-2 .
[root@VM_156_200_centos docker-volume-centos]# docker run -it --name volue-test-demo-2 kbz/volume-test-2
[root@2850978389ac /]# cd /data 
[root@2850978389ac data]# ls
x

這時候就有 x 文件了。 而且對應的宿主目錄也有這個 x 文件了:

1
2
3
[root@VM_156_200_centos docker-volume-centos]# cd /var/lib/docker/volumes/d4c83377d137104a13893b31e42c57e3635e8e59c14027463361b814c86c6ad7/_data
[root@VM_156_200_centos _data]# ls
x

感謝各位的閱讀,以上就是“Docker目錄掛載及文件共享的方法”的內容了,經過本文的學習后,相信大家對Docker目錄掛載及文件共享的方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平江县| 永宁县| 宁安市| 依安县| 镶黄旗| 娱乐| 广安市| 平昌县| 昌图县| 琼中| 荔波县| 伊金霍洛旗| 潼南县| 扶余县| 祥云县| 迁西县| 新余市| 仁寿县| 晴隆县| 河西区| 天津市| 台北市| 新巴尔虎左旗| 合江县| 河池市| 邻水| 武汉市| 宁国市| 开平市| 井冈山市| 刚察县| 宁陕县| 定结县| 海阳市| 普陀区| 九台市| 延安市| 赤城县| 巴塘县| 两当县| 年辖:市辖区|