Understanding Environment Variables
TOC
Overview
Environment variables in Kubernetes are key-value pairs that provide configuration data to containers at runtime. They offer a flexible and secure way to inject configuration information, secrets, and runtime parameters into your applications without modifying container images or application code.
Core Concepts
What are Environment Variables?
Environment variables are:
- Key-value pairs available to processes running inside containers
- Runtime configuration mechanism that doesn't require image rebuilds
- Standard way to pass configuration data to applications
- Accessible through standard operating system APIs in any programming language
Environment Variable Sources in Kubernetes
Kubernetes supports multiple sources for environment variables:
Source Type | Description | Use Case |
---|
Static Values | Direct key-value pairs | Simple configuration |
ConfigMap | Reference to ConfigMap keys | Non-sensitive configuration |
Secret | Reference to Secret keys | Sensitive data (passwords, tokens) |
Field Reference | Pod/Container metadata | Dynamic runtime information |
Resource Reference | Resource requests/limits | Resource-aware configuration |
Environment Variable Precedence
Environment variables override configuration in this order:
- Kubernetes env (highest priority)
- Referenced ConfigMaps/Secrets
- Dockerfile ENV instructions
- Application default values (lowest priority)
Use Cases and Scenarios
1. Application Configuration
Basic application settings:
apiVersion: v1
kind: Pod
spec:
containers:
- name: web-app
image: myapp:latest
env:
- name: PORT
value: "8080"
- name: LOG_LEVEL
value: "info"
- name: ENVIRONMENT
value: "production"
- name: MAX_CONNECTIONS
value: "100"
2. Database Configuration
Database connection settings using ConfigMaps and Secrets:
apiVersion: v1
kind: ConfigMap
metadata:
name: db-config
data:
DB_HOST: "postgres.example.com"
DB_PORT: "5432"
DB_NAME: "myapp"
DB_POOL_SIZE: "10"
---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
DB_USER: bXl1c2Vy # base64 encoded "myuser"
DB_PASSWORD: bXlwYXNzd29yZA== # base64 encoded "mypassword"
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
env:
# From ConfigMap
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: db-config
key: DB_HOST
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: db-config
key: DB_PORT
- name: DB_NAME
valueFrom:
configMapKeyRef:
name: db-config
key: DB_NAME
# From Secret
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: DB_PASSWORD
3. Dynamic Runtime Information
Access Pod and Node metadata:
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
env:
# Pod information
- 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
# Resource information
- name: CPU_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.cpu
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.memory
4. Environment-Specific Configuration
Different configurations for different environments:
# Development environment
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-dev
data:
DEBUG: "true"
LOG_LEVEL: "debug"
CACHE_TTL: "60"
RATE_LIMIT: "1000"
---
# Production environment
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config-prod
data:
DEBUG: "false"
LOG_LEVEL: "warn"
CACHE_TTL: "3600"
RATE_LIMIT: "100"
---
# Deployment using environment-specific config
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: app-config-prod # Change to app-config-dev for development
CLI Examples and Practical Usage
Using kubectl run
# Set environment variables directly
kubectl run myapp --image=nginx --env="PORT=8080" --env="DEBUG=true"
# Multiple environment variables
kubectl run webapp --image=myapp:latest \
--env="DATABASE_URL=postgresql://localhost:5432/mydb" \
--env="REDIS_URL=redis://localhost:6379" \
--env="LOG_LEVEL=info"
# Interactive pod with environment variables
kubectl run debug --image=ubuntu:20.04 -it --rm \
--env="TEST_VAR=hello" \
--env="ANOTHER_VAR=world" \
-- /bin/bash
Using kubectl create
# Create ConfigMap from literal values
kubectl create configmap app-config \
--from-literal=DATABASE_HOST=postgres.example.com \
--from-literal=DATABASE_PORT=5432 \
--from-literal=CACHE_SIZE=256MB
# Create ConfigMap from file
echo "DEBUG=true" > app.env
echo "LOG_LEVEL=debug" >> app.env
kubectl create configmap app-env --from-env-file=app.env
# Create Secret for sensitive data
kubectl create secret generic db-secret \
--from-literal=username=myuser \
--from-literal=password=mypassword
Complex Environment Variable Examples
Microservices with Service Discovery
apiVersion: v1
kind: ConfigMap
metadata:
name: service-config
data:
USER_SERVICE_URL: "http://user-service:8080"
ORDER_SERVICE_URL: "http://order-service:8080"
PAYMENT_SERVICE_URL: "http://payment-service:8080"
NOTIFICATION_SERVICE_URL: "http://notification-service:8080"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
template:
spec:
containers:
- name: gateway
image: api-gateway:latest
env:
- name: PORT
value: "8080"
- name: ENVIRONMENT
value: "production"
envFrom:
- configMapRef:
name: service-config
- secretRef:
name: api-keys
Multi-Container Pod with Shared Configuration
apiVersion: v1
kind: Pod
metadata:
name: multi-container-app
spec:
containers:
# Main application
- name: app
image: myapp:latest
env:
- name: ROLE
value: "primary"
- name: SHARED_SECRET
valueFrom:
secretKeyRef:
name: shared-secret
key: token
envFrom:
- configMapRef:
name: shared-config
# Sidecar container
- name: sidecar
image: sidecar:latest
env:
- name: ROLE
value: "sidecar"
- name: MAIN_APP_URL
value: "http://localhost:8080"
- name: SHARED_SECRET
valueFrom:
secretKeyRef:
name: shared-secret
key: token
envFrom:
- configMapRef:
name: shared-config
Best Practices
1. Security Best Practices
# ✅ Use Secrets for sensitive data
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
api-key: <base64-encoded-value>
database-password: <base64-encoded-value>
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
env:
# ✅ Reference secrets
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secrets
key: api-key
# ❌ Avoid hardcoding sensitive data
# - name: API_KEY
# value: "secret-api-key-123"
2. Configuration Organization
# ✅ Organize configuration by purpose
apiVersion: v1
kind: ConfigMap
metadata:
name: database-config
data:
DB_HOST: "postgres.example.com"
DB_PORT: "5432"
DB_POOL_SIZE: "10"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cache-config
data:
REDIS_HOST: "redis.example.com"
REDIS_PORT: "6379"
CACHE_TTL: "3600"
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: database-config
- configMapRef:
name: cache-config
3. Environment Variable Naming
# ✅ Use consistent naming conventions
env:
- name: DATABASE_HOST # Clear, descriptive names
value: "postgres.example.com"
- name: DATABASE_PORT # Use underscores for separation
value: "5432"
- name: LOG_LEVEL # Use uppercase for environment variables
value: "info"
- name: FEATURE_FLAG_NEW_UI # Prefix related variables
value: "true"
# ❌ Avoid unclear or inconsistent naming
# - name: db # Too short
# - name: databaseHost # Inconsistent casing
# - name: log-level # Inconsistent separator
4. Default Values and Validation
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
env:
- name: PORT
value: "8080" # Provide sensible defaults
- name: LOG_LEVEL
value: "info" # Default to safe values
- name: TIMEOUT_SECONDS
value: "30" # Include units in names
- name: MAX_RETRIES
value: "3" # Limit retry attempts