• 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
    
  • 相关阅读:
    『C#基础』数据库死锁笔记
    『C#基础』IIS的权限问题
    『C#基础』调用CMD的一个小工具
    『C#基础』获取系统图标的一个操作类
    『程序人生』其实,做软件与打游戏是一样一样的……
    『C#基础』C#调用存储过程
    『Linux』Arch Linux与VirtualBox的结合
    sql server 触发器简单学习
    用触发器替换原来的insert
    食物增肥一方
  • 原文地址:https://www.cnblogs.com/flipped/p/15855902.html
Copyright © 2020-2023  润新知