×

投影卷将多个现有的卷源映射到同一个目录。

可以投影以下类型的卷源

  • 密钥

  • 配置映射

  • 向下 API

所有源都必须与 Pod 位于相同的命名空间。

理解投影卷

投影卷可以将这些卷源的任意组合映射到单个目录,允许用户

  • 自动填充单个卷,其中包含来自多个密钥、配置映射和向下 API 信息的密钥,以便我可以合成包含各种信息源的单个目录;

  • 填充单个卷,其中包含来自多个密钥、配置映射和向下 API 信息的密钥,明确指定每个项目的路径,以便我可以完全控制该卷的内容。

当在基于 Linux 的 Pod 的安全上下文中设置RunAsUser权限时,投影文件将设置正确的权限,包括容器用户所有权。但是,当在 Windows Pod 中设置 Windows 等效权限RunAsUsername时,kubelet 无法正确设置投影卷中文件的拥有权。

因此,在 OpenShift Container Platform 中运行的 Windows 投影卷不会遵守在 Windows Pod 的安全上下文中设置的RunAsUsername权限。

以下一般场景显示了如何使用投影卷。

配置映射、密钥、向下 API。

投影卷允许您部署包含配置数据的容器,这些配置数据包括密码。使用这些资源的应用程序可以将 Red Hat OpenStack Platform (RHOSP) 部署到 Kubernetes。配置数据的组装方式可能因服务将用于生产还是测试而异。如果 Pod 使用生产或测试进行标记,则可以使用向下 API 选择器metadata.labels来生成正确的 RHOSP 配置。

配置映射 + 密钥。

投影卷允许您部署涉及配置数据和密码的容器。例如,您可以使用配置映射执行一些使用保管库密码文件解密的敏感加密任务。

配置映射 + 向下 API。

投影卷允许您生成包含 Pod 名称(通过metadata.name选择器可用)的配置。然后,此应用程序可以将 Pod 名称与请求一起传递,以便轻松确定源,而无需使用 IP 跟踪。

密钥 + 向下 API。

投影卷允许您使用密钥作为公钥来加密 Pod 的命名空间(通过metadata.namespace选择器可用)。此示例允许 Operator 使用应用程序安全地传递命名空间信息,而无需使用加密传输。

示例 Pod 规范

以下是创建投影卷的Pod规范示例。

包含密钥、向下 API 和配置映射的 Pod
apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: container-test
    image: busybox
    volumeMounts: (1)
    - name: all-in-one
      mountPath: "/projected-volume"(2)
      readOnly: true (3)
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
  volumes: (4)
  - name: all-in-one (5)
    projected:
      defaultMode: 0400 (6)
      sources:
      - secret:
          name: mysecret (7)
          items:
            - key: username
              path: my-group/my-username (8)
      - downwardAPI: (9)
          items:
            - path: "labels"
              fieldRef:
                fieldPath: metadata.labels
            - path: "cpu_limit"
              resourceFieldRef:
                containerName: container-test
                resource: limits.cpu
      - configMap: (10)
          name: myconfigmap
          items:
            - key: config
              path: my-group/my-config
              mode: 0777 (11)
1 为需要密钥的每个容器添加volumeMounts部分。
2 指定密钥将显示在其中的未使用目录的路径。
3 readOnly设置为true
4 添加volumes块以列出每个投影卷源。
5 为卷指定任何名称。
6 设置文件的执行权限。
7 添加密钥。输入密钥对象的名称。必须列出您要使用的每个密钥。
8 指定mountPath下密钥文件的路径。此处,密钥文件位于/projected-volume/my-group/my-username
9 添加向下 API 源。
10 添加配置映射源。
11 设置特定投影的模式

如果 Pod 中有多个容器,则每个容器都需要一个volumeMounts部分,但只需要一个volumes部分。

具有多个密钥且设置了非默认权限模式的 Pod
apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
  volumes:
  - name: all-in-one
    projected:
      defaultMode: 0755
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/my-username
      - secret:
          name: mysecret2
          items:
            - key: password
              path: my-group/my-password
              mode: 511

defaultMode只能在投影级别指定,而不能为每个卷源指定。但是,如上所示,您可以为每个单独的投影显式设置mode

路径考虑

配置路径相同时的密钥冲突

如果将任何密钥配置为具有相同的路径,则 Pod 规范将不被接受为有效规范。在以下示例中,mysecretmyconfigmap的指定路径相同

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/data
      - configMap:
          name: myconfigmap
          items:
            - key: config
              path: my-group/data

考虑以下与卷文件路径相关的状况。

未配置路径时的密钥冲突

唯一可以发生的运行时验证是在创建 Pod 时所有路径都已知的情况下,类似于上述场景。否则,当发生冲突时,最近指定的资源将覆盖其之前的任何内容(这对于 Pod 创建后更新的资源也适用)。

一个路径显式而另一个路径自动投影时的冲突

如果由于用户指定的路径与自动投影的数据匹配而导致冲突,则与以前一样,后面的资源将覆盖其之前的任何内容

为 Pod 配置投影卷

创建投影卷时,请考虑“理解投影卷”中描述的卷文件路径情况。

以下示例显示如何使用投影卷来挂载现有的密钥卷源。这些步骤可用于从本地文件创建用户名和密码密钥。然后,您可以创建一个运行一个容器的 Pod,使用投影卷将密钥挂载到同一个共享目录中。

用户名和密码值可以是任何有效的以base64编码的字符串。

以下示例显示 base64 中的admin

$ echo -n "admin" | base64
示例输出
YWRtaW4=

以下示例显示 base64 中的密码1f2d1e2e67df

$ echo -n "1f2d1e2e67df" | base64
示例输出
MWYyZDFlMmU2N2Rm
步骤

要使用投影卷来挂载现有的密钥卷源。

  1. 创建密钥

    1. 创建一个类似于以下内容的 YAML 文件,根据需要替换密码和用户信息

      apiVersion: v1
      kind: Secret
      metadata:
        name: mysecret
      type: Opaque
      data:
        pass: MWYyZDFlMmU2N2Rm
        user: YWRtaW4=
    2. 使用以下命令创建密钥

      $ oc create -f <secrets-filename>

      例如

      $ oc create -f secret.yaml
      示例输出
      secret "mysecret" created
    3. 您可以使用以下命令检查密钥是否已创建

      $ oc get secret <secret-name>

      例如

      $ oc get secret mysecret
      示例输出
      NAME       TYPE      DATA      AGE
      mysecret   Opaque    2         17h
      $ oc get secret <secret-name> -o yaml

      例如

      $ oc get secret mysecret -o yaml
      apiVersion: v1
      data:
        pass: MWYyZDFlMmU2N2Rm
        user: YWRtaW4=
      kind: Secret
      metadata:
        creationTimestamp: 2017-05-30T20:21:38Z
        name: mysecret
        namespace: default
        resourceVersion: "2107"
        selfLink: /api/v1/namespaces/default/secrets/mysecret
        uid: 959e0424-4575-11e7-9f97-fa163e4bd54c
      type: Opaque
  2. 创建具有投影卷的 Pod。

    1. 创建一个类似于以下内容的 YAML 文件,包括volumes部分

      kind: Pod
      metadata:
        name: test-projected-volume
      spec:
        securityContext:
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        containers:
        - name: test-projected-volume
          image: busybox
          args:
          - sleep
          - "86400"
          volumeMounts:
          - name: all-in-one
            mountPath: "/projected-volume"
            readOnly: true
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: [ALL]
        volumes:
        - name: all-in-one
          projected:
            sources:
            - secret:
                name: mysecret (1)
      1 您创建的密钥的名称。
    2. 从配置文件创建 Pod

      $ oc create -f <your_yaml_file>.yaml

      例如

      $ oc create -f secret-pod.yaml
      示例输出
      pod "test-projected-volume" created
  3. 验证 Pod 容器是否正在运行,然后监视 Pod 的更改

    $ oc get pod <name>

    例如

    $ oc get pod test-projected-volume

    输出应类似于以下内容

    示例输出
    NAME                    READY     STATUS    RESTARTS   AGE
    test-projected-volume   1/1       Running   0          14s
  4. 在另一个终端中,使用oc exec命令打开正在运行容器的shell。

    $ oc exec -it <pod> <command>

    例如

    $ oc exec -it test-projected-volume -- /bin/sh
  5. 在您的shell中,验证projected-volumes目录是否包含您的投影源。

    / # ls
    示例输出
    bin               home              root              tmp
    dev               proc              run               usr
    etc               projected-volume  sys               var