What is Environment Variables?
Most running applications require external configuration. for example: API key for service use, output format of Python Flask API (XML or JSON) or information related to email account, etc. The best way is not to configure. hard form in code because this requires redeploying or even rebuilding the application whenever a variable changes, which is detrimental when your application runs on many different environments.
Environment variable with Kubernetes.
As we all know, the Pod in kubernetes is where the application is run. Pod itself can hold 1 or more containers. Pods are processes on top of Worker Nodes. Pod itself has its own resources for file system, cpu, ram, volumes, network address … When you create a Pod (with Deployment
, StatefulSet
or other means), you set environment variables for containers running in the Pod. , then Kubernetes will move to the application inside Pod.
So with applications deployed on Kubernetes, how do we instantiate the environment variables for the Pod or initialize the config file for the Container service? In this article, we will discuss the methods to define environment variables for containers in Kubernetes Pod.
Use name
and value
pairs
To set environment variables, in your configuration file add the env
field. In the env
field is an EnvVar
array, each EnvVar
includes a name
as the variable name and value
(string) is the value of the variable.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | spec: containers: - env: - name: DATABASE_HOST value: mysql - name: DATABASE_NAME value: develop - name: DATABASE_PASSWORD value: abc123 - name: DATABASE_USER value: develop - name: DATABASE_PORT value: "3306" |
Alternatively, the environment variables you define in the Pod configuration can be used elsewhere in the configuration, for example in the commands and arguments you set for the Pod container.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | spec: containers: - env: - name: DATABASE_HOST value: mysql - name: DATABASE_NAME value: develop - name: DATABASE_PASSWORD value: abc123 - name: DATABASE_USER value: develop - name: DATABASE_PORT value: "3306" command: ["echo"] args: ["$(DATABASE_HOST) $(DATABASE_NAME) $(DATABASE_PASSWORD)"] |
Once created, the echo mysql develop abc123
command will be run on the container.
Use configmap
file
With the above method, we can easily set an environment variable for the container. However, assuming there are 10 or more environment variables to be set for each pod and these environment variables are the same, then it would be much better to have a separate configuration file for the environment variable. In Kubernetes, this can be done using a configmap
. For example:
1 2 3 4 5 6 7 8 9 | apiVersion: v1 kind: ConfigMap metadata: name: my-env data: VARIABLE1: test1 VARIABLE2: test2 VARIABLE3: test3 |
With a configmap
like above it is very easy for multiple containers to share the same environment variable configuration file. Then, in the container, we need to reference the configmap
file using configMapRef
.
1 2 3 4 5 6 | spec: containers: - envFrom: - configMapRef: name: my-env |
For more flexibility, it is also possible to use external configuration files in the formats VAR = VAL, and create a configMap from them using a statement with kubectl
. For example:
kubectl create configmap postgres-config --from-env-file=postgres-config.properties
The content of postgres-config.properties
file could be as follows:
1 2 3 4 5 | POSTGRES_DB=viblo POSTGRES_USER=viblo POSTGRES_PASSWORD=secret PGDATA=/var/lib/postgresql/data/pgdata |
Use file secrets
One other common use when need to set the environment variable is used secrets
, especially when the environment variable is the important information needed for passwords, access key, API key, … Secrets
operating under is similar to confifmap
and we can use them for the same purpose as configmap
. The difference is that secrets
have a higher level of security and privacy and Kubernetes will require base64 encryption for the information in secrets.
For example, we have the following secrets:
1 2 3 4 5 6 7 8 9 | apiVersion: v1 kind: Secret metadata: name: postgres-secrets type: Opaque data: POSTGRES_USER: cHJvZHVjdF9yb2JvdA== POSTGRES_PASSWORD: cHIwZHIwYjB0 |
We can also use stringData
instead of data
and instead use unencrypted values, Kubernetes then encodes the values for us when creating or updating the secrers. This is useful when the deployment is creating the configuration and we want to set the value at this stage.
Then we will add the secrets in the container configuration file similar to this:
1 2 3 4 5 6 7 8 | spec: containers: - name: postgres image: postgres:latest envFrom: - secretRef: name: postgres-secrets |
Use the Pod and resources container fields
In Kubernetes, in addition to setting the value directly to the value
field when setting the environment variable, we can also take the pod and resources
fields of the available container through the Kubernetes API and set them as environment variables. To do this, we will use the valueFrom
field and the fieldRef
, fieldPath
, resourceFieldRef
fieldPath
.
Below are the available container pod and resources
fields provided by Kubernetes, replacing <CONTAINER_NAME> with the name of the container for which you want to get the fields. This list may be expanded in the future.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | spec: containers: - env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName # Kubernetes 1.7+ - name: MY_NODE_IP valueFrom: fieldRef: fieldPath: status.hostIP - 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 # Kubernetes 1.8+ - name: MY_POD_UID valueFrom: fieldRef: fieldPath: metadata.uid - name: MY_CPU_REQUEST valueFrom: resourceFieldRef: containerName: <CONTAINER_NAME> resource: requests.cpu - name: MY_CPU_LIMIT valueFrom: resourceFieldRef: containerName: <CONTAINER_NAME> resource: limits.cpu - name: MY_MEM_REQUEST valueFrom: resourceFieldRef: containerName: <CONTAINER_NAME> resource: requests.memory - name: MY_MEM_LIMIT valueFrom: resourceFieldRef: containerName: <CONTAINER_NAME> resource: limits.memory |
summary
As the article just presented, there are many methods and options available in Kubernetes to define environment variables for containers in Kubernetes pod. When using it, we need to choose between methods to suit the requirements of the application. For example, when we want to manage sensitive information like passwords and other secrets, then secrets
is a preferred choice configmap
the usual configmap
or env
.