🛠️ Kubernetes Intermediate: Configuration and Management
Kubernetes Intermediate: Configuration and Resource Management
Welcome to part 2 of our Kubernetes tutorial series! As your applications grow in complexity, proper configuration management becomes crucial. In this post, we’ll explore the tools and practices that make Kubernetes applications maintainable, secure, and resource-efficient in production environments.
What We’ll Cover
- Configuration Management with ConfigMaps - Keep your application settings flexible and environment-specific
- Managing Secrets - Secure handling of sensitive data like passwords and API keys
- Resource Management - Ensure optimal resource utilization and application performance
- Advanced Deployment Strategies - Zero-downtime deployments and production rollout techniques
Prerequisites
- Completed our Kubernetes Basics tutorial
- Running Kind cluster
- Basic YAML understanding
ConfigMaps: Managing Application Configuration
ConfigMaps are one of Kubernetes’ most powerful features for configuration management. They solve several critical challenges in modern application deployment:
Why Use ConfigMaps?
- Environment Separation: Maintain different configurations for development, staging, and production without changing application code
- Configuration Updates: Update application settings without rebuilding containers
- Configuration Sharing: Share configuration data across multiple pods
- Version Control: Track configuration changes in your Git repository
Types of Configuration Data
ConfigMaps can store various types of configuration:
- Environment variables
- Configuration files
- Command-line arguments
- Custom configuration formats
Here’s a comprehensive example:
# config-map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Simple key-value pairs
APP_ENV: "development"
LOG_LEVEL: "debug"
# Configuration files
app.properties: |
environment=development
log.level=debug
feature.flag.newui=true
cache.timeout=3600
# JSON configuration
config.json: |
{
"database": {
"host": "localhost",
"port": 5432,
"maxConnections": 100
},
"cache": {
"enabled": true,
"ttl": 3600
}
}
Best Practices for ConfigMaps
- Naming Convention: Use clear, consistent names that reflect the purpose
- Size Limits: Keep ConfigMaps under 1MB
- Granularity: Split large configurations into multiple ConfigMaps
- Validation: Always validate configuration before deployment
Using ConfigMaps in Pods
There are three main ways to use ConfigMaps:
- Environment Variables:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: config-env-pod
spec:
containers:
- name: app-container image: my-app:1.0 env:
- name: APP_ENV valueFrom: configMapKeyRef: name: app-config key: APP_ENV ```
- Volume Mounts (for configuration files):
```yaml
apiVersion: v1
kind: Pod
metadata:
name: config-volume-pod
spec:
containers:
- name: app-container image: my-app:1.0 volumeMounts:
- name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: app-config ```
- Command Line Arguments:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: config-cmd-pod
spec:
containers:
- name: app-container image: my-app:1.0 command: [“/bin/app”] args: [”–env”, “$(APP_ENV)”] env:
- name: APP_ENV valueFrom: configMapKeyRef: name: app-config key: APP_ENV ```
Dynamic Updates
One of the most powerful features of ConfigMaps is their ability to update configuration dynamically:
- Most volume-mounted ConfigMaps update automatically (may take up to 1 minute)
- Environment variables require pod restart
- Use a sidecar container for more complex configuration updates
Secrets: Managing Sensitive Data
Kubernetes Secrets are essential for managing sensitive information like:
- Database credentials
- API keys
- TLS certificates
- OAuth tokens
Why Use Secrets?
- Security: Base64 encoding and optional encryption at rest
- Access Control: Fine-grained RBAC controls
- Integration: Native integration with pods and services
- Rotation: Easy secret rotation without rebuilding containers
Types of Secrets
- Opaque: Generic user-defined data
- kubernetes.io/tls: TLS certificates
- kubernetes.io/dockerconfigjson: Docker registry credentials
- kubernetes.io/service-account-token: Service account tokens
Here’s a comprehensive example:
# Create different types of secrets
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
# Base64 encoded values
db-password: cGFzc3dvcmQxMjM=
api-key: c2VjcmV0LWtleS0xMjM=
---
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: base64-encoded-cert
tls.key: base64-encoded-key
Best Practices for Secrets
- Never commit secrets to version control
- Use external secret management systems (HashiCorp Vault, AWS Secrets Manager)
- Implement secret rotation
- Limit secret access with RBAC
- Enable encryption at rest
Using Secrets in Pods
- As Environment Variables:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-env-pod
spec:
containers:
- name: app-container image: my-app:1.0 env:
- name: DB_PASSWORD valueFrom: secretKeyRef: name: app-secrets key: db-password ```
- As Volume Mounts:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: secret-volume-pod
spec:
containers:
- name: app-container image: my-app:1.0 volumeMounts:
- name: secret-volume mountPath: /etc/secrets readOnly: true volumes: - name: secret-volume secret: secretName: app-secrets ```
Resource Management
Proper resource management is crucial for:
- Application performance
- Cost optimization
- Cluster stability
- Fair resource sharing
Understanding Resource Types
- CPU
- Measured in cores or millicores (m)
- 1 core = 1000m
- Compressible resource (can be throttled)
- Memory
- Measured in bytes (Ki, Mi, Gi)
- Non-compressible resource (can’t be throttled)
- OOM killer terminates pods exceeding limits
- Ephemeral Storage
- Local storage for containers
- Temporary data, logs, etc.
Resource Requests vs Limits
Requests: Guaranteed minimum resources Limits: Maximum allowed resources
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
memory: "128Mi" # Guaranteed minimum
cpu: "250m" # 1/4 CPU core
limits:
memory: "256Mi" # Maximum allowed
cpu: "500m" # 1/2 CPU core
Resource Quotas
Resource Quotas help manage cluster resources at the namespace level:
- Compute Quotas:
apiVersion: v1 kind: ResourceQuota metadata: name: compute-quota spec: hard: requests.cpu: "4" requests.memory: "8Gi" limits.cpu: "8" limits.memory: "16Gi"
- Object Quotas:
apiVersion: v1 kind: ResourceQuota metadata: name: object-quota spec: hard: configmaps: "10" persistentvolumeclaims: "4" pods: "20" services: "10" services.loadbalancers: "2"
Best Practices for Resource Management
- Always Set Requests and Limits
- Prevents resource starvation
- Enables better scheduling
- Improves cluster stability
- Monitor Resource Usage
- Use tools like Prometheus and Grafana
- Track historical usage patterns
- Set up alerts for resource pressure
- Implement Horizontal Pod Autoscaling
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: app-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-app minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 80
Advanced Deployment Strategies
Choosing the right deployment strategy is crucial for maintaining application availability and user experience. Let’s explore the main strategies:
1. Rolling Updates (Default)
Rolling updates gradually replace old pods with new ones, ensuring zero downtime.
Benefits:
- Zero downtime deployments
- Automatic rollback capability
- Gradual traffic migration
- No additional resource overhead
apiVersion: apps/v1
kind: Deployment
metadata:
name: rolling-demo
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # How many pods above desired count
maxUnavailable: 1 # How many pods can be unavailable
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:2.0
readinessProbe: # Important for rolling updates
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
2. Blue-Green Deployments
Run two identical environments, switching traffic from blue (current) to green (new) all at once.
Benefits:
- Instant rollback capability
- Zero downtime
- Testing in production environment
- Simplified rollback process
# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-blue
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: blue
template:
metadata:
labels:
app: my-app
version: blue
spec:
containers:
- name: app
image: my-app:1.0
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-green
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: green
template:
metadata:
labels:
app: my-app
version: green
spec:
containers:
- name: app
image: my-app:2.0
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
version: blue # Switch to green when ready
ports:
- port: 80
targetPort: 8080
3. Canary Deployments
Gradually route traffic to the new version, testing it with a small subset of users.
Benefits:
- Risk mitigation
- A/B testing capability
- Gradual rollout
- Early problem detection
# Main deployment (90% of traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-stable
spec:
replicas: 9 # 90% of pods
template:
metadata:
labels:
app: my-app
version: stable
spec:
containers:
- name: app
image: my-app:1.0
---
# Canary deployment (10% of traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-canary
spec:
replicas: 1 # 10% of pods
template:
metadata:
labels:
app: my-app
version: canary
spec:
containers:
- name: app
image: my-app:2.0
---
# Service (routes to both deployments)
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app # Routes to both versions
ports:
- port: 80
Hands-on Exercise: Complete Application Setup
Let’s put it all together with a real-world example that incorporates all the concepts we’ve covered:
# complete-app.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: production
CACHE_TTL: "3600"
app.properties: |
log.level=info
feature.flags.enabled=true
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
db-password: base64-encoded-password
api-key: base64-encoded-key
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: complete-app
spec:
replicas: 3
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: complete-app
spec:
containers:
- name: app
image: my-app:1.0
resources:
requests:
cpu: "250m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: db-password
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
---
apiVersion: v1
kind: Service
metadata:
name: complete-app
spec:
selector:
app: complete-app
ports:
- port: 80
targetPort: 8080
What’s Next?
In our next post, we’ll explore advanced Kubernetes topics including:
- Service Mesh with Istio
- Monitoring and Observability
- Cluster Autoscaling
- Custom Resource Definitions (CRDs)
- Operators and Custom Controllers
Additional Resources
- Kubernetes Official Documentation on ConfigMaps
- Kubernetes Secrets Best Practices
- Resource Management Guide
- Deployment Strategies Explained
Remember to join our community on Discord for questions and discussions about Kubernetes deployments and configurations!