A customer approached me recently with a use case where they needed to have the OpenShift container know the hostname of the node it was running on. They had found that the normal hostname file on Red Hat CoreOS was not on the node so they were not certain how they could derive the hostname value when they launched the custom daemonset they built. Enter the downward API in OpenShift.
The downward API is a implementation that allows containers to consume information about API objects without integrating via the OpenShift API. Such information includes items like the pod’s name, namespace, and resource values. Containers can consume information from the downward API using environment variables or a volume file.
Lets go ahead and demonstrate the capabilities of the downward API with a simple example of how it can be used. First lets create the following downward-secret.yaml file which will be used in our demonstration. The secret file is just a basic secret nothing exciting:
$ cat << EOF > downward-secret.yaml apiVersion: v1 kind: Secret metadata: name: downwardsecret data: password: cGFzc3dvcmQ= username: ZGV2ZWxvcGVy type: kubernetes.io/basic-auth EOF
$ oc create -f downward-secret.yaml secret/downwardsecret created
$ cat << EOF > downward-pod.yaml apiVersion: v1 kind: Pod metadata: name: downward-pod spec: containers: - name: busybox-container image: k8s.gcr.io/busybox command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv NODENAME HOSTIP SERVICEACCT NAMESPACE; printenv DOWNWARD_SECRET; sleep 10; done; resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" volumeMounts: - name: downwardinfo mountPath: /etc/downwardinfo readOnly: false env: - name: NODENAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: HOSTIP valueFrom: fieldRef: fieldPath: status.hostIP - name: SERVICEACCT valueFrom: fieldRef: fieldPath: spec.serviceAccountName - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: DOWNWARD_SECRET valueFrom: secretKeyRef: name: downwardsecret key: username volumes: - name: downwardinfo downwardAPI: items: - path: "cpu_limit" resourceFieldRef: containerName: busybox-container resource: limits.cpu - path: "cpu_request" resourceFieldRef: containerName: busybox-container resource: requests.cpu - path: "mem_limit" resourceFieldRef: containerName: busybox-container resource: limits.memory - path: "mem_request" resourceFieldRef: containerName: busybox-container resource: requests.memory EOF
$ cat downward-pod.yaml apiVersion: v1 kind: Pod metadata: name: downward-pod spec: containers: - name: busybox-container image: k8s.gcr.io/busybox command: [ "sh", "-c"] args: - while true; do echo -en '\n'; printenv NODENAME HOSTIP SERVICEACCT NAMESPACE; printenv DOWNWARD_SECRET; sleep 10; done; resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" volumeMounts: - name: downwardinfo mountPath: /etc/downwardinfo readOnly: false env: - name: NODENAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: HOSTIP valueFrom: fieldRef: fieldPath: status.hostIP - name: SERVICEACCT valueFrom: fieldRef: fieldPath: spec.serviceAccountName - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: DOWNWARD_SECRET valueFrom: secretKeyRef: name: downwardsecret key: username volumes: - name: downwardinfo downwardAPI: items: - path: "cpu_limit" resourceFieldRef: containerName: busybox-container resource: limits.cpu - path: "cpu_request" resourceFieldRef: containerName: busybox-container resource: requests.cpu - path: "mem_limit" resourceFieldRef: containerName: busybox-container resource: limits.memory - path: "mem_request" resourceFieldRef: containerName: busybox-container resource: requests.memory
resources: requests: memory: "32Mi" cpu: "125m" limits: memory: "64Mi" cpu: "250m" volumeMounts: - name: downwardinfo mountPath: /etc/downwardinfo readOnly: false
env: - name: NODENAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: HOSTIP valueFrom: fieldRef: fieldPath: status.hostIP - name: SERVICEACCT valueFrom: fieldRef: fieldPath: spec.serviceAccountName - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: DOWNWARD_SECRET valueFrom: secretKeyRef: name: downwardsecret key: username
volumes: - name: downwardinfo downwardAPI: items: - path: "cpu_limit" resourceFieldRef: containerName: busybox-container resource: limits.cpu - path: "cpu_request" resourceFieldRef: containerName: busybox-container resource: requests.cpu - path: "mem_limit" resourceFieldRef: containerName: busybox-container resource: limits.memory - path: "mem_request" resourceFieldRef: containerName: busybox-container resource: requests.memory
$ oc create -f downward-pod.yaml pod/downward-pod created $ oc get pod NAME READY STATUS RESTARTS AGE downward-pod 1/1 Running 0 6s
$ oc logs downward-pod master-0.kni20.schmaustech.com 192.168.0.210 default default developer master-0.kni20.schmaustech.com 192.168.0.210 default default developer
$ oc exec -it downward-pod sh kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. / #
/ # printenv KUBERNETES_PORT=tcp://172.30.0.1:443 KUBERNETES_SERVICE_PORT=443 HOSTNAME=downward-pod SHLVL=1 HOME=/root TERM=xterm KUBERNETES_PORT_443_TCP_ADDR=172.30.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 HOSTIP=192.168.0.210 DOWNWARD_SECRET=developer NAMESPACE=default KUBERNETES_PORT_443_TCP=tcp://172.30.0.1:443 KUBERNETES_SERVICE_PORT_HTTPS=443 PWD=/ KUBERNETES_SERVICE_HOST=172.30.0.1 SERVICEACCT=default NSS_SDB_USE_CACHE=no NODENAME=master-0.kni20.schmaustech.com
/ # ls /etc/downwardinfo cpu_limit cpu_request mem_limit mem_request
/ # echo "$(cat /etc/downwardinfo/cpu_limit)" 1 / # echo "$(cat /etc/downwardinfo/cpu_request)" 1 / # echo "$(cat /etc/downwardinfo/mem_limit)" 67108864 / # echo "$(cat /etc/downwardinfo/mem_request)" 33554432