Jonas
Jonas

Reputation: 5149

Set node label to the pod environment variable

How to set Node label to Pod environment variable? I need to know the label topology.kubernetes.io/zone value inside the pod.

Upvotes: 7

Views: 4692

Answers (2)

anemyte
anemyte

Reputation: 20306

The Downward API currently does not support exposing node labels to pods/containers. There is an open issue about that on GitHib, but it is unclear when it will be implemented if at all.

That leaves the only option to get node labels from Kubernetes API, just as kubectl does. It is not easy to implement, especially if you want labels as environment variables. I'll give you an example how it can be done with an initContainer, curl, and jq but if possible, I suggest you rather implement this in your application, for it will be easier and cleaner.

To make a request for labels you need permissions to do that. Therefore, the example below creates a service account with permissions to get (describe) nodes. Then, the script in the initContainer uses the service account to make a request and extract labels from json. The test container reads environment variables from the file and echoes one.

Example:

# 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 into a file in the 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:
    # A container that needs 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

Upvotes: 4

Gupta
Gupta

Reputation: 10408

You could use InitContainer

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

Ref: Node Label to Pod


Edit Update

A similar Solution could be Inject node labels into Kubernetes pod

Upvotes: 1

Related Questions