容器是隔離環境,容器內程式的檔案、設定等都在容器的內部,要讀寫容器內的檔案非常不方便。
因此,容器提供程式的執行環境,但是程式執行產生的資料、程式執行依賴的設定都應該與容器進行解耦。
資料卷(volume)是一個虛擬目錄,是容器內目錄與宿主機目錄之間對映的橋樑。
以Nginx為例,我們知道Nginx中有兩個關鍵的目錄:
html
:放置一些靜態資源;conf
:放置組態檔;如果我們要讓Nginx代理我們的靜態資源,最好是放到html
目錄;如果我們要修改Nginx的設定,最好是找到conf
下的nginx.conf
檔案。
從dockerhub的nginx說明處,我們可以看到nginx靜態檔案的位置:
不過,容器執行的Nginx所有的檔案都在容器內部。所以我們必須利用資料卷將兩個目錄與宿主機目錄關聯,方便我們操作。如圖:
在上圖中:
conf
、html
conf
目錄和html
目錄分別與兩個資料卷關聯/var/lib/docker/volumes/conf/_data
目錄和/var/lib/docker/volumes/html/_data
目錄這樣,容器內的conf
和html
目錄就與宿主機的conf
和html
目錄關聯起來,被稱為掛載。此時,操作宿主機的/var/lib/docker/volumes/html/_data
就是在操作容器內的/usr/share/nginx/html/_data
目錄。只要我們將靜態資源放入宿主機對應目錄,就可以被Nginx代理了。
資料卷的相關命令有:
命令 | 說明 | 檔案地址 |
---|---|---|
docker volume create | 建立資料卷 | docker volume create |
docker volume ls | 檢視所有資料卷 | docs.docker.com |
docker volume rm | 刪除指定資料卷 | docs.docker.com |
docker volume inspect | 檢視某個資料卷的詳情 | docs.docker.com |
docker volume prune | 清除資料卷 | docker volume prune |
注意:容器與資料卷的掛載要在建立容器時設定,對於建立好的容器,是不能設定資料卷的。而且建立容器的過程中,資料卷會自動建立。
需求如下:
建立Nginx容器,修改nginx容器內的html目錄下的index.html檔案內容
將靜態資源部署到nginx的html目錄
注意:
1. 在執行docker run命令時,使用 -v 資料卷:容器內目錄 可以完成資料卷掛載
2. 當建立容器時,如果掛載了資料卷且資料卷不存在,會自動建立資料卷
docker rm -f nginx
# 首先建立容器並指定資料卷,通過 -v 引數來指定資料卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
docker volume ls
docker volume inspect html
可以看到對映到的宿主機的目錄為
進入這個目錄,修改對應的html檔案即可。
需求:
檢視mysql容器,判斷是否有資料卷掛載
基於宿主機目錄實現MySQL資料目錄、組態檔、初始化指令碼的掛載(查閱官方映象檔案)
1. 掛載/root/mysql/data到容器內的/var/lib/mysql目錄
2. 掛載/root/mysql/init到容器內的/docker-entrypoint-initdb.d目錄
3. 掛載/root/mysql/conf到容器內的/etc/mysql/conf.d目錄
注意:
1. 在執行docker run命令時,使用 -v 本地目錄 : 容器內目錄 可以完成本地目錄掛載
2. 本地目錄必須以「/」或 "./" 開頭,如果直接以名稱開頭,會被識別為資料卷而非本地目錄
-v mysql : /var/lib/mysql 會被識別為一個資料卷叫mysql
-v ./mysql : /var/lib/mysql 會被識別為當前目錄下的mysql目錄
# 檢視MySQL容器詳細資訊
docker inspect mysql
# 關注其中.Config.Volumes部分和.Mounts部分
.Config.Volumes
部分:
可以發現這個容器宣告了一個本地目錄,需要掛載資料卷,但是資料卷未定義。這就是匿名卷。
.Mounts
部分:
可以發現,其中有幾個關鍵屬性:
上述設定是將容器內的/var/lib/mysql
目錄,這時mysql資料儲存的目錄,與資料卷0d617a75a536b8d4a7ac0705403677721e1467a9859350d908861d340009a001
掛載。於是在宿主機中就有了/var/lib/docker/volumes/0d617a75a536b8d4a7ac0705403677721e1467a9859350d908861d340009a001/_data
這個目錄。這就是匿名資料卷對應的目錄,其使用方式與普通資料卷沒有差別。
資料卷的目錄結構較深,如果我們去運算元據卷目錄會不太方便。在很多情況下,我們會直接將容器目錄與宿主機指定目錄掛載。掛載語法與資料卷類似:
# 掛載本地目錄
-v 本地目錄:容器內目錄
# 掛載本地檔案
-v 本地檔案:容器內檔案
再次說明一下:
本地目錄必須以「/」或 "./" 開頭,如果直接以名稱開頭,會被識別為資料卷而非本地目錄
-v mysql:/var/lib/mysql # 會被識別為一個資料卷叫mysql,執行時會自動建立這個資料卷
-v ./mysql:/var/lib/mysql # 會被識別為當前目錄下的mysql目錄,執行時如果不存在會建立目錄
從檔案中可以看到,設定mysql組態檔的目錄如下:
設定初始化指令碼如下:
只有第一次才會生效
資料目錄如下:
刪除並重新建立mysql容器,並完成本地目錄掛載:
/root/mysql/data
到容器內的/var/lib/mysql
目錄/root/mysql/init
到容器內的/docker-entrypoint-initdb.d
目錄(初始化的SQL指令碼目錄)/root/mysql/conf
到容器內的/etc/mysql/conf.d
目錄(這個是MySQL組態檔目錄)刪除原來的MySQL容器
docker rm -f mysql
進入root目錄
cd ~
建立並執行新mysql容器,掛載本地目錄
先提前建立這些目錄
在 root目錄操作
mkdir mysql
# 進入mysql目錄
cd mysql/
#建立以下三個目錄
mkdir data
mkdir conf
mkdir init
把主備好的組態檔和指令碼放到過去:
直接把目錄上傳到linux伺服器:
上傳後內容如下:
在root的家目錄執行執行如下命令
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v ./mysql/data:/var/lib/mysql \
-v ./mysql/conf:/etc/mysql/conf.d \
-v ./mysql/init:/docker-entrypoint-initdb.d \
mysql
可以看到data目錄有檔案了