前言
docker 中的 volume 可以 mount 文件到特定目錄,同時保留原有目錄不變;同樣的 mount 放到 Kubernetes 卻變成了:只是把 mount 的幾個文件直接放到了根目錄,原有目錄中文件消失。在很多場景下,我們會希望只是掛載一個文件到容器內部某個目錄,而不影響原有目錄,常見使用場景有以下兩種:
我需要把一個特定文件放置到 linux 特定目錄下,且需要依賴 linux 底層 lib 庫,該目錄下已經存在其它文件,不能覆蓋。
項目在沒有容器化之前,證書和配置通常放到一個目錄中,現在容器化之後依然如此,這就有個問題,當把證書放到 Secret、配置放到 ConfigMap中,之後 mount 到容器特定目錄時互相覆蓋,影響服務正常運行,這些都是一些非常常見的場景。
當然解決方式也非常簡單,大致如下兩種:
首先我可以通過曲線救國的方式把這些文件掛載到其它目錄,不影響原有文件夾。這樣一來,就解決了文件覆蓋問題,但是如果程序中已經配置只能從特定文件夾讀取該文件,或者該文件只能在特定文件夾下運行,如果非要修改目錄,那麼就需要修改代碼,這種方式不在過多解釋。
其次我通過查找 Kubernetes 官網
https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath
Kubernetes 官方已經通過 subPath 解決同一個 Pod 多次使用同一個 volume 而引起的覆蓋問題,下面通過示例解釋,如何通過 subPath 解決同一個 Pod 共享數據卷問題。
subPath 使用
以下是使用單個共享卷的 LAMP 堆棧(Linux Apache Mysql PHP)的 pod 的示例。HTML 內容映射到其 html 文件夾,數據庫將存儲在 mysql 文件夾中,這樣就不需要爲 mysql 和 html 單獨創建 volume 了。
apiVersion: v1
kind: Pod
metadata:
name: my-lamp-site
spec:
containers:
- name: mysql
image: mysql
volumeMounts:
- mountPath: /var/lib/mysql
name: site-data
subPath: mysql
- name: php
image: php
volumeMounts:
- mountPath: /var/www/html
name: site-data
subPath: html
volumes:
- name: site-data
persistentVolumeClaim:
claimName: my-lamp-site-data
那麼如果 subPath 不是文件夾,而是一個文件,又該如何解決呢?同樣的道理,只需要通過 subPath 指定出該文件即可,注意 subPath 要使用相對目錄。具體如下所示:
containers:
- volumeMounts:
- name: demo-config
mountPath: /etc/ssl.key
subPath: ssl.key
volumes:
- name: demo-ssl
configMap:
name: ssl-secret
Kubernetes 如何實現 subPath
代碼進行了精簡,重點 t.Mode()&os.ModeDir 即根據 volume 中的 subPath 指定的是目錄還是文件分別進行不同的操作。
func (mounter Interface, subpath Subpath, kubeletPid int) (hostPath string, err error) {
...
// Create target of the bind mount. A directory for directories, empty file
// for everything else.
t, err := os.Lstat(subpath.Path)
if err != nil {
return "", fmt.Errorf("lstat %s failed: %s", subpath.Path, err)
}
if t.Mode()&os.ModeDir > 0 {
if err = os.Mkdir(bindPathTarget, 0750); err != nil && !os.IsExist(err) {
return "", fmt.Errorf("error creating directory %s: %s", bindPathTarget, err)
}
} else {
// "/bin/touch <bindDir>".
// A file is enough for all possible targets (symlink, device, pipe,
// socket, ...), bind-mounting them into a file correctly changes type
// of the target file.
if err = ioutil.WriteFile(bindPathTarget, []byte{}, 0640); err != nil {
return "", fmt.Errorf("error creating file %s: %s", bindPathTarget, err)
}
}
總結
本文主要介紹了通過使用 volume subPath 解決把文件掛載到容器已存在文件的目錄且不覆蓋原有目錄的方法。更多文檔請參考 [1]
參考資料
[1]
更多文檔: https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath
推薦閱讀
原創不易,隨手關注或者”在看“,誠摯感謝!