Skip to main content

Managing Environments

Learn how to effectively manage multiple environments (development, staging, production) using KubeZero's modular approach and GitOps principles.

Environment Strategy Overview

KubeZero supports multiple environment management strategies:

  1. Virtual Cluster Environments: Lightweight isolation within a single cluster
  2. Namespace-Based Environments: Traditional Kubernetes namespace separation
  3. Cluster-Based Environments: Complete cluster isolation per environment
  4. Hybrid Approaches: Combining multiple strategies

Virtual Cluster Environments

Virtual clusters provide the best balance of isolation and resource efficiency.

Creating Virtual Environments

# modules/vcluster-environment/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

helmCharts:
- name: vcluster
repo: https://charts.loft.sh
version: 0.15.0
namespace: vcluster-dev
releaseName: dev-environment
valuesFile: values-dev.yaml

resources:
- namespace.yaml
- rbac.yaml
# modules/vcluster-environment/values-dev.yaml
vcluster:
image: rancher/k3s:v1.28.2-k3s1

storage:
size: 5Gi
className: fast-ssd

networking:
advanced:
clusterDomain: "cluster.local"
fallbackHostCluster: false

rbac:
clusterRole:
create: true

nodeSelector:
environment: development

tolerations:
- key: "development"
operator: "Equal"
value: "true"
effect: "NoSchedule"

resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi

Environment-Specific Configurations

Create configurations for each environment:

# Directory structure
environments/
├── development/
│ ├── kustomization.yaml
│ ├── vcluster-config.yaml
│ └── app-overrides/
├── staging/
│ ├── kustomization.yaml
│ ├── vcluster-config.yaml
│ └── app-overrides/
└── production/
├── kustomization.yaml
├── vcluster-config.yaml
└── app-overrides/
# environments/development/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: vcluster-dev

resources:
- ../../modules/vcluster-environment
- ../../stacks/application-stack/manifests

patches:
- target:
kind: VCluster
name: dev-environment
patch: |-
- op: replace
path: /spec/resources/limits/cpu
value: "500m"
- op: replace
path: /spec/resources/limits/memory
value: "1Gi"

- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 1
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: ENVIRONMENT
value: "development"

Accessing Virtual Clusters

# Install vCluster CLI
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
sudo install -c -m 0755 vcluster /usr/local/bin

# Connect to development virtual cluster
vcluster connect dev-environment -n vcluster-dev

# Use kubectl with the virtual cluster
kubectl get pods
kubectl apply -f my-app.yaml

# Disconnect
vcluster disconnect

Namespace-Based Environments

For simpler setups or when virtual clusters aren't needed.

Environment Namespaces

# stacks/multi-environment/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../../modules/my-application

commonLabels:
app.kubernetes.io/part-of: my-platform
# stacks/multi-environment/overlays/development/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: development

resources:
- ../../base

namePrefix: dev-

patches:
- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 1
- op: replace
path: /spec/template/spec/containers/0/resources/requests/cpu
value: "100m"
- op: replace
path: /spec/template/spec/containers/0/resources/requests/memory
value: "128Mi"

configMapGenerator:
- name: app-config
literals:
- ENVIRONMENT=development
- LOG_LEVEL=debug
- FEATURE_FLAGS=experimental-features
# stacks/multi-environment/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: production

resources:
- ../../base

namePrefix: prod-

patches:
- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 5
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: ENVIRONMENT
value: "production"
- op: replace
path: /spec/template/spec/containers/0/resources/requests/cpu
value: "500m"
- op: replace
path: /spec/template/spec/containers/0/resources/requests/memory
value: "512Mi"

configMapGenerator:
- name: app-config
literals:
- ENVIRONMENT=production
- LOG_LEVEL=info
- FEATURE_FLAGS=stable-features

Cluster-Based Environments

For maximum isolation and compliance requirements.

Multi-Cluster Setup

# registry/clusters/management/_gitops.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: environment-clusters
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: development
url: https://dev-cluster.example.com
namespace: default
values:
replicas: 1
resources:
requests:
cpu: 100m
memory: 128Mi
- cluster: staging
url: https://staging-cluster.example.com
namespace: default
values:
replicas: 3
resources:
requests:
cpu: 200m
memory: 256Mi
- cluster: production
url: https://prod-cluster.example.com
namespace: default
values:
replicas: 5
resources:
requests:
cpu: 500m
memory: 512Mi
template:
metadata:
name: '{{cluster}}-applications'
spec:
project: multi-cluster
source:
repoURL: https://github.com/company/applications
targetRevision: HEAD
path: environments/{{cluster}}
destination:
server: '{{url}}'
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true

Configuration Management

Environment-Specific Secrets

Use External Secrets Operator for environment-specific secrets:

# environments/development/secrets.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: development
spec:
refreshInterval: 15s
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
data:
- secretKey: database-url
remoteRef:
key: secret/development/myapp
property: database_url
- secretKey: api-key
remoteRef:
key: secret/development/myapp
property: api_key
# environments/production/secrets.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 1h # Less frequent refresh for production
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
data:
- secretKey: database-url
remoteRef:
key: secret/production/myapp
property: database_url
- secretKey: api-key
remoteRef:
key: secret/production/myapp
property: api_key

Configuration Hierarchy

Implement a configuration hierarchy for different environments:

# config/base/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Base configuration
app.yaml: |
server:
port: 8080
timeout: 30s
logging:
format: json
features:
metrics: true
health_checks: true
# config/development/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Development overrides
app.yaml: |
server:
port: 8080
timeout: 30s
logging:
level: debug
format: json
features:
metrics: true
health_checks: true
debug_endpoints: true
mock_external_services: true
# config/production/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Production configuration
app.yaml: |
server:
port: 8080
timeout: 10s
logging:
level: info
format: json
features:
metrics: true
health_checks: true
debug_endpoints: false
security_headers: true

GitOps Environment Promotion

Automated Promotion Pipeline

# .github/workflows/promote-environments.yaml
name: Environment Promotion
on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
deploy-development:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Development
run: |
# Update development environment
kubectl apply -k environments/development/

test-staging:
needs: deploy-development
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Staging
run: |
kubectl apply -k environments/staging/
- name: Run Integration Tests
run: |
# Run tests against staging
npm run test:integration

deploy-production:
needs: test-staging
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Deploy to Production
run: |
kubectl apply -k environments/production/

Manual Promotion with ArgoCD

# argocd/promotion-workflow.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: staging-promotion
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/applications
targetRevision: HEAD
path: environments/staging
destination:
server: https://kubernetes.default.svc
namespace: staging
syncPolicy:
automated:
prune: false # Manual approval required
selfHeal: false
syncOptions:
- CreateNamespace=true

Environment Monitoring

Environment-Specific Monitoring

# monitoring/environment-dashboards.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: environment-dashboard
data:
dashboard.json: |
{
"dashboard": {
"title": "Environment Overview",
"panels": [
{
"title": "Application Health by Environment",
"targets": [
{
"expr": "up{job=\"my-app\"} by (environment)",
"legendFormat": "{{environment}}"
}
]
},
{
"title": "Request Rate by Environment",
"targets": [
{
"expr": "rate(http_requests_total[5m]) by (environment)",
"legendFormat": "{{environment}}"
}
]
}
]
}
}

Alerting Rules

# monitoring/alerts.yaml
groups:
- name: environment.rules
rules:
- alert: DevelopmentEnvironmentDown
expr: up{job="my-app",environment="development"} == 0
for: 5m
labels:
severity: warning
environment: development
annotations:
summary: "Development environment is down"

- alert: ProductionEnvironmentDown
expr: up{job="my-app",environment="production"} == 0
for: 1m
labels:
severity: critical
environment: production
annotations:
summary: "Production environment is down"
runbook_url: "https://wiki.company.com/runbooks/production-outage"

Environment Lifecycle Management

Creating New Environments

Script to create new environments:

#!/bin/bash
# create-environment.sh

ENVIRONMENT_NAME=$1
CLUSTER_TYPE=$2 # vcluster, namespace, or cluster

if [ -z "$ENVIRONMENT_NAME" ] || [ -z "$CLUSTER_TYPE" ]; then
echo "Usage: $0 <environment-name> <cluster-type>"
exit 1
fi

case $CLUSTER_TYPE in
"vcluster")
echo "Creating vCluster environment: $ENVIRONMENT_NAME"

# Create vCluster configuration
mkdir -p environments/$ENVIRONMENT_NAME
cat > environments/$ENVIRONMENT_NAME/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: vcluster-$ENVIRONMENT_NAME

resources:
- ../../modules/vcluster-environment
- ../../stacks/application-stack/manifests

namePrefix: ${ENVIRONMENT_NAME}-

patches:
- target:
kind: VCluster
name: environment
patch: |-
- op: replace
path: /metadata/name
value: $ENVIRONMENT_NAME
EOF
;;

"namespace")
echo "Creating namespace environment: $ENVIRONMENT_NAME"

mkdir -p environments/$ENVIRONMENT_NAME
cat > environments/$ENVIRONMENT_NAME/kustomization.yaml <<EOF
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: $ENVIRONMENT_NAME

resources:
- namespace.yaml
- ../../stacks/application-stack/manifests

namePrefix: ${ENVIRONMENT_NAME}-
EOF

cat > environments/$ENVIRONMENT_NAME/namespace.yaml <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: $ENVIRONMENT_NAME
labels:
environment: $ENVIRONMENT_NAME
EOF
;;

"cluster")
echo "Creating cluster environment: $ENVIRONMENT_NAME"
echo "Please provision cluster manually and update ArgoCD configuration"
;;

*)
echo "Invalid cluster type. Use: vcluster, namespace, or cluster"
exit 1
;;
esac

# Create ArgoCD application
cat > argocd/applications/$ENVIRONMENT_NAME.yaml <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: $ENVIRONMENT_NAME
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/applications
targetRevision: HEAD
path: environments/$ENVIRONMENT_NAME
destination:
server: https://kubernetes.default.svc
namespace: $ENVIRONMENT_NAME
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
EOF

echo "Environment $ENVIRONMENT_NAME created successfully!"
echo "Apply with: kubectl apply -f argocd/applications/$ENVIRONMENT_NAME.yaml"

Environment Cleanup

#!/bin/bash
# cleanup-environment.sh

ENVIRONMENT_NAME=$1

if [ -z "$ENVIRONMENT_NAME" ]; then
echo "Usage: $0 <environment-name>"
exit 1
fi

echo "Cleaning up environment: $ENVIRONMENT_NAME"

# Delete ArgoCD application
kubectl delete application $ENVIRONMENT_NAME -n argocd

# Delete environment resources
kubectl delete namespace $ENVIRONMENT_NAME
kubectl delete namespace vcluster-$ENVIRONMENT_NAME

# Remove configuration files
rm -rf environments/$ENVIRONMENT_NAME
rm -f argocd/applications/$ENVIRONMENT_NAME.yaml

echo "Environment $ENVIRONMENT_NAME cleaned up successfully!"

Best Practices

1. Environment Parity

Keep environments as similar as possible:

# Use the same base configuration
resources:
- ../../stacks/application-stack/base

# Only patch differences
patches:
- target:
kind: Deployment
name: my-app
patch: |-
- op: replace
path: /spec/replicas
value: 1 # Different per environment

2. Resource Management

Set appropriate resource limits per environment:

# Development - minimal resources
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi

# Production - generous resources
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi

3. Security Isolation

Implement proper security boundaries:

# Network policies for environment isolation
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: environment-isolation
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
environment: development
egress:
- to:
- namespaceSelector:
matchLabels:
environment: development

4. Configuration Management

Use a clear configuration hierarchy:

  1. Base configuration: Common to all environments
  2. Environment overlays: Environment-specific changes
  3. Secrets: Always external, never in Git
  4. Feature flags: Control features per environment

5. Promotion Strategy

Implement a clear promotion strategy:

Development → Staging → Production
↓ ↓ ↓
Automatic Semi-Auto Manual

Troubleshooting Environments

Common Issues

  1. Resource conflicts between environments

    # Check resource usage
    kubectl top nodes
    kubectl top pods --all-namespaces
  2. Configuration drift

    # Compare configurations
    kubectl diff -k environments/staging/
    argocd app diff staging
  3. Secret synchronization issues

    # Check External Secrets Operator
    kubectl get externalsecrets -A
    kubectl describe externalsecret app-secrets -n staging

Debugging Commands

# Check environment status
kubectl get applications -n argocd | grep $ENVIRONMENT_NAME

# View environment logs
kubectl logs -l app=my-app -n $ENVIRONMENT_NAME

# Check vCluster status
vcluster list
kubectl get pods -n vcluster-$ENVIRONMENT_NAME

# Compare environment configurations
kubectl diff -k environments/development/
kubectl diff -k environments/production/

Next Steps

Effective environment management is crucial for successful platform operations. Use these patterns and practices to create robust, scalable environment strategies with KubeZero.