我们知道,每个pod在被成功创建出来之后,都会被系统分配唯一的名字,IP地址,并且处于某个namespace中。

我们如何在pod的容器内获取pod的的这些重要信息呢?

答案就是Downward API

Downward API 可以通过两种方式将pod信息注入容器内容

1:环境变量:用于单个变量,可以将pod信息和container 信息注入容器内部

2: volume挂载:将数组类信息生成为文件并挂载到容器内部。

环境变量方式:将pod信息注入环境变量

下面的例子通过Downward API将pod的ip,名称,和所在namespace注入容器的环境变量中,容器应用使用env命令将全部环境变量打印到标准输出中

[root@bogon ~]# kubectl create -f dapi-test-pod.yaml 
pod/dapi-test-pod created

 dapi-test-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: busybox
      command: ["/bin/sh","-c","env"]
      env:
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
  restartPolicy: Never

 查看dapi-test-pod的日志

[root@bogon ~]# kubectl logs pod/dapi-test-pod
KUBERNETES_PORT=tcp://169.169.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=dapi-test-pod
SHLVL=1
HOME=/root
MY_POD_NAMESPACE=default
MY_POD_IP=172.17.0.2
KUBERNETES_PORT_443_TCP_ADDR=169.169.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://169.169.0.1:443
KUBERNETES_SERVICE_HOST=169.169.0.1
PWD=/
MY_POD_NAME=dapi-test-pod

 从日志中我们可以看到pod的ip name namespace 等信息被正确保存到了pod的环境变量中。

环境变量方式:将容器资源信息注入为环境变量

下面的例子将通过Downward API将Container的资源请求和限制信息注入容器的环境变量中,容器应用使用printenv命令将设置的资源请求和资源限制环境变量打印到标准输出中

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod-container-vars
spec:
  containers:
    - name: test-container
      image: busybox
      imagePullPolicy: Never
      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 3600;
           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

requests.cpu:容器的cpu请求值

limits.cpu: 容器的cpu限制值

requests.memory:容器的内存请求值

limits.memory:容器的内存限制值

运行kubectl create 命令来创建pod

[root@bogon ~]# kubectl create -f dapi-test-pod-container-vars.yaml 
pod/dapi-test-pod-container-vars created
[root@bogon ~]# kubectl get pods
NAME                           READY   STATUS      RESTARTS   AGE
dapi-test-pod                  0/1     Completed   0          98m
dapi-test-pod-container-vars   1/1     Running     0          2m53s

 查看日志:

[root@bogon ~]# kubectl logs dapi-test-pod-container-vars

1
1
33554432
67108864

 从日志中我们可以看到container的requests.cpu limits.cpu requests.memory limits.memory 等信息都被正确保存到了pod的环境变量中

volume挂载方式:

下面的例子通过Downward API 将pod的Lable Annotation 列表通过Volume挂载为容器中的一个文件,

容器应用使用echo 命令将文件内容打印到标准输出中:

vim dapi-test-pod-volume.yaml

apiVersion: v1
kind: Pod
metadata: 
  name: dapi-test-pod-volume
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations: 
    build: two
    builder: john-doe
spec:
  containers:
    - name: test-container
      image: busybox
      imagePullPolicy: Never
      command: ["sh","-c"]
      args:
        - while true; do
            if [[ -e /etc/podinfo/labels ]]; then
              echo -en '\n\n'; cat /etc/podinfo/labels;
            fi;
            if [[ -e /etc/podinfo/annotations ]]; then
              echo -en '\n\n'; cat /etc/podinfo/annotations;
            fi;
             sleep 3600;
          done
      volumeMounts:
         - name: podinfo
           mountPath: /etc/podinfo
           readOnly: false
  volumes: 
    - name: podinfo
      downwardAPI:
        items:
        - path: "lables"
          fieldRef: 
            fieldPath: metadata.labels
        - path: "annotations"
          fieldRef:
            fieldPath: metadata.annotations

通过items字段的设置,系统会根据path的名称生成文件:
/etc/podinfo/lables

/etc/podinfo/annotations

我们将元数据 labels 和 annotaions 以文件的形式挂载到了/etc/podinfo目录下,创建上面的 POD :

运行kubectl create 命令创建pod:

[root@bogon ~]# kubectl create -f dapi-test-pod-volume.yaml 
pod/dapi-test-pod-volume created
[root@bogon ~]# kubectl get pods
NAME                           READY   STATUS      RESTARTS   AGE
dapi-test-pod                  0/1     Completed   0          3h34m
dapi-test-pod-container-vars   1/1     Running     0          118m
dapi-test-pod-volume           1/1     Running     0          4s

查看日志:

我们通过打印出来的日志可以看到 POD 的 Labels 和 Annotations 信息都被挂载到 /etc/podinfo目录下面的 lables 和 annotations

[root@bogon ~]# kubectl logs pods/dapi-test-pod-volume


build="two"
builder="john-doe"
kubernetes.io/config.seen="2020-06-27T15:57:50.532237846+08:00"

Downward API 价值:

在实际应用中,如果你的应用有获取 POD 的基本信息的需求,一般我们就可以利用Downward API来获取基本信息,然后编写一个启动脚本或者利用initContainer将 POD 的信息注入到我们容器中去,然后在我们自己的应用中就可以正常的处理相关逻辑了。