前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >k8s subPathExpr stat no such file or directory 及挂载后找不到文件的问题

k8s subPathExpr stat no such file or directory 及挂载后找不到文件的问题

作者头像
饶文津
发布2022-05-11 10:22:56
1.4K0
发布2022-05-11 10:22:56
举报
文章被收录于专栏:饶文津的专栏饶文津的专栏

在 k8s 集群、云基础架构或是网络设备上我们常常需要用 fluent bit、fluentd 之类的工具来收集日志。其中一种架构是将收集日志的 agent 运行在宿主机上,我们自己的服务写日志,agent 收集日志转发到 elastic search 之类的处理后端上。

如果 agent 和我们自己的服务都是以 pod 的形式运行在 k8s 集群上,我们就需要让他们一个读一个写同一个文件,就都需要挂载同一个目录。而当我们有多个 pod 可能有相同的日志路径时,我们就要保证能区别出不同的 pod 的日志。

挂载时映射到不同路径

一种方法是直接写日志时,写到包含 POD_NAME 这类环境变量的路径下。但我想在挂载目录时就映射到宿主机包含 POD_NAME 的目录下,于是就考虑 SubPathExpr,这个是 Kubernetes 1.17 后有的功能。

大概的用法如下

代码语言:javascript
复制
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

然而执行

代码语言:javascript
复制
kubectl apply -f deployment.yaml

后,并没有成功运行起来,

代码语言:javascript
复制
kubectl describe pod my-pod-xxx -n mynamespace

发现报错

代码语言:javascript
复制
Error: stat /tmp/log: no such file or directory

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

代码语言:javascript
复制
      volumes:
        - name: log
          hostPath:
            path: /tmp/log
            type: DirectoryOrCreate

这下是运行起来了,但是本地怎么就不见 /tmp/log 里有新的文件夹呢?

到容器里执行

代码语言:javascript
复制
mount | grep "/tmp/log"

得到

代码语言:javascript
复制
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 挂载的长这样

代码语言:javascript
复制
/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 来存配置文件。

代码语言:javascript
复制
kind: ConfigMap
apiVersion: v1
metadata:
  name: log-config
  namespace: development
data:
  log.conf: >+
    xxxxxx
    xxxxxx.File=/log/${POD_NAME}/xxxx.log
    xxxxxx

然后

代码语言:javascript
复制
kubectl apply -f configmap.yml

还要编辑 deployment:

代码语言:javascript
复制
          - 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

代码语言:javascript
复制
kubectl apply -f development.yml
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 挂载时映射到不同路径
  • 修改写日志的路径
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档