# downward API卷

以downward API卷的形式将元数据以文件的形式挂载至Pod中的容器中，与其他两种方式相比，其缺点主要体现在：仅可以暴露本Pod的元数据，可使用的元数据有限（比环境变量的方式多了标签和注解）。

相对于环境变量的方式，多了两种元数据，是因为Pod的**标签**和**注解**是支持更新的，因此若以环境变量的方式导入，是无法实时更新的，而使用卷的方式就可以，其[**更新原理与ConfigMap的同步更新一样**](https://yangsijie151104.gitbook.io/k8s-note/configmap-he-secret/configmap/cong-configmap-zhong-du-qu-pei-zhi/configmap-du-qu-wei-wen-jian)；

Pod在生成后，会有自己的定义（配置文件），这种方式就是通过从定义（配置文件）和状态中取得相关数据，并将其存放至downward API卷中，进而将该卷挂载至容器中，从而被容器中的应用读取和使用。

## 可用元数据

该方式下，可暴露的元数据如下：

* 本Pod的名称（`metadata.name`）；
* 本Pod的IP地址；（`status.podIP`）
* 本Pod所在的命名空间（`metadata.namespace`）；
* 本Pod运行的Node的名称（`spec.nodeName`）；
* 本Pod运行所归属的ServiceAccount名称（`spec.serviceAccountName`）；
* 本Pod的标签（`metadata.labels`）；
* 本Pod的注解（`metadata.annotations`）；
* 本Pod中**每个容器**的CPU和内存的请求量（`spec.containers.resources.requests.cpu`）；
* 本Pod中**每个容器**可使用的CPU和内存的上限（`spec.containers.resources.limits.cpu`）；

{% hint style="info" %}
**前七种（非资源相关）：**&#x5728;`pod.spec.volumes.items.fieldRef`中指定（从字段名可以看出，引用的是配置文件中的相关字段）；

**后两种（资源相关）：**&#x5728;`pod.spec.volumes.items.resourceFieldRef`中指定，其中引用的是`spec.containers.resources`中资源请求量与使用上限等相关字段；
{% endhint %}

{% hint style="warning" %}
注意，由于Pod中不同的容器具有不同的资源量，因此在配置文件中可以通过指定容器名的方式（`spec.volumes.items.resourceFieldRef.containerName`），将**本容器或其他容器**的资源请求量和使用上限元数据传入本容器中。
{% endhint %}

## 使用案例

由于是将元数据以downward API卷的方式传递至容器中，因此需要两步：

1. 定义卷：在`spec.volumes.downwardAPI.items`中加载各元数据；
2. 挂载卷：在Pod的`spec.containers.volumeMounts`中指定挂载点和挂载的卷名；

在上面介绍可用元数据时，已经提到，针对**非资源相关**的元数据是在`pod.spec.volumes.items.fieldRef`中指定的，而针对**资源相关**的元数据则是在`pod.spec.volumes.items.resourceFieldRef`中指定的。

并且在上面也介绍了各元数据所对应的Pod的配置文件中的字段。

这里展示一个案例，创建一个仅包含一个容器的Pod，并且定义downward API卷，并且将该方式支持的所有元数据都传入容器中：

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: downward
  labels:    # 定义Pod的标签
    foo: bar
  annotations:    # 定义Pod的注解
    key1: value1
    key2: |
      multi
      line
      value
spec:
  containers:
  - name: main
    image: busybox
    command: ["sleep", "9999999"]
    resources:    # 容器资源相关配置
      requests:    # 资源请求量
        cpu: 1m
        memory: 100Ki
      limits:    # 资源使用上限
        cpu: 2m
        memory: 100Mi
    volumeMounts: # 挂载点
    - name: downward    # 卷名
      mountPath: /etc/downward
  volumes:
  - name: downward
    downwardAPI:  # 定义downward API卷
      items:
      - path: "podName"    # 相对路径，可以理解为创建的文件名为podName
        fieldRef:    # 非资源相关元数据，使用fieldRef
          fieldPath: metadata.name    # 元数据：本Pod的名称；Pod配置文件中的字段
      - path: "podIP"
        fieldRef:
          fieldPath: status.podIP    # 元数据：本Pod的IP地址
      - path: "podNamespace"
        fieldRef:
          fieldPath: metadata.namespace    # 元数据：本Pod所在命名空间名称
      - path: "nodeName"
        fieldRef:
          fieldPath: spec.nodeName    # 元数据：本Pod所在Node名称
      - path: "serviceAccountName"
        fieldRef:
          fieldPath: spec.serviceAccountName    # 元数据：本Pod所属的ServiceAccount名称
      - path: "labels"
        fieldRef:
          fieldPath: metadata.labels    # 元数据：本Pod的标签
      - path: "annotations"
        fieldRef:
          fieldPath: metadata.annotations    # 元数据：本Pod的注解
      - path: "containerCpuRequestMilliCores"
        resourceFieldRef:    # 资源相关元数据，使用resourceFieldRef
          containerName: main    # 由于volumes与容器同级别，因此这里需指定容器名
          resource: requests.cpu    # Pod配置文件中pod.spec.containers.resources中的字段；元数据：本Pod中名为main的容器的CPU请求量
          divisor: 1m    # 基数，例如本容器requests.cpu=1m，因此这里显示为1（1m/1m=1）
      - path: "containerMemoryRequestBytes"
        resourceFieldRef:
          containerName: main
          resource: requests.memory    # 元数据：本Pod中名为main的容器的内存请求量
          divisor: 1    # 基数，不写单位则为Bytes，因此这里显示为102400（1Ki/1Bytes=102400Bytes）
      - path: "containerCpuLimitMilliCores"
        resourceFieldRef:
          containerName: main
          resource: limits.cpu    # 元数据：本Pod中名为main的容器的可使用CPU上限
          divisor: 1m
      - path: "containerMemoryLimitBytes"
        resourceFieldRef:
          containerName: main
          resource: limits.memory    # 元数据：本Pod中名为main的容器的可使用内存上限
          divisor: 1
```
