A best practice when deploying applications in a Kubernetes environment is to securely handle sensitive data by utilizing environment variables and mounting secrets from external sources rather than hard-coding them within the application code or container image.
In this guide, we’ll walk through how to set and manage Kubernetes environment variables so you can properly configure your deployments. We’ll showcase a few different ways in which you can populate environment variable values and make them available to your Pods. Let’s dig in.
What are Kubernetes environment variables?
Kubernetes environment variables are key-value pairs that provide configuration information to containers running in Kubernetes pods. When they are injected into containers, the containerized processes can retrieve the values as they run. Setting environment variables is one of the main ways to supply config parameters to your apps running in Kubernetes.
Environment variables are an ideal way to configure container deployments because they don't require anything to be injected into your container's filesystem. This ensures your workloads remain stateless so they can still be easily scaled across your Kubernetes Nodes, without requiring any complicated volume mounts.
Use cases for environment variables in Kubernetes
Kubernetes environment variables can be used to supply any external values that your containerized apps depend on. Some of the most common scenarios include:
- Setting database connection and remote server credentials - Apps that need to communicate with external services can access environment variables to learn the IP address, port number, and credentials to use.
- Identifying Pod details at runtime - You can use environment variables to access Pod metadata values from inside the container, such as the assigned IP address.
- Customizing app config values - Environment variables are often used to enable app feature flags and apply customized settings. Examples include the domain name an app is served on or the URI of the API server instance it should connect to.
- Use per-environment configuration - Environment variables decouple configuration from code. Using environment variables instead of hardcoded values lets you easily deploy multiple instances of your app to your Kubernetes cluster, such as staging and production versions with different sets of features enabled.
Environment variables are only useful when your containerized app knows how to read them. If you're creating your own apps and container images, then it's best practice to prefer environment variables for configuration because this helps make your deployments more portable. When you're working with third-party images, you should check the vendor's documentation to learn which environment variables are supported and the values that they accept.
How do environment variables work in Kubernetes?
Kubernetes environment variables are defined at the container level within your Kubernetes Pod manifests. Different containers within the Pod can, therefore, use their own sets of environment variables.
You can set environment variables in the env
and envFrom
manifest fields. env
is used to write key-value pairs with hardcoded values, whereas envFrom
lets you populate environment variables from the contents of ConfigMaps, Secrets, and runtime Pod properties.
When you start a Pod that defines some environment variables for its containers, Kubernetes will automatically set those variables in the configuration file when it creates the Pod's containers. The process running inside each container can then access the variables using any available mechanism, such as process.env.DEMO_VAR
in Node.js or $DEMO_VAR
in Bash.
How to change environment variables after a Pod has been created?
Kubernetes doesn't allow you to change environment variables after a Pod has been created. You must terminate the Pod and then create a replacement with the updated values. If you're using a higher-level object such as a Deployment or ReplicaSet, you can update the Pod's template in that object and scale down the Pod replica count to zero. Once you scale back up again, the new Pods will use the environment variables set in the current template version.
💡 You might also like:
- Kubectl Describe Command – Pods, Deployments & More
- Kubectl Get Context : Current Context, Switching & Listing
- What Are Kubernetes Jobs? Use Cases, Types & How to Run
Guide: How to define environment variables in the Kubernetes
There are three ways to define Kubernetes environment variables
- Directly in a Kubernetes Pod or container configuration file using the env field
- From external sources like ConfigMaps using the envFrom field
- Using Kubernetes secrets
Let's walk through some examples of how to set environment variables for your Kubernetes Pods. Make sure you've got Kubectl installed and connected to a cluster so you can follow along below.
1. Set environment variables with env in a Kubernetes configuration file
The env
field is the simplest way to set a Kubernetes environment variable. It needs to be nested within the spec.containers
section of your Pod manifest.
env
lets you define an environment variable as named key-value pair:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: DEMO_VAR
value: foobar
Let's prove that this example successfully sets the DEMO_VAR
environment variable inside the container. Copy the YAML file, save it as pod.yaml
in your working directory, and use Kubectl to create a Pod in your cluster:
$ kubectl apply -f pod.yaml
pod/nginx created
Next, use the kubectl exec
command to start an interactive shell session inside the container:
$ kubectl exec -it nginx -- sh
Finally, try echoing out the value of the $DEMO_VAR
variable --- you'll see it's set to foobar
, as defined in your Pod manifest:
/ # echo $DEMO_VAR
foobar
This demonstrates the environment variable was successfully set in the container.
2. Set environment variables using ConfigMap values
Kubernetes ConfigMaps are API objects that are purpose-built to store key-value data. It can be easier and more convenient to set a large number of environment variables using a ConfigMap, as this decouples their values from your Pod's manifest.
Here's a simple ConfigMap that contains two keys:
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-config
data:
debug_mode: "1"
log_level: "verbose"
You can make the contents stored in the ConfigMap available as Pod environment variables using the envFrom
field in your Pod manifest's spec.containers
section:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
envFrom:
- configMapRef:
name: demo-config
Now, the container's environment will include the $debug_mode
and $log_level
environment variables defined by the ConfigMap's key-value data pairs.
In some situations, you might want to select a subset of values from a ConfigMap or rename their keys before they're set as environment variables. To do this, replace the envFrom
field with its env.valueFrom
alternative:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: ENABLE_DEBUG_MODE
valueFrom:
configMapKeyRef:
name: demo-config
key: debug_mode
In this example, the container receives an environment variable called $ENABLE_DEBUG_MODE
that's set to the value of the ConfigMap's debug_mode
key.
3. Set environment variables using Kubernetes Secrets
Environment variables can also be used to inject data from Kubernetes Secrets. Secrets should be used to store sensitive data, such as any passwords and API tokens that your apps require. They provide greater security and privacy protections, including support for encrypted storage within the Kubernetes control plane.
Below is an example of a Kubernetes Secret file:
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: database-credentials
data:
DB_USER: YWRtaW4K
DB_PASSWORD: UEAzMDQ5MTU1dzByZAo=
Note: Values in Secrets must be base64-encoded, as shown in the example above.
You can populate environment variables from Secrets by using the env
and envFrom
Pod manifest fields in the same way as you reference a ConfigMap. Simply change envFrom.configMapRef
to envFrom.secretRef
and env.valueFrom.configMapKeyRef
to env.valueFrom.secretKeyRef
:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: database-credentials
key: DB_PASSWORD
4. Set environment variables to pod values
So far, we've seen how Kubernetes environment variables let you inject known values into your containers. However, they can also be made to reference certain properties of the Pod the container belongs to, including its name, annotations, host Node, and IP address.
This is achieved using the env.valueFrom.fieldRef.fieldPath
field. The following example sets the APP_URL
environment variable to the IP address that Kubernetes assigns to the Pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: APP_URL
valueFrom:
fieldRef:
fieldPath: status.podIP
You can find a list of all the supported fieldPath
values in the Kubernetes documentation.
5. Set environment variables to container resource requests and limits
Finally, environment variables can reference container-level resource requests and limits, too. For example, you might want to set an environment variable that configures your application's runtime to cap its memory usage to the limit that's available to the Pod.
This functionality is enabled using the env.valueFrom.resourceFieldRef
field. Note that within this field, you must set the containerName
property to match the name of the container you're targeting:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: APP_MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: nginx
resource: limits.memory
resources:
requests:
memory: "100Mi"
limits:
memory: "100Mi"
In the example above, the container's APP_MEMORY_LIMIT
environment variable will have the value 104857600
. Kubernetes injects the value after resolving it into a numeric bytes quantity instead of using the human-readable form written into your manifest.
Should I use the Kubernetes environment variable for Secret data?
Although Secrets can be injected into containers as environment variables, it's often safer to access them as mounted files in a volume instead. Data from Secrets will always be visible at the container level, but using files instead of environment variables helps protect you from malicious processes that collect environment variables after compromising a container, preventing further security risks.
Environment variables can be used to supply secrets to your containers, provided their values are actually sourced from Kubernetes Secret objects. It's not recommended to set secrets as hardcoded env entries or plain ConfigMap keys --- this will cause your data to be stored in plaintext.
How to pass environment variables in a Kubernetes deployment YAML manifest
In this guide, we've been working with individual Pods. However, it's best practice to avoid using bare Pods to run real workloads in your cluster. It's recommended to use Deployment objects instead so you can scale multiple Pod replicas using declarative configuration.
Deployment environment variables are set in the same way as Pods. You should use the familiar env
and envFrom
fields, but nested under the Pod template
section of your Deployment manifest file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: nginx
image: nginx:alpine-slim
env:
- name: DEMO_VAR
value: foobar
You can see the full path to the env
field is spec.template.spec.env
. It specifies that all containers created from the Deployment's Pod template will be started with the DEMO_VAR
variable set to foobar
.
Environment variables in Infrastructure as Code[
Environment variables are critical to other DevOps tools, too, not just Kubernetes. For example, they're used by IaC providers like Terraform and Pulumi to enable customization and reuse of your config files. You can use Spacelift to centrally manage environment variables across the IaC systems that you use, ensuring consistent configuration is applied without any duplication.
Mounted files
Every now and then, an environment variable is not what you need - you need a file instead. Terraform Kubernetes provider is a great example. One of the common ways of configuring it involves setting a KUBECONFIG variable pointing to the actual config file, which needs to be present in your workspace as well.
It's almost like creating an environment variable, though instead of typing (or pasting) the value, you'll be uploading a file:
Similar to environment variables, mounted files can have different visibility settings - you can learn more about them here. One thing to note here is that plaintext files can be downloaded back straight from the UI or API, while secret ones will only be visible to the run executed for the stack.
If you want to learn more about Spacelift, create a free account today or book a demo with one of our engineers.
Key points
In this article, we've looked at how you can use environment variables in your Kubernetes applications' configuration file with any runtime values they require. Environment variables are frequently used to customize app settings and supply required credentials, making your containers more portable across environments.
You can set Kubernetes environment variables using the env
and envFrom
fields in your Pod manifests. When you're managing a large number of environment variables, it's often easiest to create a ConfigMap, but this isn't a hard requirement.
However, it's important to use Secrets in conjunction with environment variables when you're working with sensitive information. Using the same environment variables across multiple applications in the same environment can lead to maintenance issues and potential exposure of sensitive information. Kubernetes secrets can be a solution to this problem.
Written by James Walker
Top comments (0)