【问题标题】:K8s 1.16: Mounting an existing directory in an image to a pvK8s 1.16:将镜像中的现有目录挂载到 pv
【发布时间】:2020-07-20 14:18:55
【问题描述】:

tl;dr:我们如何将 pod 中的现有目录挂载到 PV,从而使我们能够持久保存将要生成的数据?

我们目前正在运行 K8s 1.16.7,集成了 Azure Disk 和 Azure File。我们有一个图像,其中包含一些我们希望存储在 PV 上以保持持久性的目录。在 Docker 中,这很容易处理,因为容器会将数据写入主机挂载。有谁知道如何在 Kubernetes 中解决这个问题?当我们现在这样做时,容器会启动,但目录(例如:/etc/nginx/conf.d/ 作为 PV 的挂载)是空的,并且 Pod 崩溃了。

例子:

在下面的容器中,/usr/src/app 填充了 hello-world 应用程序。部署下面的文件后,容器由于无法在 /usr/src/app 中找到任何内容而崩溃(由于 PV 挂载,目录为空)。

---
apiVersion: v1
kind: Namespace
metadata:
  name: testwebsite
  labels:
    environment: development
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: normal
  namespace: testwebsite
provisioner: disk.csi.azure.com
parameters:
  storageaccounttype: Standard_LRS
  kind: Managed
  resourceGroup: resourcegroup
  cachingmode: None
mountOptions:
  - dir_mode=0777
  - file_mode=0777
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-azurefile
  namespace: testwebsite
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: normal
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-kubernetes
  namespace: testwebsite
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-kubernetes
  template:
    metadata:
      labels:
        app: hello-kubernetes
    spec:
      containers:
      - name: hello-kubernetes
        image: paulbouwer/hello-kubernetes:1.8
        ports:
        - containerPort: 8080
        volumeMounts:
          - name: azurefile01
            mountPath: "/usr/src/app"
      volumes:
      - name: azurefile01
        persistentVolumeClaim:
          claimName: pvc-azurefile

目标:将容器内 /usr/src/app 中的数据写入 PV。

提前谢谢!

【问题讨论】:

    标签: kubernetes storage persistent-volumes


    【解决方案1】:

    据我了解您的要求,每次创建 Pod 时,您都希望其 /usr/src/app 包含迄今为止由您的应用生成并永久存储在 PersistentVolume 中的数据以及原始数据/usr/src/app 的内容是您的paulbouwer/hello-kubernetes:1.8 图像的组成部分,可在/usr/src/app 目录下找到。

    你可以在kubernetes中使用init container来实现它,这会将Pod启动过程中/usr/src/app目录的原始内容复制到PersistentVolume可能已经包含一些数据,之前由您的应用生成。在这样的卷初始化之后,主容器将挂载PersistentVolume,其中包含您的应用先前生成的数据(如果有的话)以及您图像中/usr/src/app目录的原始内容。

    您的Deployment 可能如下所示:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-kubernetes
      namespace: testwebsite
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello-kubernetes
      template:
        metadata:
          labels:
            app: hello-kubernetes
        spec:
          initContainers:
          - name: init-hello-kubernetes
            image: paulbouwer/hello-kubernetes:1.8
            command: ['sh', '-c', 'cp -a /usr/src/app/* /mnt/pv-content/']
            volumeMounts:
             - name: azurefile01
               mountPath: "/mnt/pv-content"
          containers:
          - name: hello-kubernetes
            image: paulbouwer/hello-kubernetes:1.8
            ports:
            - containerPort: 8080
            volumeMounts:
              - name: azurefile01
                mountPath: "/usr/src/app"
          volumes:
          - name: azurefile01
            persistentVolumeClaim:
              claimName: pvc-azurefile
    

    为了从paulbouwer/hello-kubernetes:1.8 图像的/usr/src/app/ 中获取原始数据,您的 init 容器也必须基于该图像。

    一个警告: paulbouwer/hello-kubernetes:1.8 图像必须包含 cp 二进制文件才能执行操作。

    如您所见,这不是一个非常“优雅”的解决方案。好吧,事实上并非如此。这就是为什么不建议将您的PersistentVolume 挂载到已经包含一些重要文件的目录下,这些文件需要您的应用程序才能正常运行。但是没有办法在某个挂载点下挂载一个卷并同时保留其原始内容。它在 Linux 或其他基于 nix 的系统中根本无法以这种方式工作。您要么挂载整个卷,要么根本不挂载它并保留特定目录的原始内容。原始内容甚至没有被覆盖。它还在那里。当这个特定路径被用作不同卷的挂载点时,它只是保持不可用。

    【讨论】:

    • 感谢您的回答马里奥!我记得使用 Docker(所以不是 kubernetes)将主机目录安装到容器中。容器会将原始数据写入挂载的主机路径,因此在移除容器后数据仍然存在。很遗憾听到这在 K8s 中以一种优雅的方式是不可能的。 :-(
    猜你喜欢
    • 2019-09-27
    • 2014-04-15
    • 2022-01-08
    • 2021-03-11
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    相关资源
    最近更新 更多