k8s subPathExpr stat no such file or directory 及掛載后找不到文件的問題


在 k8s 集群、雲基礎架構或是網絡設備上我們常常需要用 fluent bit、fluentd 之類的工具來收集日志。其中一種架構是將收集日志的 agent 運行在宿主機上,我們自己的服務寫日志,agent 收集日志轉發到 elastic search 之類的處理后端上。

如果 agent 和我們自己的服務都是以 pod 的形式運行在 k8s 集群上,我們就需要讓他們一個讀一個寫同一個文件,就都需要掛載同一個目錄。而當我們有多個 pod 可能有相同的日志路徑時,我們就要保證能區別出不同的 pod 的日志。

掛載時映射到不同路徑

一種方法是直接寫日志時,寫到包含 $POD_NAME 這類環境變量的路徑下。但我想在掛載目錄時就映射到宿主機包含 $POD_NAME 的目錄下,於是就考慮 SubPathExpr,這個是 Kubernetes 1.17 后有的功能。

大概的用法如下

apiVersion: apps/v1
kind: Deployment
...
spec:
    spec:
      containers:
      - name: asr
        ...
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        volumeMounts:
          - name: log
            mountPath: /log
            subPathExpr: $(POD_NAME)
      volumes:
        - name: log
          hostPath:
            path: /tmp/log

然而執行

kubectl apply -f deployment.yaml

后,並沒有成功運行起來,

kubectl describe pod my-pod-xxx -n mynamespace

發現報錯

Error: stat /tmp/log: no such file or directory

非常地不解,也只好先加上 type:

      volumes:
        - name: log
          hostPath:
            path: /tmp/log
            type: DirectoryOrCreate

這下是運行起來了,但是本地怎么就不見 /tmp/log 里有新的文件夾呢?

到容器里執行

mount | grep "/tmp/log"

得到

overlay on /tmp/log type overlay (rw,relatime,lowerdir=/data00/docker/lib/overlay2/l/CCC:....省略...:/data00/docker/lib/overlay2/l/NNN,upperdir=/data00/docker/lib/overlay2/eee/diff,workdir=/data00/docker/lib/overlay2/eee/work)

而其它 hostPath 掛載的長這樣

/dev/vda1 on /opt/tmp/xxx type ext4 (rw,relatime,errors=remount-ro,data=ordered)

后來找到了這個 issue:

https://github.com/kubernetes/kubernetes/issues/61456

(實際上先搜到的是一個翻譯文 ddeevv.com/question/kubernetes-kubernetes-61456.html

原來是因為早期 k8s 不會對 subPath 做檢查,於是就存在一個漏洞,用戶可以搞一個軟鏈接,讓容器可以訪問任何宿主機上的目錄,后來修復了這個漏洞 https://kubernetes.io/blog/2018/04/04/fixing-subpath-volume-vulnerability/,

就導致容器方式(containerized)運行的 kubelet,用 subPath (或 subPathExpr)后創建的目錄就跑到 kubelet 的容器里了。

那要怎么辦呢,如果 kubelet 是你自己部署的,那可以把 hostPath 對應的路徑給掛載到 kubelet 的容器里,不然就沒辦法了

其實還有辦法,就是不用 subPath(subPathExpr 同),而是搞個 initContainer 來創建目錄。

修改寫日志的路徑

或者繞過去,修改寫日志的路徑,由於我們有多個日志要寫,統一用配置文件來配置這些日志寫的路徑,所以就可以搞一個 configmap 來存配置文件。

kind: ConfigMap
apiVersion: v1
metadata:
  name: log-config
  namespace: development
data:
  log.conf: >+
    xxxxxx
    xxxxxx.File=/log/${POD_NAME}/xxxx.log
    xxxxxx

然后

kubectl apply -f configmap.yml

還要編輯 deployment:

          - name: log
            mountPath: /log/
            # subPathExpr: $(POD_NAME)
          - name: log-config
            mountPath: /conf
            readOnly: true
      volumes:
        - name: log
          hostPath:
            path: /my/log
        - name: log-config
          configMap:
            name: log-config

kubectl apply -f development.yml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM