English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french
查看: 8|回复: 0

Kubernetes使用存储挂载单个文件

[复制链接]
查看: 8|回复: 0

Kubernetes使用存储挂载单个文件

[复制链接]
查看: 8|回复: 0

233

主题

0

回帖

709

积分

高级会员

积分
709
YDVK46VSRap

233

主题

0

回帖

709

积分

高级会员

积分
709
2025-2-21 20:15:44 | 显示全部楼层 |阅读模式
一般来说, 挂载存储都是把一个 PV 挂载到一个路径, 挂载后此路径下原来的文件就会不见, 只能看到挂载后的文件, 和在 Linux 下挂载磁盘是一样的. 那么现在有个需求:
需求

此服务是 java 程序, 数据库使用的是内嵌的 h2 database, 下图中的两个文件就是数据库的文件. 这两个文件是存在于根目录下的, 假设此程序数据库文件是代码写死的 (真实情况是: 数据库路径是可以更改的), 现在要部署到 kubernetes 中, 并对数据库做持久化.

使用 subpath

根据之前挂载 configmap 到单个文件的经验, 我们应该使用 subpath 来挂载, 先创建好 pvc, yml 如下
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: metabase-pvc
spec:
  storageClassName: managed-nfs-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
statefulset 的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
spec:
  replicas: 1
  serviceName: "metabase"
  selector:
    matchLabels:
      app: metabase
  template:
    metadata:
      labels:
        app: metabase
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/iuxt/metabase:test
        name: metabase
        volumeMounts:
        - name: metabase-pv
          mountPath: /metabase.db.mv.db
          subPath: metabase.db.mv.db
        - name: metabase-pv
          mountPath: /metabase.db.trace.db
          subPath: metabase.db.trace.db
      volumes:
        - name: metabase-pv
          persistentVolumeClaim:
            claimName: metabase-pvc
但是这样挂载后, 容器内的 metabase.db.mv.db 和 metabase.db.trace.db 是目录, 并不是文件, 程序也自然无法启动.
subpath 原理

下面是绑定 subPath 的源码部分,我们可以看到下面的 t.Model()&os.ModeDir 部分,如果 subPath 是一个文件夹的话就会去创建这个文件夹,如果是文件的话就进行单独挂载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func doBindSubPath(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 ".
        // 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)
        }
    }
    ...
}
那么我们可不可以通过手动创建好文件来实现需求, 答案是可以的. 你可以自己测试下, 但是在存储中手动创建文件也太不优雅了..
使用 init container 来自动创建空文件

init container 非常适合来做这件事, 那么完整的 yaml 文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    name: metabase-StatefulSet
  name: metabase
spec:
  replicas: 1
  serviceName: "metabase"
  selector:
    matchLabels:
      app: metabase
  template:
    metadata:
      labels:
        app: metabase
    spec:
      initContainers:
      - name: init
        image: busybox:1.28
        command: ['sh', '-c', "touch /metabase/metabase.db.mv.db /metabase/metabase.db.trace.db"]
        volumeMounts:
        - name: metabase-pv
          mountPath: /metabase
      volumes:
        - name: metabase-pv
          persistentVolumeClaim:
            claimName: metabase-pvc
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/iuxt/metabase:test
        name: metabase
        ports:
        - containerPort: 3000
          protocol: TCP

        volumeMounts:
        - name: metabase-pv
          mountPath: /metabase.db.mv.db
          subPath: metabase.db.mv.db
        - name: metabase-pv
          mountPath: /metabase.db.trace.db
          subPath: metabase.db.trace.db
        - name: metabase-pv
          mountPath: /metabase/plugins
          subPath: plugins
      volumes:
        - name: metabase-pv
          persistentVolumeClaim:
            claimName: metabase-pvc
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: metabase
  name: metabase
spec:
  ports:
  - port: 3000
    targetPort: 3000
  selector:
    app: metabase
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: metabase
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: intranet
  tls:
  - hosts:
    - metabase.i.com
    secretName: i-com
  rules:
  - host: metabase.i.com
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: metabase
            port:
              number: 3000
这样完美解决了问题, 并且不会影响到目录下的其他文件.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

233

主题

0

回帖

709

积分

高级会员

积分
709

QQ|智能设备 | 粤ICP备2024353841号-1

GMT+8, 2025-3-11 02:24 , Processed in 1.191859 second(s), 29 queries .

Powered by 智能设备

©2025

|网站地图