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:
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:
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:
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:
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
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
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
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:
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
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
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:
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:
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:
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:
-
Use ConfigMaps for non-sensitive configuration: Keep your configuration separate from your application code and Pod definitions.
-
Use Secrets for sensitive data: Never store sensitive information in ConfigMaps or directly in Pod specifications.
-
Group related configurations: Create separate ConfigMaps for different aspects of your application (e.g., database settings, logging settings).
-
Use meaningful variable names: Choose descriptive names that clearly indicate the purpose of each variable.
-
Consider environment-specific ConfigMaps: You might have different configurations for development, staging, and production environments.
-
Validate environment variables: Have your application check for required environment variables during startup.
-
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:
# 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:
- Separates database configuration from credentials
- Groups application settings in a dedicated ConfigMap
- Injects all these variables into the web application pods
- 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:
-
Restart the Pods: This is the simplest approach, but causes downtime.
bashkubectl rollout restart deployment/my-app
-
Use a configuration reloader: Tools like Reloader can watch for changes in ConfigMaps and Secrets and automatically trigger rolling updates.
-
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
- Create a ConfigMap with database connection settings and use it in a Pod.
- Create a Secret with API credentials and inject it into a Deployment.
- Set up a Pod that displays its own name and namespace using the Downward API.
- Create a Deployment that uses environment variables from multiple sources (direct definition, ConfigMap, Secret).
- Update a ConfigMap and observe how changes affect existing and new Pods.
Additional Resources
- Kubernetes Documentation: ConfigMaps
- Kubernetes Documentation: Secrets
- Kubernetes Documentation: Environment Variables
- Kubernetes Documentation: Downward API
- The Twelve-Factor App - A methodology for building modern, scalable applications
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)