In a previous post, I described the Kubernetes Downward API and how it allows us to inject pod/container metadata into our runtime container.
In this article, I’ll show how you can read the environment variables and mounted files from inside a containerized GoLang based application.
Injection of metadata
As explained in the earlier article, there are two types of metadata that can be exposed with the Downward API: pod metadata and container metadata.
This injection is put into environment variables by definitions located at ‘.spec.template.spec.containers[].env’, like below:
env: # pulling pod fields - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName
And the injection of metadata as volume files is defined at ‘.spec.template.spec.volumes’ like below:
volumes: - name: podinfo downwardAPI: items: # pulling container fields from containers[].name - path: "mem_limit" resourceFieldRef: containerName: golang-hello-world-web resource: limits.memory divisor: 1Mi
View my downward-golang-web.yaml for a full example.
Environment variables from GoLang
From the example above, if you have an environment variable named MY_NODE_NAME coming from the Downward API that is the name of the Kubernetes worker node the pod is running on, then you can get that information like this using GoLang.
// pull from OS environment variable, provide default func getenv(key, fallback string) string { value := os.Getenv(key) if len(value) == 0 { return fallback } return value }
The basic call is ‘os.Getenv()’, but this function allows us to provide a default value in case it is not passed in, which is useful during non-Kubernetes testing of the container.
File from GoLang
In our manifest, the Downward API metadata is mounted at the directory “/etc/podinfo”. Given that we injected “mem_limit”, a simple file read in GoLang for this file looks like:
data, ferr := ioutil.ReadFile("/etc/podinfo/mem_limit") if ferr == nil { log.Printf("FILE %s = %s\n",file,data) } else { log.Printf("error reading file %v",ferr) }
But even better is to use “filepath.Walk()” to iterate through all the files located in “/etc/podinfo”. This full logic is provided in main.go.
Full example
If you would like to see a full example at work, see my k8s-downward-golang-web github project. Here is how you would grab the project, then run ‘kubectl apply’ on the manifest that deploys the Downward API with Python Flask application.
# get requirements sudo apt-get install git make -y # grab project from github git clone https://github.com/fabianlee/k8s-downward-golang-web.git cd k8s-downward-golang-web # run kubectl apply make k8s-apply
View the logs using kubectl
kubectl logs -l app=downward-golang-web --tail=100
And you should see a result similar to below that shows the injected environment variable and file metadata that are printed out when the container starts and the Python Flask application reads them from ‘main’.
2021/05/01 03:52:56 build version/time: 0.1.1/now 2021/05/01 03:52:56 ENV MY_NODE_NAME = microk8s-2 2021/05/01 03:52:56 ENV MY_POD_NAME = downward-golang-web-66cc9b56fb-gx929 2021/05/01 03:52:56 ENV MY_POD_IP = 10.1.100.148 2021/05/01 03:52:56 ENV MY_POD_SERVICE_ACCOUNT = default 2021/05/01 03:52:56 ENV MY_POD_LABEL_APP = downward-golang-web 2021/05/01 03:52:56 ENV MY_POD_ANNOTATION_AUTHOR = fabian lee 2021/05/01 03:52:56 ENV MY_POD_MEM_LIMIT_MB = 16 2021/05/01 03:52:56 ENV MY_POD_MEM_REQUEST_MB = 4 2021/05/01 03:52:56 FILE /etc/podinfo/annotations 2021/05/01 03:52:56 FILE /etc/podinfo/labels 2021/05/01 03:52:56 FILE /etc/podinfo/mem_limit 2021/05/01 03:52:56 FILE /etc/podinfo/mem_request 2021/05/01 03:52:56 FILE /etc/podinfo/name 2021/05/01 03:52:56 FILE /etc/podinfo/namespace 2021/05/01 03:52:56 app context: /downward-golang/ 2021/05/01 03:52:56 Starting web server on port 8080
You can also exec directly into the shell and view the env vars and volume mounted files directly.
# try 'env' and 'ls /etc/podinfo' # use 'exit' to quit shell kubectl exec -it $(kubectl -l app=downward-golang-web get pods --output=jsonpath={.items..metadata.name}) -- sh
REFERENCES
kubernetes.io, expose pod info to containers through env vars