昨天都還只是紙上談兵,根本還沒有真的見到 volume 本人,別急,讓我們把 mysql 給運行起來:
$ docker container run --detach --name mysql --env MYSQL_ROOT_PASSWORD=whatever mysql # 不換行
cc94cfe86706e585f36d60e7dec2a7ffdfcf9ca5ff83f697d8
接著一樣,確認這個容器是真的有在運作,而不是進入停止的狀態。
$ docker container list
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc94cfe86706 mysql "docke..." Abou... Up 3306/tcp, 33.. mysql
確認過後,再次使用 inspect
這個指令來看看容器有什麼不一樣!
$ docker container inspect mysql
[
{
...
"Mounts":[
{
"Type": "volume",
"Name": "2c1a7d85be3f0c1079ab0d73b92fd9aadb82...",
"Source": "/var/lib/docker/volumes/2c1a7d../_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
...
}
]
礙於獨特的 SHA 值太長,所以我用了 … 的方式來縮短篇幅,但這個並不影響,因為每個人運行後的 SHA 值都不一樣。
可以觀察到這個容器掛載了一個 volume 在裡面,可以看到 Destination 的部分,是指容器內部路徑,而 Source 則是指外部的 volume,而這個 volume 的路徑,若是使用 Linux 作業系統的人,可以直接透過 cd
的指令進入到這個資料夾中。
而 macOS 以及 Windows 的使用者,還記得我們在之前的章節提過,macOS 以及 Windows 都是透過迷你的虛擬機在運行 Docker,所以直接 cd
到這個路徑是行不通的,因為資料是存放在迷你的虛擬機中。
這邊可以透過以下指令來列出存活的 volume:
$ docker volume list
DRIVER VOLUME NAME
local 2c1a7d85be3f0c1079ab0d73b92fd9aadb8204c2....
仔細對比 VOLUME NAME 會發現跟連接到容器的 SHA 值是一模一樣的,代表寫在映像檔中的 VOLUME 指令,會在沒有指定 volume 的情況下自行建立一個以隨機 SHA 值命名的 volume。
我們一樣可以透過 inspect 的指令來看到 volume 的詳細資訊,可以透過 docker volume inspect + TAB 的方式,來做到篩選現有的 volume,並且檢查其詳細資訊:
$ docker volume inspect 2c1a7d85be3f0c1079ab0d73....
[
{
"CreatedAt": "2022-09-17T10:46:59Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/2c1a7d85b...",
"Name": "2c1a7d85be3f0c10...",
"Options": null,
"Scope": "local"
}
]
怎麼知道哪個 volume 接到哪個容器?
從剛剛的結尾,我們會發現一件事,可以透過容器看到現在連接的是哪一個 volume,但卻沒辦法從 volume 的角度去看到這個 volume 現在連接哪一個容器!
若是開啟兩個 MySQL 的服務呢?
$ docker container run --detach --name mysql2 --env MYSQL_ROOT_PASSWORD=whatever mysql # 不換行
35fd131389c0343f0faadc4fbe74b976d216c1fc65cd84b
接著列出所有的 volume 看看:
$ docker volume list
DRIVER VOLUME NAME
local 2c1a7d85be3f0c1079ab0d73b92fd9aadb8204c2....
local 35fd131389c0343f0faadc4fbe74b976d216c1fc....
應該會開始意識到 VOLUME NAME 所帶來的問題,對吧?
從列出 volume 這件事情,我們沒有辦法得到任何有用的資訊,沒辦法知道這是接到哪一個。
而如果今天容器被刪除了呢?我們也知道刪除容器再次重啟是一件稀鬆平常的事情。
$ docker container rm --force mysql mysql2
mysql
mysql2
接著確認所有的容器都被刪除地乾乾淨淨了。
$ docker container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
接著再列出 volume,它們並沒有被刪除,就如同前面提到的,volume 正常情況下會需要透過手動來刪除。
$ docker volume list
DRIVER VOLUME NAME
local 2c1a7d85be3f0c1079ab0d73b92fd9aadb8204c2....
local 35fd131389c0343f0faadc4fbe74b976d216c1fc....
但現在好像完蛋了,哪一個 volume 是對應到哪一個服務呢?雖然資料都還在,難不成我要像在玩抽抽樂一樣嗎?這個 volume 去對應那個容器試試看好了,不行再換下一個?
為你的 volume 命名
顯然抽抽樂去對應容器不是一個有效率且聰明的作法,所以我們可以透過替 volume 命名來讓我們人類可以透過肉眼輕易的理解出區別。
回到最一開始啟動容器時的指令,可以透過加入 --volume
的指令,來告訴 Docker 要對應的 volume 名字是什麼:
$ docker container run --detach --name mysql --env MYSQL_ROOT_PASSWORD=whatever --volume /var/lib/mysql mysql # 不要輸入這段指令,是錯誤的
請你先別急著下指令,上面雖然加入了 --volume
的指令並且目的地也是 mysql 這個映像檔本身資料庫檔案存放的位置,但上述的寫法其實和沒寫是一樣的,因為 VOLUME /var/lib/mysql 早就被定義在 Dockerfile 裡面了不是嗎?
所以我們應該在目的地的前方加上 volume 的名字,像是這樣:
$ docker container run --detach --name mysql --env MYSQL_ROOT_PASSWORD=whatever --volume mysql-data:/var/lib/mysql mysql # 不換行
827b118d0aa7c8f83415e66d2a49106....
注意到了嗎?我們只需要在目的地的前方加上我們要取的名字,並且用冒號進行連接,就能夠建立一個有名字的 volume 並且連接到 /var/lib/mysql
這個路徑。
接著列出所有的 volume 看看,是不是真的有效:
$ docker volume list
DRIVER VOLUME NAME
local 2c1a7d85be3f0c1079ab0d73b92fd9aadb8204c2....
local 35fd131389c0343f0faadc4fbe74b976d216c1fc....
local mysql-data
接著 inspect
這個 volume 看看,是不是一切都變得易讀多了呢?
也可以輕鬆地透過名字來分辨這個 volume 是哪一個容器要用的:
$ docker volume inspect mysql-data
[
{
"CreatedAt": "2022-09-17T14:13:56Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mysql-data/_data",<-易讀
"Name": "mysql-data", <-易讀
"Options": null,
"Scope": "local"
}
]
除了在容器啟動時直接輸入 volume 的名字,如剛剛範例中的 mysql-data:/var/lib/mysql 之外,也可以提前建立好 volume,並連接到容器上。
$ docker volume create whatever
whatever
結語
希望大家有因為這次的鐵人賽而對 Docker 稍微有一些概念,進而自己去挖掘更多的功能!