Kubernetes(k8s)通過環境變量將 Pod 信息呈現給容器


Downward API

有兩種方式可以將 Pod 和 Container 字段呈現給運行中的容器:

  • 環境變量
  • 卷文件

這兩種呈現 Pod 和 Container 字段的方式統稱為 Downward API。

使用環境變量的方式

用 Pod 字段作為環境變量的值

Pod 的配置文件

cat test_pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-fieldref
spec:
  containers:
    - name: test-container
      image: busybox
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
          printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
          sleep 10;
        done;
      env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - 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
        - name: MY_POD_SERVICE_ACCOUNT
          valueFrom:
            fieldRef:
              fieldPath: spec.serviceAccountName
  restartPolicy: Never

這個配置文件中,你可以看到五個環境變量。env 字段是一個 EnvVars. 對象的數組。 數組中第一個元素指定 MY_NODE_NAME 這個環境變量從 Pod 的 spec.nodeName 字段獲取變量值。 同樣,其它環境變量也是從 Pod 的字段獲取它們的變量值。

說明: 本示例中的字段是 Pod 字段,不是 Pod 中 Container 的字段。

# 創建Pod
# kubectl apply -f test_pod.yaml 
pod/dapi-envars-fieldref created

# 驗證 Pod 中的容器運行正常
# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
dapi-envars-fieldref   1/1     Running   0          5s

# 查看容器日志,輸出信息顯示了所選擇的環境變量的值
# kubectl logs dapi-envars-fieldref

develop-worker-2
dapi-envars-fieldref
default
10.0.2.110
default

要了解為什么這些值在日志中,請查看配置文件中的command和 args字段。 當容器啟動時,它將五個環境變量的值寫入stdout。每十秒重復執行一次。

接下來,通過打開一個 Shell 進入 Pod 中運行的容器:

# kubectl exec -it dapi-envars-fieldref /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.

# 在 Shell 中,查看環境變量
/ # printenv
MY_POD_SERVICE_ACCOUNT=default
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.3.255.1:443
DASHBOARD_KUBERNETES_DASHBOARD_SERVICE_HOST=10.3.255.88
HOSTNAME=dapi-envars-fieldref
DASHBOARD_KUBERNETES_DASHBOARD_PORT_9090_TCP_ADDR=10.3.255.88
SHLVL=1
HOME=/root
DASHBOARD_KUBERNETES_DASHBOARD_PORT_9090_TCP_PORT=9090
DASHBOARD_KUBERNETES_DASHBOARD_PORT_9090_TCP_PROTO=tcp
DASHBOARD_KUBERNETES_DASHBOARD_SERVICE_PORT=9090
DASHBOARD_KUBERNETES_DASHBOARD_PORT=tcp://10.3.255.88:9090
MY_POD_NAMESPACE=default
DASHBOARD_KUBERNETES_DASHBOARD_PORT_9090_TCP=tcp://10.3.255.88:9090
TERM=xterm
MY_POD_IP=10.0.2.110
KUBERNETES_PORT_443_TCP_ADDR=10.3.255.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
MY_NODE_NAME=develop-worker-2
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.3.255.1:443
KUBERNETES_SERVICE_HOST=10.3.255.1
PWD=/
DASHBOARD_KUBERNETES_DASHBOARD_SERVICE_PORT_HTTP=9090
MY_POD_NAME=dapi-envars-fieldref

用 Container 字段作為環境變量的值

包含一個容器的 Pod 的配置文件

# cat test_pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-resourcefieldref
spec:
  containers:
    - name: test-container
      image: busybox
      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

這個配置文件中,你可以看到四個環境變量。env 字段是一個 EnvVars. 對象的數組。數組中第一個元素指定 MY_CPU_REQUEST 這個環境變量從 Container 的 requests.cpu 字段獲取變量值。同樣,其它環境變量也是從 Container 的字段獲取它們的變量值。

說明: 本例中使用的是 Container 的字段而不是 Pod 的字段。

# 創建Pod
# kubectl apply -f test_pod1.yaml
pod/dapi-envars-resourcefieldref created

# 驗證 Pod 中的容器運行正常
# kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
dapi-envars-resourcefieldref   1/1     Running   0          6s

# 查看容器日志,輸出信息顯示了所選擇的環境變量的值
# kubectl logs dapi-envars-resourcefieldref

1
1
33554432
67108864

使用文件的方式

Pod字段

包含一個容器的 Pod的配置文件

# cat test_pod2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example
  labels:
    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
  annotations:
    build: two
    builder: john-doe
spec:
  containers:
    - name: client-container
      image: busybox
      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 5;
        done;
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
            fieldRef:
              fieldPath: metadata.labels
          - path: "annotations"
            fieldRef:
              fieldPath: metadata.annotations

在配置文件中,你可以看到 Pod 有一個 downwardAPI 類型的卷,並且掛載到容器中的 /etc/podinfo 目錄。
查看 downwardAPI 下面的 items 數組。 每個數組元素都是一個 DownwardAPIVolumeFile 對象。 第一個元素指示 Pod 的 metadata.labels 字段的值保存在名為 labels 的文件中。 第二個元素指示 Pod 的 annotations 字段的值保存在名為 annotations 的文件中。

說明: 本示例中的字段是Pod字段,不是Pod中容器的字段。

# 創建 Pod
# kubectl apply -f test_pod2.yaml
pod/kubernetes-downwardapi-volume-example created

# 驗證Pod中的容器運行正常
# kubectl get pods
NAME                                    READY   STATUS    RESTARTS   AGE
kubernetes-downwardapi-volume-example   1/1     Running   0          47s

# 查看容器的日志,輸出顯示 labels 和 annotations 文件的內容
# kubectl logs kubernetes-downwardapi-volume-example

cluster="test-cluster1"
rack="rack-22"
zone="us-est-coast"

build="two"
builder="john-doe"
kubectl.kubernetes.io/last-applied-configuration="{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{\"build\":\"two\",\"builder\":\"john-doe\"},\"labels\":{\"cluster\":\"test-cluster1\",\"rack\":\"rack-22\",\"zone\":\"us-est-coast\"},\"name\":\"kubernetes-downwardapi-volume-example\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"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 5; done;\"],\"command\":[\"sh\",\"-c\"],\"image\":\"busybox\",\"name\":\"client-container\",\"volumeMounts\":[{\"mountPath\":\"/etc/podinfo\",\"name\":\"podinfo\"}]}],\"volumes\":[{\"downwardAPI\":{\"items\":[{\"fieldRef\":{\"fieldPath\":\"metadata.labels\"},\"path\":\"labels\"},{\"fieldRef\":{\"fieldPath\":\"metadata.annotations\"},\"path\":\"annotations\"}]},\"name\":\"podinfo\"}]}}\n"
kubernetes.io/config.seen="2021-05-17T15:31:02.676723051+08:00"
kubernetes.io/config.source="api"

# 進入 Pod 中運行的容器,打開一個 Shell
# kubectl exec -it kubernetes-downwardapi-volume-example -- sh

# 在該 Shell中,查看 labels 文件,輸出顯示 Pod 的所有標簽都已寫入 labels 文件
/ # cat /etc/podinfo/labels 
cluster="test-cluster1"
rack="rack-22"

# 查看annotations文件,
/ # cat /etc/podinfo/annotations 
build="two"
builder="john-doe"
kubectl.kubernetes.io/last-applied-configuration="{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{\"build\":\"two\",\"builder\":\"john-doe\"},\"labels\":{\"cluster\":\"test-cluster1\",\"rack\":\"rack-22\",\"zone\":\"us-est-coast\"},\"name\":\"kubernetes-downwardapi-volume-example\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"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 5; done;\"],\"command\":[\"sh\",\"-c\"],\"image\":\"busybox\",\"name\":\"client-container\",\"volumeMounts\":[{\"mountPath\":\"/etc/podinfo\",\"name\":\"podinfo\"}]}],\"volumes\":[{\"downwardAPI\":{\"items\":[{\"fieldRef\":{\"fieldPath\":\"metadata.labels\"},\"path\":\"labels\"},{\"fieldRef\":{\"fieldPath\":\"metadata.annotations\"},\"path\":\"annotations\"}]},\"name\":\"podinfo\"}]}}\n"
kubernetes.io/config.seen="2021-05-17T15:31:02.676723051+08:00"

# 查看/etc/podinfo目錄下的文件
/ # ls -al /etc/podinfo/
total 4
drwxrwxrwt    3 root     root           120 May 17 07:31 .
drwxr-xr-x    1 root     root          4096 May 17 07:31 ..
drwxr-xr-x    2 root     root            80 May 17 07:31 ..2021_05_17_07_31_03.519523692
lrwxrwxrwx    1 root     root            31 May 17 07:31 ..data -> ..2021_05_17_07_31_03.519523692
lrwxrwxrwx    1 root     root            18 May 17 07:31 annotations -> ..data/annotations
lrwxrwxrwx    1 root     root            13 May 17 07:31 labels -> ..data/labels


# 在輸出中可以看到,labels 和 annotations 文件都在一個臨時子目錄中。 在這個例子是..2021_05_17_07_31_03.519523692。 在 /etc/podinfo 目錄中,..data 是一個指向臨時子目錄 的符號鏈接。/etc/podinfo 目錄中,labels 和 annotations 也是符號鏈接。

/ # ls -al /etc/podinfo/..2021_05_17_07_31_03.519523692/
total 8
drwxr-xr-x    2 root     root            80 May 17 07:31 .
drwxrwxrwt    3 root     root           120 May 17 07:31 ..
-rw-r--r--    1 root     root          1102 May 17 07:31 annotations
-rw-r--r--    1 root     root            58 May 17 07:31 labels

# 用符號鏈接可實現元數據的動態原子性刷新;更新將寫入一個新的臨時目錄, 然后通過使用rename(2) 完成 ..data 符號鏈接的原子性更新。
# 說明: 如果容器以 subPath卷掛載方式來使用 Downward API,則該容器無法收到更新事件。

Container 字段

包含一個容器的 Pod 的配置文件

# cat test_pod3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: kubernetes-downwardapi-volume-example-2
spec:
  containers:
    - name: client-container
      image: busybox
      command: ["sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          if [[ -e /etc/podinfo/cpu_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_limit; fi;
          if [[ -e /etc/podinfo/cpu_request ]]; then
            echo -en '\n'; cat /etc/podinfo/cpu_request; fi;
          if [[ -e /etc/podinfo/mem_limit ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_limit; fi;
          if [[ -e /etc/podinfo/mem_request ]]; then
            echo -en '\n'; cat /etc/podinfo/mem_request; fi;
          sleep 5;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      volumeMounts:
        - name: podinfo
          mountPath: /etc/podinfo
  volumes:
    - name: podinfo
      downwardAPI:
        items:
          - path: "cpu_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.cpu
              divisor: 1m
          - path: "cpu_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.cpu
              divisor: 1m
          - path: "mem_limit"
            resourceFieldRef:
              containerName: client-container
              resource: limits.memory
              divisor: 1Mi
          - path: "mem_request"
            resourceFieldRef:
              containerName: client-container
              resource: requests.memory
              divisor: 1Mi

在這個配置文件中,你可以看到 Pod 有一個 downwardAPI 類型的卷,並且掛載到容器的 /etc/podinfo 目錄。查看 downwardAPI 下面的 items 數組。每個數組元素都是一個 DownwardAPIVolumeFile。第一個元素指定名為 client-container 的容器中 limits.cpu 字段的值應保存在名為 cpu_limit 的文件中。

# 創建Pod
# kubectl apply -f test_pod3.yaml
pod/kubernetes-downwardapi-volume-example-2 created

# 查看pod是否運行正常
# kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
kubernetes-downwardapi-volume-example-2   1/1     Running   0          7s

# 打開一個 Shell,進入 Pod 中運行的容器
# kubectl exec -it kubernetes-downwardapi-volume-example-2 -- sh

# 在 Shell 中,查看 cpu_limit 文件
/ # cat /etc/podinfo/cpu_limit 
250
/ # 

# 可以使用同樣的命令查看 cpu_request、mem_limit 和 mem_request 文件

Downward API 的能力

下面這些信息可以通過環境變量和 downwardAPI 卷提供給容器:

  • 能通過 fieldRef 獲得的:

    • metadata.name - Pod 名稱
    • metadata.namespace - Pod 名字空間
    • metadata.uid - Pod 的 UID
    • metadata.labels[' '] - Pod 標簽 的值 (例如, metadata.labels['mylabel'])
    • metadata.annotations[' '] - Pod 的注解 的值(例如, - metadata.annotations['myannotation'])
  • 能通過 resourceFieldRef 獲得的:

    • 容器的 CPU 約束值
    • 容器的 CPU 請求值
    • 容器的內存約束值
    • 容器的內存請求值
    • 容器的巨頁限制值(前提是啟用了 DownwardAPIHugePages 特性門控)
    • 容器的巨頁請求值(前提是啟用了 DownwardAPIHugePages 特性門控)
    • 容器的臨時存儲約束值
    • 容器的臨時存儲請求值

此外,以下信息可通過 downwardAPI 卷從 fieldRef 獲得:

  • metadata.labels - Pod 的所有標簽,以 label-key="escaped-label-value" 格式顯示,每行顯示一個標簽
  • metadata.annotations - Pod 的所有注解,以 annotation-key="escaped-annotation-value" 格式顯示,每行顯示一個標簽

以下信息可通過環境變量獲得:

  • status.podIP - 節點 IP
  • spec.serviceAccountName - Pod 服務帳號名稱, 版本要求 v1.4.0-alpha.3
  • spec.nodeName - 節點名稱, 版本要求 v1.4.0-alpha.3
  • status.hostIP - 節點 IP, 版本要求 v1.7.0-alpha.1

說明: 如果容器未指定 CPU 和內存限制,則 Downward API 默認將節點可分配值 視為容器的 CPU 和內存限制。

Downward API的動機

對於容器來說,有時候擁有自己的信息是很有用的,可避免與 Kubernetes 過度耦合。 Downward API 使得容器使用自己或者集群的信息,而不必通過 Kubernetes 客戶端或 API 服務器來獲得。
一個例子是有一個現有的應用假定要用一個非常熟悉的環境變量來保存一個唯一標識。 一種可能是給應用增加處理層,但這樣是冗余和易出錯的,而且它違反了低耦合的目標。 更好的選擇是使用 Pod 名稱作為標識,把 Pod 名稱注入這個環境變量中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM