Docker深入淺出系列 | 容器資料持久化
Docker深入淺出系列 | 容器資料持久化
Docker已經上市很多年,不是什麼新鮮事物了,很多企業或者開發同學以前也不多不少有所接觸,但是有實操經驗的人不多,本系列教程主要偏重實戰,儘量講乾貨,會根據本人理解去做闡述,具體官方概念可以查閱官方教程,因為本系列教程對前一章節有一定依賴,建議先學習前面章節內容。
Docker深入淺出系列 | 容器初體驗
Docker深入淺出系列 | Image實戰演練
Docker深入淺出系列 | 單節點多容器網路通訊
教程目的:
- 瞭解Docker怎麼實現資料儲存
- 瞭解Docker資料掛載方式是什麼
- 瞭解Docker資料持久化怎麼使用
- 瞭解Docker不同資料掛載方式的使用場景
Docker資料儲存方式
Docker容器對於宿主機器來說只是一個執行在Linux上的應用,因此它的資料儲存還是會依賴宿主機器,Docker是通過掛載宿主機檔案系統或記憶體的方式來實現資料儲存的,掛載方式有三種:volume、bind mount和tmpfs。
- volumes - 在宿主的檔案系統上的docker工作路徑下建立一個資料夾(
/var/lib/docker/volumes
)來儲存資料,其他非docker程序是不能修改該路徑下的檔案,完全由docker來管理 - bind mounts - 可以儲存在宿主機器任何一個地方,但是會依賴宿主機器的目錄結構,不能通過docker CLI 去直接管理,並且非docker程序和docker程序都可以修改該路徑下的檔案
- tmpfs - 無論是在Docker主機上還是在容器內,tmpfs掛載都不會持久儲存在磁碟上,它會將資訊儲存在宿主機器記憶體裡。 容器在其生存期內可以使用它來儲存非持久狀態或敏感資訊。 例如,在內部,swarm services 使用tmpfs掛載將機密掛載到服務的容器中 或者 我們一些不需要持久化資料的開發測試環境,可以使用tmpfs
Volumes初體驗
Volumes 是Docker推薦的掛載方式,與把資料儲存在容器的可寫層相比,使用Volume可以避免增加容器的容量大小,還可以使儲存的資料與容器的生命週期獨立。
- 與bind mounts相比,volumes更易於備份或遷移。
- 您可以使用Docker CLI命令或Docker API管理Volumes。
- volumes在Linux和Windows容器上均可工作。
- 可以在多個容器之間更安全地共享volumes。
- volumes驅動程式使您可以將volumes儲存在遠端主機或雲提供程式上,以加密volumes內容或新增其他功能。
Volumes實戰
通過預設-v
方式
預設情況下,docker會幫我們建立一個隨機命名的volume
1.利用我們前面章節下載的image,建立一個容器,命名為mysql01
[root@localhost /]# docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD=evan123 mysql
4dc868313a330840a833d78a1a88462bcfa4562f61f7da5dcecc9a57290bcb82
2.我們可以看看容器到底有沒有自動幫我們建立一個volumes
[root@localhost /]# docker volume ls
DRIVER VOLUME NAME
local cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
通過上面的輸出結果可以看到,docker 預設幫我建立了一個volume,並且隨機起了一個看不懂的名字
3.通過docker inspect
檢視volume詳細資訊
[root@localhost /]# docker inspect cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
[
{
"CreatedAt": "2020-02-26T07:39:49Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54/_data",
"Name": "cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54",
"Options": null,
"Scope": "local"
}
]
從上面volume詳情可以瞭解到,現在容器的資料是掛在在宿主機器上 /var/lib/docker/
目錄下, scope
是本地
4.通過-v
指定容器volume的名字,使用我們自定義的一個可讀的名字
[root@localhost /]# docker run -d --name mysql02 -v evan_volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=evan124 mysql
4d51b14837ab8564b878043420ea923565bafe90880eaa7bf362dbc35c7f756c
5.再次檢視下volume是否建立成功
[root@localhost /]# docker volume ls
DRIVER VOLUME NAME
local cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
local evan_volume
剛才建立的volume已經成功了
6.再檢視下volume的詳細資訊
[root@localhost /]# docker inspect evan_volume
[
{
"CreatedAt": "2020-02-26T11:00:02Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/evan_volume/_data",
"Name": "evan_volume",
"Options": null,
"Scope": "local"
}
]
從上面資訊可以看到,容器已經成功掛載宿主機器上的evan_volume
通過--mount
方式
-v
能做的--mount
指令都可以做,與-v
指令對比,--mount
指令更靈活,支援更多複雜操作,並且不需要嚴格按照引數順序,通過key value鍵值對方式進行配置,可讀性更高。
--mount
有以下幾個引數:
- type - type可以是bind、volume或者tmpfs,預設是volume
- source - 宿主機上的目錄路徑,可以用縮寫
src
- destination - 目標路徑,容器上掛載的路徑,可以用
dst
或者target
- readonly - 可選項,如果設定了,那麼容器掛載的路徑會被設定為只讀
- volume-opt - 可選項,當volume驅動接受同時多個引數作為選項時,可以以多個鍵值對的方式傳入
1.建立一個容器,命名為mysql-mount,指定volume名為mysql-mount
[root@localhost /]# docker run --name mysql-mount -e MYSQL_ROOT_PASSOWRD=evan123 --mount type=volume,source=mysql-mount,target=/var/lib/mysql mysql
2020-02-26 12:09:37+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian9 started.
2020-02-26 12:09:37+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2020-02-26 12:09:37+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian9 started.
2020-02-26 12:09:37+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
2.檢視volume是否建立成功
[root@localhost /]# docker volume ls
DRIVER VOLUME NAME
local cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
local evan_volume
local mysql-mount
local myvol2
local myvol3
從上面查詢結果可以看出來,mysql-mount已經建立成功
3.檢視宿主機器是否存在對應的目錄
"Mounts": [
{
"Type": "volume",
"Name": "mysql-mount",
"Source": "/var/lib/docker/volumes/mysql-mount/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
]
從輸出結果可以看到,通過--mount
可以實現跟-v
同樣的操作結果,資料也繫結宿主機器上docker路徑對應目錄
bind mounts初體驗
與volumes相比,bind mount的功能有限。 使用繫結安裝時,會將主機上的檔案或目錄安裝到容器中。 檔案或目錄由主機上的完整或相對路徑引用。 相比之下,當您使用volume時,將在主機上Docker的儲存目錄中建立一個新目錄,並且Docker管理該目錄的內容。
該檔案或目錄不需要在Docker主機上已經存在。 如果尚不存在,則按需建立。 bind mounts效能非常好,但是它們依賴於具有特定目錄結構的主機檔案系統。 如果要開發新的Docker應用程式,請考慮使用命名volume。 您不能使用Docker CLI命令直接管理bind mounts
1.建立一個tomcat容器,命名為tomcat-bind
,掛載宿主機器路徑為/tmp
[root@localhost /]# docker run -d --name tomcat-bind --mount type=bind,source=/tmp,target=/user/local tomcat
3dab7d9f469b231ff68072ff8b910e25270c1ab28a944efc0a2b0c9c321e57df
2.通過docker inspect tomcat-mount
檢視容器資訊
"Mounts": [
{
"Type": "bind",
"Source": "/tmp",
"Destination": "/user/local",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
可以看到容器已經成功掛載到宿主機器上的/tmp
目錄,而不是前面我們演示的docker管理路徑下
tmpfs初體驗
使用tmpfs不會持久化資料,資料只會存放在宿主機器記憶體中
1.建立一個tomcat容器,命名為tomcat-tmps
,指定掛載方式為temps
[root@localhost /]# docker run -d --name tomcat-tmpfs --mount type=tmpfs,target=/tmp tomcat
fdf6c8a7ae067db01ed97dc3c3a6903f615a8b687e9b06cd70218a0e8a2d6bf4
2.我們通過docker container inspect tomcat-tmpfs
檢視下是否會建立任務目錄在宿主機器
"Mounts": [
{
"Type": "tmpfs",
"Source": "",
"Destination": "/tmp",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
從上面輸出結果可以看到,宿主機器上並沒有任何目錄,只是在目標路徑也就是容器裡指定了/tmp
作為資料儲存路徑
驗證docker資料儲存
思路:我們嘗試在mysql容器建立一個數據庫,然後退出後把容器刪除掉,再建立一個新的容器,資料儲存路徑指向同一個volume,觀察是否在新的容器可以看到上一個容器建立好的資料庫
1.進入我們上面建立的mysql
[root@localhost /]# docker exec -it mysql01 bash
2.建立資料庫eshare
mysql> create database eshare
-> ;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| eshare |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
從輸出結果可以看到,資料庫已經建立成功
3.退出容器,刪除mysyql01容器
mysql> exit
Bye
root@4dc868313a33:/# exit
exit
[root@localhost /]# docker container rm -f mysql01
mysql01
容器mysql01已經順利刪除
4.檢視mysql01掛載的volume是否還在
[root@localhost /]# docker volume ls
DRIVER VOLUME NAME
local cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
local evan_volume
local mysql-mount
local myvol2
local myvol3
可以看到,對應的volume還在
DRIVER VOLUME NAME
local cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54
5.建立一個新mysql容器,命名為mysql-volume,並且繫結mysql01的volume
[root@localhost /]# docker run -d --name mysql-volume -v cc439258feb4817e1ecfa1f6969613f3e84be9a4499819ec7386f7e443eb6c54:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=evan123 mysql
360127340b462c3539f158c776aef03fd8f58c5a2aafdd622e0f1c161a1bd189
6.驗證新的容器mysql-volume 中,是否存在已經建立好的資料庫eshare
[root@localhost /]# docker exec -it mysql-volume bash
root@360127340b46:/# mysql -uroot -pevan123
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| eshare |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
從上面輸出結果可以看到,新的容器已經存在之前建立好的資料庫,這就證明了docker不僅可以持久化資料,並且不同容器還可以共享同一個volume。