如何在多个 Pod 上挂载相同的持久卷?

2024-03-15

我有一个三节点 GCE 集群和一个具有三个副本的单 Pod GKE 部署。我像这样创建了 PV 和 PVC:

# Create a persistent volume for web content
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nginx-content
  labels:
    type: local
spec:
  capacity:
    storage: 5Gi
  accessModes:
   - ReadOnlyMany
  hostPath:
    path: "/usr/share/nginx/html"
--
# Request a persistent volume for web content
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-content-claim
  annotations:
    volume.alpha.kubernetes.io/storage-class: default
spec:
  accessModes: [ReadOnlyMany]
  resources:
    requests:
      storage: 5Gi

它们在容器规范中引用如下:

    spec:
      containers:
      - image: launcher.gcr.io/google/nginx1
        name: nginx-container
        volumeMounts:
          - name: nginx-content
            mountPath: /usr/share/nginx/html
        ports:
          - containerPort: 80
      volumes:
      - name: nginx-content
        persistentVolumeClaim:
          claimName: nginx-content-claim

尽管我将卷创建为 ReadOnlyMany,但在任何给定时间只有一个 pod 可以挂载该卷。其余的给出“错误 400:RESOURCE_IN_USE_BY_ANOTHER_RESOURCE”。如何才能使所有三个副本从同一卷读取相同的 Web 内容?


首先,我想指出您的配置中的一个根本差异。请注意,当您使用您的PersistentVolumeClaim如您的示例中所定义,您不使用您的nginx-content PersistentVolume根本不。您可以通过运行以下命令轻松验证它:

kubectl get pv

on your GKE集群。您会注意到,除了手动创建的nginx-content PV,还有另外一个,是根据PVC你申请的。

请注意,在您的PersistentVolumeClaim您明确引用的定义default与您手动创建的存储类无关PV。实际上即使你完全省略注释:

annotations:
        volume.alpha.kubernetes.io/storage-class: default

它将以完全相同的方式工作,即default无论如何都会使用存储类。使用默认存储类别GKE意思是GCE持久磁盘将用作您的卷配置程序。您可以阅读更多相关内容here https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes#storageclasses:

配置了 gcePersistentDisk 等卷实现 通过 StorageClass 资源。 GKE 为以下对象创建默认 StorageClass 使用标准永久磁盘类型 (ext4) 的您。默认 当 PersistentVolumeClaim 未指定时,使用 StorageClass 存储类名称。您可以替换提供的默认 StorageClass 与你自己的。

但让我们继续解决您所面临的问题。

解决方案:

首先我想强调一下您不必使用任何类似 NFS 的文件系统来实现您的目标.

如果您需要您的PersistentVolume可用于ReadOnlyMany mode, GCE持久磁盘是一个完全满足您要求的完美解决方案。

它可以安装在ro许多人的模式Pods与此同时,对许多人来说更重要的是Pods,安排在不同的GKE nodes。此外,它的配置非常简单并且可以正常工作GKE盒子外面。

如果您想使用存储空间ReadWriteMany模式,我同意像 NFS 这样的东西可能是唯一的解决方案GCE持久磁盘不提供这样的能力。

让我们仔细看看如何配置它。

我们需要从定义我们的PVC。这一步实际上已经由您完成,但您在进一步的步骤中有点迷失了。让我解释一下它是如何工作的。

以下配置是正确的(正如我提到的annotations部分可以省略):

# Request a persistent volume for web content
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-content-claim
spec:
  accessModes: [ReadOnlyMany]
  resources:
    requests:
      storage: 5Gi

不过,我想对此添加一条重要评论。你说:

尽管我将卷创建为 ReadOnlyMany,但只有一个 pod 可以 在任何给定时间安装卷。

实际上你没有。我知道这可能看起来有点棘手并且有点令人惊讶,但这不是定义的方式accessModes真的有效。事实上,这是一个被广泛误解的概念。首先您不能定义访问模式PVC从某种意义上说,把你想要的约束放在那里。支持的访问模式是特定存储类型的固有特征。它们已经由存储提供商定义。

你实际上在做什么PVC定义要求一个PV支持特定的访问模式或访问模式。请注意,它的形式为a list这意味着您可以提供许多您想要的不同访问模式PV支持。

基本上就像是在说:“嘿!存储提供商!给我一个支持的卷ReadOnlyMany mode."您以这种方式请求能够满足您要求的存储。但请记住,你得到的可能比你要求的更多。这也是我们请求时的场景PV支持ReadOnlyMany模式在GCP。它为我们创造了一个PersistentVolume这符合我们列出的要求accessModes部分但它也支持ReadWriteOnce模式。虽然我们没有要求也支持的东西ReadWriteOnce您可能会同意我的观点,即内置支持这两种模式的存储完全满足我们对支持的要求ReadOnlyMany。基本上这就是它的工作原理。

Your PV由 GCP 自动配置以响应您的PVC支持这两个accessModes如果你没有明确指定Pod or Deployment您想要将其安装到的定义只读模式,默认安装在读写 mode.

您可以通过附加到Pod就能够成功挂载了PersistentVolume:

kubectl exec -ti pod-name -- /bin/bash

并尝试在已安装的文件系统上写入一些内容。

您收到的错误消息:

"Error 400: RESOURCE_IN_USE_BY_ANOTHER_RESOURCE"

特别关注GCE持久磁盘已经被一个安装了GKE node in ReadWriteOnce模式,并且不能被其他人安装node你的其余部分Pods已安排。

如果你想把它安装在ReadOnlyManymods,您需要在您的Deployment定义通过添加readOnly: true中的声明volumes下的部分Pod's模板规格如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nginx-content
      volumes:
      - name: nginx-content
        persistentVolumeClaim:
          claimName: nginx-content-claim
          readOnly: true

但请记住,能够将其安装在readOnly模式,首先我们需要用数据预先填充该卷。否则,您将看到另一条错误消息,指出无法以只读模式安装未格式化的卷。

最简单的方法是创建一个Pod这仅用于复制已上传到我们的其中之一的数据GKE 节点到我们的目的地PV.

请注意,预填充PersistentVolume可以通过多种不同的方式来处理数据。你可以安装在这样的Pod只有你的PersistentVolume您将在您的Deployment并使用获取您的数据curl or wget从某个外部位置将其直接保存在您的目的地PV。由你决定。

在我的示例中,我展示了如何使用额外的方法来做到这一点local https://kubernetes.io/docs/concepts/storage/volumes/#local允许我们安装到我们的体积Pod a directory, partition or disk(在我的示例中,我使用一个目录/var/tmp/test位于我的 GKE 节点之一)可在我们的 kubernetes 节点之一上使用。它的解决方案比hostPath因为我们不必关心这样的安排Pod到包含数据的特定节点。具体的节点亲和力规则已经定义在PersistentVolume and Pod自动调度到特定节点上。

要创建它,我们需要三件事:

StorageClass:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

PersistentVolume定义:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /var/tmp/test
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - <gke-node-name>

最后PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 10Gi
  storageClassName: local-storage

然后我们就可以创建临时的Pod这仅用于从我们的复制数据GKE node to our GCE持久磁盘.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/mnt/source"
        name: mypd
      - mountPath: "/mnt/destination"
        name: nginx-content
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim
    - name: nginx-content
      persistentVolumeClaim:
        claimName: nginx-content-claim

您在上面看到的路径并不重要。此次的任务Pod只是允许我们将数据复制到目的地PV。最终我们的PV将安装在完全不同的路径中。

一旦Pod创建完毕并且两个卷都已成功安装,我们可以通过运行以下命令附加到它:

kubectl exec -ti my-pod -- /bin/bash

Pod只需运行:

cp /mnt/source/* /mnt/destination/

就这样。现在我们可以exit并删除我们的临时Pod:

kubectl delete pod mypod

一旦它消失了,我们就可以应用我们的Deployment和我们的PersistentVolume最后可以安装在readOnly模式由所有Pods位于各个GKE 节点:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nginx-content
      volumes:
      - name: nginx-content
        persistentVolumeClaim:
          claimName: nginx-content-claim
          readOnly: true

顺便提一句。如果您同意您的事实Pods仅在一个特定节点上调度,您可以放弃使用GCE持久磁盘根本并切换到上面提到的local https://kubernetes.io/docs/concepts/storage/volumes/#local体积。这样你所有的Pods不仅可以读取它,还可以同时写入它。唯一需要注意的是所有这些Pods将在单个节点上运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在多个 Pod 上挂载相同的持久卷? 的相关文章

  • Ruby on Rails - 复选框未保存到数据库?

    我有一个迁移 它使用布尔值并在其视图中生成一个复选框 但是 无论我单击什么 保存到数据库的值都不会受到影响 我的迁移看起来像这样 def self up create table blogposts do t t string title
  • 将二进制数转换为包含每个二进制数的数组

    我试图将二进制值转换为每个 1 0 的列表 但我得到默认的二进制值而不是列表 我有一个字符串 我将每个字符转换为二进制 它给了我一个列表 其中每个字符都有一个字符串 现在我试图将每个字符串拆分为值为 0 1 的整数 但我什么也得不到 if
  • Hapijs 在一个连接上同时使用 Http 和 Https

    New to Hapijs http hapijs com 并尝试使用它来创建一个应用程序 该应用程序对所有请求使用 HTTPS 并将 HTTP 重定向到安全连接 问题是应用程序进入 HTTPS 模式没有问题 但如果我将 URL 更改为 H
  • Cassandra 会话与集群 有什么可分享的?

    考虑 Cassandra 的 Session 和 Cluster 类 Java 驱动程序 我想知道有什么区别 在 Hibernate 中 每次都会创建一个会话并共享会话工厂 从许多来源我了解到 它被认为是创建一个会话并在多个线程之间共享它
  • 如何设置 Swashbuckle 与 Microsoft.AspNetCore.Mvc.Versioning

    我们有asp net core webapi 我们添加了Microsoft AspNetCore Mvc Versioning and Swashbuckle拥有招摇的用户界面 我们将控制器指定为 ApiVersion 1 0 Route
  • ftrace 是否允许捕获 Linux 内核的系统调用参数,或者仅捕获函数名称?

    目标是检查任何进程传递给特定系统调用 例如 exec open 等 的参数 来自官方文档 https www kernel org doc Documentation trace ftrace txt 没有描述记录函数参数的功能 主要查看
  • 如何制作饼图聚合数据源?

    Using 适用于 ASP NET MVC 的 Kendo UI 完整版 http www kendoui com 版本 2013 3 1119 2013年11月20日 如果我有这段代码 status chart kendoChart da
  • 如何在不同的目录中执行python脚本?

    Solved对于可能觉得这有帮助的人 请参阅下面我的答案 我有两个脚本 a py 和 b py 在我当前的目录 C Users MyName Desktop MAIN 中 我运行 gt python a py 第一个脚本 a py 在我当前
  • 如何使用 jQuery 和“this”捕获更改的表单元素值

    我有以下代码 每当我的 Web 表单中发生元素更改时 该代码都会起作用 我一直在纠结的是如何捕捉表单字段元素 id name and 改变值当更改事件被触发时 谁能帮我解决这个问题吗 Thanks JavaScript
  • Android Studio 3.0 中的 DexGuard 集成

    我已升级我的 Android 项目以使用最新的 Android Studio 3 0 功能 从那时起 我在每次 Gradle 同步时都会收到以下警告消息 警告 您正在使用的插件之一支持 Java 8 语言 特征 要尝试 Android 插件
  • 在Python中使用os.makedirs创建目录时出现权限问题

    我只是想处理上传的文件并将其写入工作目录中 该目录的名称是系统时间戳 问题是我想以完全权限创建该目录 777 但我不能 使用以下代码创建的目录755权限 def handle uploaded file upfile cTimeStamp
  • 将蒙版图像作为 PNG 文件写入磁盘

    基本上 我从网络服务器下载图像 然后将它们缓存到磁盘上 但在这样做之前 我想屏蔽它们 我正在使用每个人似乎都指出的屏蔽代码 可以在这里找到 http iosdevelopertips com cocoa how to mask an ima
  • Java编程编译jar

    我有一个文本文件中的java源代码 必须在源代码中输入一些自定义的硬编码变量 然后将其转换为 jar 这是可行的 但是当我运行 jar 时 找不到 Main 类 当我用 WinRAR 解压 jar 文件时 我似乎找不到错误 当我通过 cmd
  • 美丽的汤刮 - 登录凭据不起作用

    尝试使用登录凭据抓取页面 payload email gmail com password urls login url https www spotrac com signin url https www spotrac com nba
  • Android 中用于过渡的自定义动画对象?

    我想用一些更奇特的东西来覆盖 Android 中的默认活动转换 我想做的事情不能用通常使用的 XML 集来完成 所以我不能使用overridePendingTransition因为它只接受对基于 XML 的动画资源的整数引用 我想做的是创建
  • XmlDocument Save 使文件保持打开状态

    我有一个简单的 C 函数 可以创建一个基本的 XML 文件并保存 private void CreateXMlFile string Filename string Name string Company XmlDocument doc n
  • 如何使 Django 自定义管理命令参数不再需要?

    我正在尝试在 django 中编写自定义管理命令 如下所示 class Command BaseCommand def add arguments self parser parser add argument delay type int
  • 使用 ActivePerl 时为什么必须指定带有备份扩展的 -i 开关?

    除非我使用备份扩展指定它们 否则我无法就地编辑在 ActivePerl 下运行的 Perl 单行代码 C gt perl i ape splice F 2 0 q inserted text qq F n file1 txt Can t d
  • 是什么让 DVCS 中的合并变得如此简单?

    我读于乔尔谈软件 http www joelonsoftware com items 2010 03 17 html 通过分布式版本控制 分布式部分实际上不是 最有趣的部分 有趣的是 这些 系统根据变化来思考 而不是 就版本而言 and a
  • 带有包含布局的导航抽屉布局

    我认为我的问题实际上很简单 但我不知道如何解决 有一个工作导航抽屉 代码如下

随机推荐

  • 从两个不同的 C DLL 调用两个同名函数

    我需要在同一个可执行文件中访问两个 C DLL 我有两个库的头文件和 LIB 文件 不幸的是 我需要访问的函数子集具有完全相同的名称 到目前为止 我能想到的最佳解决方案是使用 LoadLibrary 加载其中一个 DLL 并使用 GetPr
  • 如何在 WordPress 中动态创建 pdf? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我使用 Contact Form 7 让用户输入数据 然后根据他们的数据输入 我需要在输出整个 pdf 之前向 pdf 添加不同的文本
  • 无延迟调用setTimeout

    在 JavaScript 库中经常看到这样的代码 setTimeout function 0 我想知道为什么要使用这样的包装代码 非常简化 浏览器是单线程的 并且这个单线程 UI 线程 在渲染引擎和 js 引擎之间共享 如果您想做的事情需要
  • 如何更改 Laravel 中请求参数的值

    我需要像这样更改请求参数的值 request gt name My Value 我使用这段代码但不起作用 request gt offsetSet img img Try to requestData request gt all requ
  • 如何在 gRPC python 中定义全局错误处理程序

    我试图捕获任何服务程序中引发的任何异常 这样我就可以确保只传播已知的异常 而不传播意外的异常 例如 ValueError TypeError 等 我希望能够捕获任何引发的错误 并格式化它们或将它们转换为其他错误 以更好地控制公开的信息 我不
  • 使用 Spring RestTemplate 将查询参数添加到每个 REST 请求

    有没有办法向执行的每个 HTTP 请求添加查询参数RestTemplate在春天 Atlassian API 使用查询参数os authType指定身份验证方法 所以我想附加 os authtype basic对每个请求 而不在我的代码中指
  • .NET Core 3.1 CreateHostBuilder无法解析JSON文件

    我在尝试运行 ASP Net Core 3 1 项目时遇到错误 错误位于CreateHostBuilder within Program cs public class Program public static void Main str
  • 有没有办法在成员名称循环中对 N C++ 类成员应用操作(可能通过预处理器)?

    问题 我有一个 C 类 其中有大量 gt 100 成员 其行为几乎相同 同类型 在函数中 每个成员都有与其他成员完全相同的代码 例如从构造函数中的映射进行赋值 其中映射键与成员键相同 这种行为的相同性在许多函数 gt 20 中重复出现 当然
  • Android - 手风琴小部件

    我正在寻找创建一个的最佳方法手风琴式小部件 如本页所示 http labs adobe com technologies spry samples accordion AccordionSample html 有没有办法使用标准 Andro
  • Omniauth“与”STI 和设计

    我想通了 没有结果 我有一个名为 User 的模型以及带有 STI 粉丝和艺术家的模型 如下所示 class User lt ActiveRecord Base devise database authenticatable registe
  • AngularJS - 为什么需要 $apply 来正确解决 $q 承诺?

    我正在尝试在我的角度应用程序中编写一个小型服务 这将使我能够选择全局 Javascript 对象中指定的配置参数 我不想尝试访问全局配置对象 除非文档已准备好 因为我无法保证脚本元素在 HTML 中插入的顺序 但是 我不明白为什么我需要打电
  • css 内联块与浮动

    我正在做一些测试float and inline block我注意到它们之间存在差异 正如你可以看到的这个例子 http codepen io anon pen kwrtD 如果我使用display inline blockdiv 之间有一
  • 如何检测OutofMemoryError的原因?

    我抱怨我的服务器应用程序在高负载时崩溃 这是一个运行在以下位置的网络应用程序Tomcat 5 我看到线程转储 并且发现存在 OutOfMemory 错误 1TISIGINFO 转储事件 systhrow 00040000 详细信息 java
  • java.lang.ClassCastException:DTOObject 无法转换为 DTOObject

    我在 Spring Boot 1 4 0M3 上运行的应用程序中遇到一个奇怪的问题 该应用程序使用 Spring 缓存实现 其中提供程序是 Redis 我收到 classCastException 无法转换相同的对象 我使用 Mongodb
  • C 中用户定义的数组大小

    我正在阅读 C 插图 第一个练习题问 MATMUL 程序将固定大小的矩阵相乘 使程序处理任何指定的尺寸 下面是我迄今为止提出的代码 但是我读到所有属性都需要在主函数之前声明 那么如何获得自定义大小的数组而不在主函数中声明它们呢 define
  • NSPopover - 焦点丢失时隐藏? (在弹出窗口外单击)

    我正在使用doubleClickAction of a NSTableView显示一个NSPopover 像这样的东西 NSInteger selectedRow dataTableView clickedRow NSInteger sel
  • 立即调用函数表达式:括号放在哪里?

    我看过IIFE的写法 function console log do cool stuff 也 function console log do more cool stuff 它们在我使用过的任何环境中似乎都一样工作 尽管有时我被告知一种方
  • Tomcat 6 - 请求的资源...不可用

    我正在尝试开始使用 Java 和 Stripes Framework 进行开发 我的 web xml 文件中有以下内容
  • Dropbox sdk 存储库 maven

    即使这听起来像是一个愚蠢的问题 我也无法找到 dropbox sdk 所在的存储库 所以在我的 pom xml 中我声明了这个依赖项
  • 如何在多个 Pod 上挂载相同的持久卷?

    我有一个三节点 GCE 集群和一个具有三个副本的单 Pod GKE 部署 我像这样创建了 PV 和 PVC Create a persistent volume for web content apiVersion v1 kind Pers