Skip to main content

Kubernetes Environment

Introduction

Environment variables are a crucial aspect of application configuration in Kubernetes. They allow you to separate configuration from code, making your applications more flexible, portable, and easier to maintain. In this guide, we'll explore how Kubernetes handles environment variables and how you can leverage them effectively in your deployments.

Environment variables in Kubernetes serve several important purposes:

  • They provide a way to pass dynamic configuration to applications
  • They enable applications to behave differently in different environments (development, staging, production)
  • They help in keeping sensitive information separate from application code
  • They facilitate the implementation of the 12-Factor App methodology

Basic Environment Variables in Pods

The simplest way to define environment variables is directly in a Pod specification. Let's look at a basic example:

yaml
apiVersion: v1
kind: Pod
metadata:
name: simple-env-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: DATABASE_URL
value: "mysql://user:password@mysql:3306/db"
- name: LOG_LEVEL
value: "info"

In this example, two environment variables (DATABASE_URL and LOG_LEVEL) are defined and will be available inside the container.

You can verify the environment variables are set correctly by executing a command in the container:

bash
kubectl exec simple-env-pod -- env | grep -E 'DATABASE_URL|LOG_LEVEL'

Output:

DATABASE_URL=mysql://user:password@mysql:3306/db
LOG_LEVEL=info

Using ConfigMaps for Environment Variables

Hardcoding environment variables in Pod definitions isn't ideal for configuration that needs to be reused across multiple Pods. Kubernetes provides ConfigMaps to store configuration data that can be consumed by Pods.

Creating a ConfigMap

Let's create a ConfigMap to store our application configuration:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database_url: "mysql://user:password@mysql:3306/mydb"
cache_host: "redis:6379"
log_level: "debug"

You can create this ConfigMap using:

bash
kubectl apply -f configmap.yaml

Using ConfigMap Values as Environment Variables

There are two main ways to use ConfigMap data as environment variables:

1. Individual ConfigMap Keys

yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-env-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: log_level

2. All Keys from a ConfigMap

yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-envfrom-pod
spec:
containers:
- name: my-container
image: nginx
envFrom:
- configMapRef:
name: app-config

With envFrom, all keys from the ConfigMap become environment variables in the container. The environment variable names will be the same as the keys in the ConfigMap.

Using Secrets for Sensitive Environment Variables

For sensitive data like passwords, API keys, or tokens, you should use Kubernetes Secrets instead of ConfigMaps.

Creating a Secret

yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
db_password: cGFzc3dvcmQxMjM= # base64 encoded "password123"
api_key: c2VjcmV0a2V5MTIz # base64 encoded "secretkey123"

Alternatively, you can create a Secret using the kubectl command:

bash
kubectl create secret generic app-secrets \
--from-literal=db_password=password123 \
--from-literal=api_key=secretkey123

Using Secret Values as Environment Variables

Similar to ConfigMaps, there are multiple ways to use Secrets as environment variables:

1. Individual Secret Keys

yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db_password
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secrets
key: api_key

2. All Keys from a Secret

yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-envfrom-pod
spec:
containers:
- name: my-container
image: nginx
envFrom:
- secretRef:
name: app-secrets

Environment Variables in Deployments

The configurations we've seen so far apply to Pods, but you'll most often work with higher-level abstractions like Deployments. Here's how to set environment variables in a Deployment:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: my-app:1.0
env:
- name: NODE_ENV
value: "production"
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secrets

This Deployment creates Pods with environment variables from:

  • A directly defined NODE_ENV variable
  • All keys from the app-config ConfigMap
  • All keys from the app-secrets Secret

Dynamic Environment Variables

Kubernetes also allows you to use dynamic information as environment variables.

Pod Information

You can expose Pod information through the Downward API:

yaml
apiVersion: v1
kind: Pod
metadata:
name: downward-api-pod
labels:
app: web
tier: frontend
spec:
containers:
- name: main
image: nginx
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName

Container Resources

You can also reference container resource limits and requests:

yaml
apiVersion: v1
kind: Pod
metadata:
name: resource-env-pod
spec:
containers:
- name: main
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
env:
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: main
resource: requests.cpu
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: main
resource: limits.memory

Best Practices for Environment Variables

When working with environment variables in Kubernetes, consider the following best practices:

  1. Use ConfigMaps for non-sensitive configuration: Keep your configuration separate from your application code and Pod definitions.

  2. Use Secrets for sensitive data: Never store sensitive information in ConfigMaps or directly in Pod specifications.

  3. Group related configurations: Create separate ConfigMaps for different aspects of your application (e.g., database settings, logging settings).

  4. Use meaningful variable names: Choose descriptive names that clearly indicate the purpose of each variable.

  5. Consider environment-specific ConfigMaps: You might have different configurations for development, staging, and production environments.

  6. Validate environment variables: Have your application check for required environment variables during startup.

  7. Don't overuse environment variables: For complex configurations, consider using configuration files mounted as volumes instead.

Visualizing Environment Variable Flow

Here's a diagram showing how environment variables flow from various sources to Pods:

Real-world Example: Configuring a Web Application

Let's look at a more comprehensive example of configuring a web application with different types of environment variables:

yaml
# Database configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
data:
DB_HOST: "postgres-service"
DB_PORT: "5432"
DB_NAME: "myapp"
DB_USER: "app_user"
---
# Database credentials
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM=
---
# Application configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
NODE_ENV: "production"
LOG_LEVEL: "info"
CACHE_TTL: "3600"
ENABLE_METRICS: "true"
---
# Web application deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: myapp:1.0
ports:
- containerPort: 3000
envFrom:
- configMapRef:
name: app-config
- configMapRef:
name: db-config
- secretRef:
name: db-credentials
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name

This configuration:

  1. Separates database configuration from credentials
  2. Groups application settings in a dedicated ConfigMap
  3. Injects all these variables into the web application pods
  4. Adds dynamic Pod information

Environment Variables and Application Lifecycle

Environment variables in Kubernetes are set when a container starts and remain constant throughout its lifecycle. If you update a ConfigMap or Secret, existing Pods won't automatically get the new values. You have a few options to handle this:

  1. Restart the Pods: This is the simplest approach, but causes downtime.

    bash
    kubectl rollout restart deployment/my-app
  2. Use a configuration reloader: Tools like Reloader can watch for changes in ConfigMaps and Secrets and automatically trigger rolling updates.

  3. Design your application to reload configuration: Your application can periodically check for changes in configuration files (when mounted as volumes).

Summary

Environment variables in Kubernetes provide a flexible way to configure applications without hardcoding values in your code. By using ConfigMaps and Secrets, you can manage non-sensitive and sensitive configuration separately, promoting better security practices.

Key takeaways:

  • Use env to define individual environment variables directly in Pod specifications
  • Use ConfigMaps for non-sensitive configuration data
  • Use Secrets for sensitive information
  • Use the Downward API to expose Pod metadata as environment variables
  • Follow best practices to maintain clean, secure, and manageable configurations

Exercises

  1. Create a ConfigMap with database connection settings and use it in a Pod.
  2. Create a Secret with API credentials and inject it into a Deployment.
  3. Set up a Pod that displays its own name and namespace using the Downward API.
  4. Create a Deployment that uses environment variables from multiple sources (direct definition, ConfigMap, Secret).
  5. Update a ConfigMap and observe how changes affect existing and new Pods.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)