将节点标签设置为 pod 环境变量

时间:2021-04-27 13:43:25

标签: kubernetes

如何将Node标签设置为Pod环境变量?我需要知道 pod 内的标签 topology.kubernetes.io/zone 值。

2 个答案:

答案 0 :(得分:2)

Downward API 目前不支持将节点信息暴露给 pods/containers。 GitHib 上有一个关于此的 open issue,但尚不清楚何时会实施。

这是从 Kubernetes API 获取节点标签的唯一选择,就像 kubectl 一样。实现起来并不容易,特别是如果你想要标签作为环境变量。我将举一个例子说明如何使用 initContainercurljq 但如果可能的话,我建议您宁愿在您的应用程序中实现它,因为它会更容易更干净。

要发出标签请求,您需要获得相应权限。因此,下面的示例创建了一个有权访问 get(描述)节点的服务帐户。然后,initContainer 中的脚本使用服务帐户发出请求并提取标签。 test 容器从文件和 echo 中读取环境变量。

示例:

# Create a service account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: describe-nodes
  namespace: <insert-namespace-name-where-the-app-is>
---
# Create a cluster role that allowed to perform describe ("get") over ["nodes"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: describe-nodes
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get"]
---
# Associate the cluster role with the service account
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: describe-nodes
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: describe-nodes
subjects:
- kind: ServiceAccount
  name: describe-nodes
  namespace: <insert-namespace-name-where-the-app-is>
---
# Proof of concept pod
apiVersion: v1
kind: Pod
metadata:
  name: get-node-labels
spec:
  # Service account to get node labels from Kubernetes API
  serviceAccountName: describe-nodes

  # A volume to keep the extracted labels
  volumes:
    - name: node-info
      emptyDir: {}

  initContainers:
    # The container that extracts the labels
    - name: get-node-labels

      # The image needs 'curl' and 'jq' apps in it
      # I used curl image and run it as root to install 'jq'
      # during runtime
      # THIS IS A BAD PRACTICE UNSUITABLE FOR PRODUCTION
      # Make an image where both present.
      image: curlimages/curl
      # Remove securityContext if you have an image with both curl and jq
      securityContext:
        runAsUser: 0

      # It'll put labels here
      volumeMounts:
        - mountPath: /node
          name: node-info

      env:
        # pass node name to the environment
        - name: NODENAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: APISERVER
          value: https://kubernetes.default.svc
        - name: SERVICEACCOUNT
          value: /var/run/secrets/kubernetes.io/serviceaccount
        - name: SCRIPT
          value: |
            set -eo pipefail

            # install jq; you don't need this line if the image has it
            apk add jq

            TOKEN=$(cat ${SERVICEACCOUNT}/token)
            CACERT=${SERVICEACCOUNT}/ca.crt

            # Get node labels into a json
            curl --cacert ${CACERT} \
                 --header "Authorization: Bearer ${TOKEN}" \
                 -X GET ${APISERVER}/api/v1/nodes/${NODENAME} | jq .metadata.labels > /node/labels.json

            # Extract 'topology.kubernetes.io/zone' from json
            NODE_ZONE=$(jq '."topology.kubernetes.io/zone"' -r /node/labels.json)
            # and save it in a file in a format suitable for sourcing
            echo "export NODE_ZONE=${NODE_ZONE}" > /node/zone
      command: ["/bin/ash", "-c"]
      args:
        - 'echo "$$SCRIPT" > /tmp/script && ash /tmp/script'

  containers:
    # The container that need the label value
    - name: test
      image: debian:buster
      command: ["/bin/bash", "-c"]
      # source ENV variable from file, echo NODE_ZONE, and keep running doing nothing
      args: ["source /node/zone && echo $$NODE_ZONE && cat /dev/stdout"]
      volumeMounts:
        - mountPath: /node
          name: node-info

答案 1 :(得分:1)

您可以使用 InitContainer

...
spec:
      initContainers:
      - name: node2pod
        image: <image-with-k8s-access>
        env:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
       ...

参考:Node Label to Pod


编辑更新

类似的解决方案可能是 Inject node labels into Kubernetes pod