Docker資料持久化

谢友海發表於2024-09-08

容器刪除掉後,裡邊的資料也會跟著刪除。資料的儲存和重複可用這是最基本的要求,也就是常說的資料持久化。在寫Dockerfile的時候可以用VOLUME命令,指定資料持久化

VOLUME命令設定持久化

當知道了容器中的資料不能持久化後,可以在編寫Dockerfile時用VOLUME命令設定持久化的目錄。

dockerfile

FROM ubuntu:21.04
VOLUME ["/app"]
RUN apt-get update && \
    apt-get install vim -y 

然後構建映象 docker image build -t volume-test:1

[root@iZwz9257qzx65bg8c3p88gZ docker-test]# docker image ls -a
REPOSITORY                     TAG       IMAGE ID       CREATED          SIZE
volume-test                    1         0526a62af1d2   16 seconds ago   180MB
....

並使用該映象啟動一個容器,引數為以命令列模式進入該容器

docker container run -it -p 3999:3999 0526a62af1d2 sh

[root@iZwz9257qzx65bg8c3p88gZ docker-test]# docker container run -it -p 3999:3999 0526a62af1d2 sh
# ls
app  bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# echo hello > app/hello.txt
# cd app
# ls
hello.txt
# cat hello.txt
hello
# exit
[root@iZwz9257qzx65bg8c3p88gZ docker-test]# 

上面的操作分別是

  • 進入容器,可以看到根目錄下有app資料夾(通過VOLUME ["/app"]指定的與宿主機共享資料的目錄)
  • 然後進入app目錄寫入了一個helloapp下的hello.txt檔案,然後退出容器的命令列

然後我們需要驗證這個檔案是不是也同步到了我們的宿主機器上,這樣才能保證完成容器資料的持久化`

docker volume相關命令

[root@iZwz9257qzx65bg8c3p88gZ _data]# docker volume 

Usage:  docker volume COMMAND

Manage volumes

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused local volumes
  rm          Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

首先 ls查詢所有的volume

[root@iZwz9257qzx65bg8c3p88gZ _data]# docker volume ls
DRIVER    VOLUME NAME
local     0bdf00aab64d926f21a6f90342e391d84a4c6ec14b67fe249f8c96ac4e59d91b
local     0ea958861d42b680f60053c59c5384a44069d53e7229f47118ffd64399b46926
local     01b1566780ad5af79b7228f10741b14cc38246e784f3fa5669fe7888a94bfb09
local     3cea763fa6e484560cc489b2aa9f794d370f0f34809a0a4fdd2e513a9c474a74
local     5d599f822fd7cf3f217423af17d483f14deecde3f0adaab300b5c777b3e77636
local     5f61686f8e896c94fb4e1ad2f518e9fb4e4160be75c5358be430919f7a1f5130
local     6b3f0fc9738e3402273e21b605629e6d5dfbf34c37747df4818fa5cd2b1e6059
local     7ae7a3c826c0bdf9a3f893266fedb5c6356d7067cb54bef2ca8506194483b635
local     8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b
local     8b24b542f0d75f7073c47e555d155c7719cd5d65c09b5b03b2a3f87dab4ba513
local     98e980c61c1b6fac75f899303f959f9ff8f788fdb6094edba8349d2dd950ce34
local     824de8cf2066827829e7ff90efc66073607956d8ad6c33e9d3811f8ba2cbc3e0
local     9759e4fb808c4674d384785b6bc746122d0284cafb2c94623d900c7f3508931e
local     40334acb4196bae68de3232bacb4dad775cc63b9cb96f4d9940c99acc3a491ce
local     c69dc1de5d77b32eae6ccb7654921bbd63a07c4cf39b7b86ed818e79b211d480
local     d5c0e014d7499a3a08642700f8ca8208f2d32a2d06fded94a621a82ccbf3cfe5
local     e38488f4bd0dc6f910bee270bd1e1bd5ac9816d6f2e581f9406e7feab444cc45

然後找到我們剛剛建立的那個(這裡我是一個一個找的…下面可以知道如何給volume命名~)

[root@iZwz9257qzx65bg8c3p88gZ _data]# docker volume inspect 8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b
[
    {
        "CreatedAt": "2021-11-28T16:06:46+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b/_data",
        "Name": "8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b",
        "Options": null,
        "Scope": "local"
    }
]

Mountpoint對應的路徑就是宿主機持久化資料的路徑

[root@iZwz9257qzx65bg8c3p88gZ _data]# cd /var/lib/docker/volumes/8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b/_data
[root@iZwz9257qzx65bg8c3p88gZ _data]# ls
hello.txt
[root@iZwz9257qzx65bg8c3p88gZ _data]# cat hello.txt 
hello

經過驗證發現資料的確從容器同步到了宿主機,完成了容器資料的持久化~

設定啟動容器volume的名字

和上面不同的地方在於我們使用映象啟動容器的時候使用-v命令

docker container run -d -v VolumeName:DockerfileVOLUMEPath image

我們這裡的命令就變成了

docker container run -it -p 3999:3999 -v my-data:/app 0526a62af1d2 sh

[root@iZwz9257qzx65bg8c3p88gZ _data]#  docker container run -it -p 3999:3999 -v my-data:/app  0526a62af1d2 sh
# ls
app  bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# cd app
# ls
# echo "hello my data" > hello.txt
# ls
hello.txt
# cat hello.txt
hello my data
# exit

重複檔案的操作

然後退出,來到宿主機,檢視宿主機dockervolume

[root@iZwz9257qzx65bg8c3p88gZ _data]# docker volume ls
DRIVER    VOLUME NAME
local     0bdf00aab64d926f21a6f90342e391d84a4c6ec14b67fe249f8c96ac4e59d91b
local     0ea958861d42b680f60053c59c5384a44069d53e7229f47118ffd64399b46926
local     01b1566780ad5af79b7228f10741b14cc38246e784f3fa5669fe7888a94bfb09
local     3cea763fa6e484560cc489b2aa9f794d370f0f34809a0a4fdd2e513a9c474a74
local     5d599f822fd7cf3f217423af17d483f14deecde3f0adaab300b5c777b3e77636
local     5f61686f8e896c94fb4e1ad2f518e9fb4e4160be75c5358be430919f7a1f5130
local     6b3f0fc9738e3402273e21b605629e6d5dfbf34c37747df4818fa5cd2b1e6059
local     7ae7a3c826c0bdf9a3f893266fedb5c6356d7067cb54bef2ca8506194483b635
local     8ad42e37588d4bb6386f4c18e8c887ffd3a20d7ec4a4742947d01b6f7514331b
local     8b24b542f0d75f7073c47e555d155c7719cd5d65c09b5b03b2a3f87dab4ba513
local     98e980c61c1b6fac75f899303f959f9ff8f788fdb6094edba8349d2dd950ce34
local     824de8cf2066827829e7ff90efc66073607956d8ad6c33e9d3811f8ba2cbc3e0
local     9759e4fb808c4674d384785b6bc746122d0284cafb2c94623d900c7f3508931e
local     40334acb4196bae68de3232bacb4dad775cc63b9cb96f4d9940c99acc3a491ce
local     c69dc1de5d77b32eae6ccb7654921bbd63a07c4cf39b7b86ed818e79b211d480
local     d5c0e014d7499a3a08642700f8ca8208f2d32a2d06fded94a621a82ccbf3cfe5
local     e9b25fe9c662b3d06d2914878b3d1ec498532fa8bf936de61ec1b6076d0fa360
local     e38488f4bd0dc6f910bee270bd1e1bd5ac9816d6f2e581f9406e7feab444cc45
local     my-data

這個時候,你就可以發現其中一條volume是我們自定義的名稱,檢視詳細的資訊也的確是我們剛剛生成的

[root@iZwz9257qzx65bg8c3p88gZ _data]# docker volume inspect my-data
[
    {
        "CreatedAt": "2021-11-28T16:24:42+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
        "Name": "my-data",
        "Options": null,
        "Scope": "local"
    }
]

驗證資料是否同步到了宿主機✅

[root@iZwz9257qzx65bg8c3p88gZ _data]# cd /var/lib/docker/volumes/my-data/_data
[root@iZwz9257qzx65bg8c3p88gZ _data]# ls
hello.txt
[root@iZwz9257qzx65bg8c3p88gZ _data]# cat hello.txt 
hello my data

新容器使用宿主機的資料

已經會把容器(container)中的資料和檔案,儲存在作業系統上了。現在的需求是,再建立一個容器,新容器如何用我們之前用volume儲存下來的的持久化資料?

現在我們本地已經有了之前的容器同步持久化下來的資料了,那麼如果我們重新起了一個容器,如果去使用這一塊資料呢~其實很簡單和指定volume名稱的命令是一樣的

[root@iZwz9257qzx65bg8c3p88gZ docker-test]# docker container run -it -p 3002:3002 -v my-data:/app --name datafromlocal volume-test sh
# ls
app  bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# cd app
# ls
hello.txt
# cat hello.txt
hello my data
# exit

Bind Mount實現資料持久化

資料持久化除了Data Volume外,還有一種叫做Bind Mount,從中文翻譯來講,就是掛載繫結。簡單講就是把容器中持久化的資料,繫結到本機的一個自定義位置

Data Volume,在WIndows/Mac環境中很難使用,因為路徑是虛擬機器的路徑,不容易找到(mac都不太好找到的,下圖的問題還未有解決方法,mac下找不到~哈哈)

image-20211128165421450

相較於Data Volume來說 Bind Mount 設定更簡單,可以和開發環境更好的融合

[root@iZwz9257qzx65bg8c3p88gZ docker-test]# docker container run -it -p 3002:3002 -v ~/docker-test:/app --name datafromlocal volume-test sh
# ls
app  bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# cd app
# ls
dockerfile
# cat dockerfile 
FROM ubuntu:21.04
VOLUME ["/app"]
RUN apt-get update && \
    apt-get install vim -y

# ls
dockerfile
# exit

這種用法其實就是自定義了一個宿主機的目錄同容器內的某個目錄做繫結掛在,而不是像volume幫你管理在某個規定好的位置

[root@iZwz9257qzx65bg8c3p88gZ docker-test]# ls
dockerfile
[root@iZwz9257qzx65bg8c3p88gZ docker-test]# docker container run -it -p 3002:3002 -v ~/docker-test:/app --name datafromlocal volume-test sh
# cd app
# ls
dockerfile
# vim newFile.txt
# exit
[root@iZwz9257qzx65bg8c3p88gZ docker-test]# ls
dockerfile  newFile.txt

完成了宿主機和容器的資料共享持久化!

  • 容器內建立了一個newFile.txt
  • 退出容器回到宿主機通過ls命令,發現已經從容器中同步過來,完成了容器資料的持久化
本作品採用《CC 協議》,轉載必須註明作者和本文連結
CunWang@Ch

相關文章