在容器中获取配置及上下文信息 -- Projected Volumes

2022-04-12 21:49:15   最后更新: 2022-04-12 21:49:15   访问数量:99




 

上一篇文章中,我们详细介绍了 Kubernetes 中的 Pod:

 

详解 Kubernetes 中的 Pod

 

在实际的线上场景中,我们并不能在配置 Pod 的 yaml 里描述所有需要的信息,因为总有一些信息或因为其保密性,或因为其动态变化性,是不能够放在配置文件里的,那么,这类信息要怎么加入到我们的 Pod 配置体系中呢?

 

这就需要一种特殊的 Volume -- 投射数据卷,Projected Volume。本文我们就来详细介绍投射数据卷的用法。

 

 

 

 

之所以被称作“投射数据卷”,是因为这些数据是提前定义好,或者动态拉取,然后投射进 Kubernetes 的容器中的,它们有三种:

 

  1. Secret
  2. ConfigMap
  3. DownwardAPI

 

需要注意的是:

 

  1. Pod 只能使用同一个命名空间中的 Projected Volume;
  2. Pod 要使用的 Projected Volume 必须在 Pod 启动前就已经存在;
  3. 虽然 Projected Volume 基本上都有挂载为 volume 和作为环境变量两种使用方式,但作为环境变量的方式不会随着 volume 数据本身的更新而更新,所以对于需要感知 Projected Volume 数据变化的场景,还是推荐挂载为 volume 来进行使用。

 

下面,我们来一一介绍。

 

 

Secret Volume 的作用是帮你把想要访问的加密数据存放到 etcd 中,这样,Pod 中的容器就可以通过挂载相应 Volume 的方式访问到这些加密信息了。

 

3.1 Secret Volume 的创建

 

有两种方式可以创建 Secret Volume:

 

  1. 通过命令的方式;
  2. 通过 yaml 配置文件的方式。

 

3.1.1 通过命令创建 Secret Volume

 

首先,我们需要两个文件,分别用来存储用户名和密码:

 

$ echo "admin" > username.txt

$ echo "UjtLdUtzWOnfcIh8" > password.txt

 

然后,执行 kubectl create 命令就可以完成 Secret Volume 的创建:

 

\$ kubectl create secret generic user --from-file=./username.txt

\$ kubectl create secret generic pass --from-file=./password.txt

 

3.1.2 通过配置文件创建 Secret Volume

 

编写配置文件:

 

apiVersion: v1 kind: Secret metadata: name: secret-volume type: Opaque data: user: YWRtaW4= pass: VWp0TGRVdHpXT25mY0loOAo=

 

 

  • 需要注意的是,在配置文件中,所有数据中的值都需要进行 base64 转码处理。

 

同样,通过 kubectl create 命令,就可以完成 Secret Volume 的创建了:

 

$ kubectl create -f secret-volume.yaml

 

3.1.3 Secret Volume 的查询

 

通过 kubectl get 命令可以进行 secret 的查询:

 

$ kubectl get secretes

 

事实上,这样查询出来的明文结果是具有很大的风险的,在真实的线上环境中,我们还需要开启 Secret 加密插件,进一步保障数据的保密性。

 

3.2 Secret Volume 的实际使用

 

Secret Volume 虽然是一种用来保存加密信息的特殊的 Volume,但他的使用和其他 Volume 并没有明显区别。

 

例如,下面是一个 Pod 的定义:

 

apiVersion: v1 kind: Pod metadata: name: test-projected-volume spec: containers: - name: test-secret-volume image: busybox args: - sleep - "86400" volumeMounts: - name: mysql-cred mountPath: "/projected-volume" readOnly: true volumes: - name: mysql-cred projected: sources: - secret: name: user - secret: name: pass

 

 

我们通过 exec 命令进入到这个容器,通过查看挂载的目录就可以看到相应的内容了:

 

\$ kubectl exec -it test-projected-volume -- /bin/sh

$ cat /projected-volume/user

root

 

 

ConfigMap 与 Secret 非常类似,也是通过用键值对的方式来保存数据的 Volume,区别在于 ConfigMap 并非用来保存加密数据的,他是用来保存配置信息的。

 

4.1 ConfigMap 的配置

 

与 Secret 一样,ConfigMap 也有两种配置方法:

 

  1. 通过 properties 文件配置;
  2. 通过 yaml 文件配置。

 

4.1.1 通过 properties 文件配置

 

首先,我们先定义 properties 文件:

 

color.good=purple color.bad=yellow allow.textmod=true

 

 

执行 kubectl create 命令即可完成 ConfigMap 的创建:

 

\$ kubectl create configmap ui-config --from-file=ui.properties

 

4.1.2 通过 yaml 文件配置

 

编写配置文件:

 

apiVersion: v1 kind: ConfigMap metadata: name: ui-config data: color.good: purple color.bad: yellow

 

 

执行 kubectl create 命令即可完成 ConfigMap 的创建:

 

$ kubectl create -f config.yaml

 

4.1.3 查询 ConfigMap

 

通过 kubectl describe 命令就可以实现 ConfigMap 的查询了:

 

\$ kubectl describe configmap ui-config

 

4.2 使用 ConfigMap

 

接下来我们来介绍两种可以在 Pod 中使用 ConfigMap 的方式:

 

  1. 配置到容器的环境变量;
  2. 使用 Volume 将 ConfigMap 作为文件或目录挂载。

 

除此以外,还可以编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap,这种方式后续再进行介绍,敬请期待。

 

  • 在使用 envFrom 时,会自动忽略无效的键。

 

4.2.1 将 ConfigMap 配置到容器的环境变量

 

  • 配置环境变量

 

# test-pod-configmap.yaml apiVersion: v1 kind: Pod metadata: name: test-pod-configmap spec: containers: - name: test-busybox image: busybox imagePullPolicy: IfNotPresent args: - sleep - "86400" env: - name: KEY1 valueFrom: configMapKeyRef: name: ui-config key: color.good - name: KEY2 valueFrom: configMapKeyRef: name: ui-config key: color.bad

 

 

 

 

  • 配置容器启动参数

 

通常,我们会想要用 ConfigMap 来设置容器启动时的命令行参数,尽管这是 Kubernetes 不支持的,但它支持通过环境变量来配置启动参数,我们就可以如法炮制了:

 

# test-pod-configmap-cmd apiVersion: v1 kind: Pod metadata: name: test-pod-configmap-cmd spec: containers: - name: test-busybox image: busybox imagePullPolicy: IfNotPresent command: [ "/bin/sh","-c","echo $(KEY1) $(KEY2)"] env: - name: KEY1 valueFrom: configMapKeyRef: name: ui-config key: color.good - name: KEY2 valueFrom: configMapKeyRef: name: ui-config key: color.bad restartPolicy: Never

 

 

4.2.2 将 ConfigMap 挂载到容器中

 

同样,我们也可以将 ConfigMap 作为普通的 volume 挂载到容器中:

 

# test-pod-projected-configmap-volume.yaml apiVersion: v1 kind: Pod metadata: name: test-pod-projected-configmap-volume spec: containers: - name: test-pod-busybox image: busybox imagePullPolicy: IfNotPresent args: - sleep - "86400" volumeMounts: - name: config-volume mountPath: "/projected-volume" readOnly: true volumes: - name: config-volume projected: sources: - configMap: name: ui-config

 

 

 

在我们配置一个 Pod 时,我们把许许多多的信息编写在了配置文件上,但有时候,我们需要在容器中获取当前 Pod 的这些配置信息,我们又该怎么做呢?

 

Kubernetes 提供了 Downward API,来让我们能够实现这一功能。

 

5.1 Downward API 的使用

 

例如:

 

apiVersion: v1 kind: Pod metadata: name: test-downwardapi-volume labels: zone: us-est-coast cluster: test-cluster1 rack: rack-22 spec: containers: - name: client-container image: k8s.gcr.io/busybox command: ["sh", "-c"] args: - while true; do if [[ -e /etc/podinfo/labels ]]; then echo -en '\n\n'; cat /etc/podinfo/labels; fi; sleep 5; done; volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: false volumes: - name: podinfo projected: sources: - downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels

 

 

在这个 pod 的定义中,我们定义了一个 downwardAPI 类型的 projected volume 并且挂载到了容器中,而这个容器的功能,就是循环打印挂载的 projected volume 中的文件内容。

 

于是我们看到打印出了我们为这个 pod 定义的 labels:

 

$ kubectl logs test-downwardapi-volume

cluster="test-cluster1"

rack="rack-22"

zone="us-est-coast"

 

5.2 支持的 Downward API 列表

 

目前,Downward API 支持的字段已经非常丰富了,他分为两个部分:

 

1. 使用 fieldRef 声明和使用

 

  1. spec.nodeName - 宿主机名字
  2. status.hostIP - 宿主机IP
  3. metadata.name - Pod的名字
  4. metadata.namespace - Pod的Namespace
  5. status.podIP - Pod的IP
  6. spec.serviceAccountName - Pod的Service Account的名字
  7. metadata.uid - Pod的UID
  8. metadata.labels['<KEY>'] - 指定<KEY>的Label值
  9. metadata.annotations['<KEY>'] - 指定<KEY>的Annotation值
  10. metadata.labels - Pod的所有Label
  11. metadata.annotations - Pod的所有Annotation
  12. 使用 resourceFieldRef 声明和使用.

 

2. 7. Projected Volume

 

 

上一篇文章中,我们详细介绍了 Kubernetes 中的 Pod:

 

详解 Kubernetes 中的 Pod

 

在实际的线上场景中,我们并不能在配置 Pod 的 yaml 里描述所有需要的信息,因为总有一些信息或因为其保密性,或因为其动态变化性,是不能够放在配置文件里的,那么,这类信息要怎么加入到我们的 Pod 配置体系中呢?

 

这就需要一种特殊的 Volume -- 投射数据卷,Projected Volume。本文我们就来详细介绍投射数据卷的用法。

 

 

之所以被称作“投射数据卷”,是因为这些数据是提前定义好,或者动态拉取,然后投射进 Kubernetes 的容器中的,它们有四种:

 

  1. Secret
  2. ConfigMap
  3. DownwardAPI
  4. ServiceAccountToken

 

需要注意的是,Pod 只能使用同一个命名空间中的 Projected Volume。

 

下面,我们来一一介绍。

 

 

Secret Volume 的作用是帮你把想要访问的加密数据存放到 etcd 中,这样,Pod 中的容器就可以通过挂载相应 Volume 的方式访问到这些加密信息了。

 

3.1 Secret Volume 的创建

 

有两种方式可以创建 Secret Volume:

 

  1. 通过命令的方式;
  2. 通过 yaml 配置文件的方式。

 

3.1.1 通过命令创建 Secret Volume

 

首先,我们需要两个文件,分别用来存储用户名和密码:

 

$ echo "admin" > username.txt

$ echo "UjtLdUtzWOnfcIh8" > password.txt

 

然后,执行 kubectl create 命令就可以完成 Secret Volume 的创建:

 

\$ kubectl create secret generic user --from-file=./username.txt

\$ kubectl create secret generic pass --from-file=./password.txt

 

3.1.2 通过配置文件创建 Secret Volume

 

编写配置文件:

 

apiVersion: v1 kind: Secret metadata: name: secret-volume type: Opaque data: user: YWRtaW4= pass: VWp0TGRVdHpXT25mY0loOAo=

 

 

  • 需要注意的是,在配置文件中,所有数据中的值都需要进行 base64 转码处理。

 

同样,通过 kubectl create 命令,就可以完成 Secret Volume 的创建了:

 

$ kubectl create -f secret-volume.yaml

 

3.1.3 Secret Volume 的查询

 

通过 kubectl get 命令可以进行 secret 的查询:

 

$ kubectl get secretes

 

事实上,这样查询出来的明文结果是具有很大的风险的,在真实的线上环境中,我们还需要开启 Secret 加密插件,进一步保障数据的保密性。

 

3.2 Secret Volume 的实际使用

 

Secret Volume 虽然是一种用来保存加密信息的特殊的 Volume,但他的使用和其他 Volume 并没有明显区别。

 

例如,下面是一个 Pod 的定义:

 

apiVersion: v1 kind: Pod metadata: name: test-projected-volume spec: containers: - name: test-secret-volume image: busybox args: - sleep - "86400" volumeMounts: - name: mysql-cred mountPath: "/projected-volume" readOnly: true volumes: - name: mysql-cred projected: sources: - secret: name: user - secret: name: pass

 

 

我们通过 exec 命令进入到这个容器,通过查看挂载的目录就可以看到相应的内容了:

 

\$ kubectl exec -it test-projected-volume -- /bin/sh

$ cat /projected-volume/user

root

 

 

ConfigMap 与 Secret 非常类似,也是通过用键值对的方式来保存数据的 Volume,区别在于 ConfigMap 并非用来保存加密数据的,他是用来保存配置信息的。

 

4.1 ConfigMap 的配置

 

与 Secret 一样,ConfigMap 也有两种配置方法:

 

  1. 通过 properties 文件配置;
  2. 通过 yaml 文件配置。

 

4.1.1 通过 properties 文件配置

 

首先,我们先定义 properties 文件:

 

color.good=purple color.bad=yellow allow.textmod=true

 

 

执行 kubectl create 命令即可完成 ConfigMap 的创建:

 

\$ kubectl create configmap ui-config --from-file=ui.properties

 

4.1.2 通过 yaml 文件配置

 

编写配置文件:

 

apiVersion: v1 kind: ConfigMap metadata: name: ui-config data: color.good: purple color.bad: yellow

 

 

执行 kubectl create 命令即可完成 ConfigMap 的创建:

 

$ kubectl create -f config.yaml

 

4.1.3 查询 ConfigMap

 

通过 kubectl describe 命令就可以实现 ConfigMap 的查询了:

 

\$ kubectl describe configmap ui-config

 

4.2 使用 ConfigMap

 

接下来我们来介绍两种可以在 Pod 中使用 ConfigMap 的方式:

 

  1. 配置到容器的环境变量;
  2. 使用 Volume 将 ConfigMap 作为文件或目录挂载。

 

除此以外,还可以编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap,这种方式后续再进行介绍,敬请期待。

 

  • 需要注意的是,ConfigMap 必须在Pod使用它之前创建。
  • 在使用 envFrom 时,会自动忽略无效的键。

 

4.2.1 将 ConfigMap 配置到容器的环境变量

 

  • 配置环境变量

 

# test-pod-configmap.yaml apiVersion: v1 kind: Pod metadata: name: test-pod-configmap spec: containers: - name: test-busybox image: busybox imagePullPolicy: IfNotPresent args: - sleep - "86400" env: - name: KEY1 valueFrom: configMapKeyRef: name: ui-config key: color.good - name: KEY2 valueFrom: configMapKeyRef: name: ui-config key: color.bad

 

 

 

 

  • 配置容器启动参数

 

通常,我们会想要用 ConfigMap 来设置容器启动时的命令行参数,尽管这是 Kubernetes 不支持的,但它支持通过环境变量来配置启动参数,我们就可以如法炮制了:

 

# test-pod-configmap-cmd apiVersion: v1 kind: Pod metadata: name: test-pod-configmap-cmd spec: containers: - name: test-busybox image: busybox imagePullPolicy: IfNotPresent command: [ "/bin/sh","-c","echo $(KEY1) $(KEY2)"] env: - name: KEY1 valueFrom: configMapKeyRef: name: ui-config key: color.good - name: KEY2 valueFrom: configMapKeyRef: name: ui-config key: color.bad restartPolicy: Never

 

 

4.2.2 将 ConfigMap 挂载到容器中

 

同样,我们也可以将 ConfigMap 作为普通的 volume 挂载到容器中:

 

# test-pod-projected-configmap-volume.yaml apiVersion: v1 kind: Pod metadata: name: test-pod-projected-configmap-volume spec: containers: - name: test-pod-busybox image: busybox imagePullPolicy: IfNotPresent args: - sleep - "86400" volumeMounts: - name: config-volume mountPath: "/projected-volume" readOnly: true volumes: - name: config-volume projected: sources: - configMap: name: ui-config

 

 

 

在我们配置一个 Pod 时,我们把许许多多的信息编写在了配置文件上,但有时候,我们需要在容器中获取当前 Pod 的这些配置信息,我们又该怎么做呢?

 

Kubernetes 提供了 Downward API,来让我们能够实现这一功能。

 

5.1 Downward API 的使用

 

例如:

 

apiVersion: v1 kind: Pod metadata: name: test-downwardapi-volume labels: zone: us-est-coast cluster: test-cluster1 rack: rack-22 spec: containers: - name: client-container image: k8s.gcr.io/busybox command: ["sh", "-c"] args: - while true; do if [[ -e /etc/podinfo/labels ]]; then echo -en '\n\n'; cat /etc/podinfo/labels; fi; sleep 5; done; volumeMounts: - name: podinfo mountPath: /etc/podinfo readOnly: false volumes: - name: podinfo projected: sources: - downwardAPI: items: - path: "labels" fieldRef: fieldPath: metadata.labels

 

 

在这个 pod 的定义中,我们定义了一个 downwardAPI 类型的 projected volume 并且挂载到了容器中,而这个容器的功能,就是循环打印挂载的 projected volume 中的文件内容。

 

于是我们看到打印出了我们为这个 pod 定义的 labels:

 

$ kubectl logs test-downwardapi-volume

cluster="test-cluster1"

rack="rack-22"

zone="us-est-coast"

 

5.2 支持的 Downward API 列表

 

目前,Downward API 支持的字段已经非常丰富了,他分为两个部分:

 

 

 

1. 使用 fieldRef 声明和使用

 

  1. spec.nodeName - 宿主机名字
  2. status.hostIP - 宿主机 IP
  3. metadata.name - Pod 的名字
  4. metadata.namespace - Pod 的 Namespace
  5. status.podIP - Pod 的 IP
  6. spec.serviceAccountName - Pod 的 Service Account的名字
  7. metadata.uid - Pod 的 UID
  8. metadata.labels['<KEY>'] - 指定 <KEY> 的Label值
  9. metadata.annotations['<KEY>'] - 指定 <KEY> 的Annotation值
  10. metadata.labels - Pod 的所有 Label
  11. metadata.annotations - Pod 的所有 Annotation

 

 

 

2. 使用 resourceFieldRef 声明和使用

 

  1. limits.cpu -- 容器的 CPU 限额
  2. requests.cpu -- 容器的 CPU 需求
  3. limits.memory -- 容器的内存限额
  4. requests.memory -- 容器的内存需求
  5. limits.ephemeral-storage -- 容器的存储空间限额
  6. requests.ephemeral-storage -- 容器的存储空间需求

 

例如:

 

apiVersion: v1 kind: Pod metadata: name: dapi-envars-resourcefieldref spec: containers: - name: test-container image: k8s.gcr.io/busybox:1.24 command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv MY_CPU_REQUEST MY_CPU_LIMIT; printenv MY_MEM_REQUEST MY_MEM_LIMIT; sleep 10; done; resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" env: - name: MY_CPU_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.cpu - name: MY_CPU_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.cpu - name: MY_MEM_REQUEST valueFrom: resourceFieldRef: containerName: test-container resource: requests.memory - name: MY_MEM_LIMIT valueFrom: resourceFieldRef: containerName: test-container resource: limits.memory restartPolicy: Never

 

 

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 






docker      虚拟化      kubernetes      volume     


京ICP备2021035038号