關於hostPath的權限說明
最近項目中經常遇到pod中container掛載主機hostPath報錯無權限問題:
httpd@hostpath-volume:/test-volume$ touch 123
touch: cannot touch '123': Permission denied
於是又復習了一遍hostPath使用方法,發現沒有什么新知識的涌入:
值 | 行為 |
---|---|
空字符串(默認)用於向后兼容,這意味着在掛載hostPath卷之前不會進行任何檢查 | |
DirectoryOrCreate | 如果給定的路徑沒有任何東西存在,那將根據需要在此創建一個空目錄,權限設置為0755,與kubelet擁有相同的用戶與組 |
Directory | 指定路徑下必須存在此目錄 |
FileOrCreate | 如果給定的路徑沒有任何東西存在,那將根據需要在此創建一個空文件,權限設置為0644,與kubelet擁有相同的用戶與組 |
File | 給定的路徑下必須存在文件 |
Socket | 給定的路徑下必須存在Unix套接字 |
CharDevice | 給定的路徑下必須存在字符設備 |
BlockDevice | 給定的路徑下必須存在塊設備 |
使用這種卷類型時請注意:
- 由於每個節點上的文件不同,具有相同配置(例如從 podTemplate創建的)的pod在不同節點上的行為可能會有所不同
- 當Kubernetes按照計划添加資源感知調度時,將無法考慮hostPath使用的資源
- 在底層主機上創建的文件或目錄只能由root寫入。必須在特權容器中以root身份運行進程,或修改主機上文件權限以便寫入 hostPath 卷
注意幾個話術
- 當值為DirectoryOrCreate和FileOrCreate時,並且給定的路徑或文件不存在時,kubelet會自動創建,並且會和kubelet擁有相同的用戶與組,說白了,就是你用什么用戶起的kubelet創建出來的就是此用戶的屬主數組。
- 必須在特權容器中以root身份運行進程,或修改主機上文件權限以便寫入 hostPath 卷。如果你的容器不是以root用戶運行的,這一點可要注意了。
問題的根源
查看發現,容器掛載hostPath寫入時報錯Permission denied時基本都是容器運行用戶不是root的情況下,這就說明,啟動容器的用戶沒有權限在宿主機中屬主屬組為root的目錄或者文件中寫入。
這就很清晰明了,只要賦予運行容器的用戶寫權限,這個問題就解決了。
可是,我們應該賦予哪個用戶呢?在宿主機創建一個與啟動容器相同的用戶然后賦予權限嗎?顯然不行。
那么容器用戶與宿主機用戶的對應關系是什么呢?沒錯,是uid。
只要將宿主機的用戶與啟動容器用戶的uid相對應上,並且給它寫的權限,那這個問題就迎刃而解了。
做幾個測試
-
先創建一個普通用戶起的container
apiVersion: v1 kind: Pod metadata: name: hostpath-volume namespace: default spec: containers: - name: hostpath-container image: nginx-test:v1 imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /test-volume name: dir-volume volumes: - name: dir-volume hostPath: path: /data/vfan/test/ type: DirectoryOrCreate
-
創建這個pod,測試寫入
## kubectl create -f hostpath-test.yaml ## httpd@hostpath-volume:/$ cd /test-volume/ httpd@hostpath-volume:/test-volume$ touch 11 22 33 touch: cannot touch '11': Permission denied touch: cannot touch '22': Permission denied touch: cannot touch '33': Permission denied
-
查看宿主機相對應目錄的權限
# ll -dh /data/vfan/test/ drwxr-xr-x 2 root root 4.0K Mar 21 14:53 /data/vfan/test/
-
查看容器內用戶的uid,並查看宿主機的此uid用戶是誰
## 容器內 httpd@hostpath-volume:/test-volume$ id uid=1000(httpd) gid=1000(httpd) groups=1000(httpd) ## 容器外 # grep 1000 /etc/passwd work:x:1000:1000::/home/work:/bin/bash
如果沒有相同uid的用戶,則創建一個對應用戶即可:useradd -u 1000 xxx
-
賦予宿主機對應uid用戶權限,再次測試
## 宿主機 chown work:work test/ ## 容器內 httpd@hostpath-volume:/test-volume$ touch 11 22 33 httpd@hostpath-volume:/test-volume$ ls 11 22 33
-
容器內外權限分別是什么?
## 容器內 httpd@hostpath-volume:/test-volume$ ls -ld /test-volume/ drwxr-xr-x 2 httpd httpd 4096 Mar 21 07:27 /test-volume/ ## 容器外 [root@gzbh-intel002.gom vfan]# ll -dh /data/vfan/test/ drwxr-xr-x 2 work work 4.0K Mar 21 15:27 /data/vfan/test/