Deployment Strategies - Chiến lược triển khai
Deployment Strategies là gì?
Deployment strategies là các phương pháp khác nhau để deploy new versions của applications lên production environments. Mỗi strategy có trade-offs riêng về downtime, risk, complexity, và resource usage.
Các loại Deployment Strategies
1. Recreate Deployment
Định nghĩa: Dừng toàn bộ old version, sau đó start new version.
Đặc điểm: - Có downtime - Đơn giản nhất - Resource requirements thấp - Phù hợp cho development environments
# recreate-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-recreate
spec:
replicas: 3
strategy:
type: Recreate
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: mycompany/user-service:2.0.0
ports:
- containerPort: 8080
2. Rolling Update Deployment
Định nghĩa: Gradually replace old pods với new pods, maintaining service availability.
Đặc điểm: - Zero downtime (nếu cấu hình đúng) - Default strategy trong Kubernetes - Slow rollout process - Mix của old và new versions trong quá trình deployment
# rolling-update-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-rolling
spec:
replicas: 6
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # Tối đa 1 pod unavailable
maxSurge: 2 # Tối đa 2 pods extra
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
version: v2.0.0
spec:
containers:
- name: user-service
image: mycompany/user-service:2.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
Rolling Update với Jenkins Pipeline:
pipeline {
agent any
stages {
stage('Deploy Rolling Update') {
steps {
script {
sh """
kubectl set image deployment/user-service \
user-service=mycompany/user-service:${BUILD_NUMBER} \
--record
kubectl rollout status deployment/user-service \
--timeout=600s
# Verify deployment
kubectl get pods -l app=user-service
# Health check
sleep 30
curl -f http://api.company.com/actuator/health
"""
}
}
}
}
post {
failure {
script {
sh "kubectl rollout undo deployment/user-service"
error "Deployment failed, rolled back to previous version"
}
}
}
}
3. Blue-Green Deployment
Định nghĩa: Maintain hai identical environments (Blue và Green). Deploy to idle environment, sau đó switch traffic.
Đặc điểm: - Zero downtime - Instant rollback capability - Double resource requirements - Full environment testing trước khi switch
# blue-green-service.yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
labels:
app: user-service
spec:
selector:
app: user-service
version: blue # Switch between 'blue' and 'green'
ports:
- port: 80
targetPort: 8080
---
# Blue Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-blue
labels:
app: user-service
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: user-service
version: blue
template:
metadata:
labels:
app: user-service
version: blue
spec:
containers:
- name: user-service
image: mycompany/user-service:1.0.0
ports:
- containerPort: 8080
---
# Green Deployment (New Version)
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-green
labels:
app: user-service
version: green
spec:
replicas: 3
selector:
matchLabels:
app: user-service
version: green
template:
metadata:
labels:
app: user-service
version: green
spec:
containers:
- name: user-service
image: mycompany/user-service:2.0.0
ports:
- containerPort: 8080
Blue-Green Deployment Script:
#!/bin/bash
# blue-green-deploy.sh
NEW_VERSION=$1
CURRENT_VERSION=$(kubectl get service user-service -o jsonpath='{.spec.selector.version}')
echo "Current version: $CURRENT_VERSION"
if [ "$CURRENT_VERSION" = "blue" ]; then
NEW_COLOR="green"
OLD_COLOR="blue"
else
NEW_COLOR="blue"
OLD_COLOR="green"
fi
echo "Deploying to $NEW_COLOR environment..."
# Update the deployment with new image
kubectl set image deployment/user-service-${NEW_COLOR} \
user-service=mycompany/user-service:${NEW_VERSION}
# Wait for rollout to complete
kubectl rollout status deployment/user-service-${NEW_COLOR} --timeout=600s
# Health check on new environment
echo "Performing health checks..."
kubectl port-forward deployment/user-service-${NEW_COLOR} 8080:8080 &
PF_PID=$!
sleep 10
if curl -f http://localhost:8080/actuator/health; then
echo "Health check passed. Switching traffic to $NEW_COLOR..."
# Switch service to point to new environment
kubectl patch service user-service -p '{"spec":{"selector":{"version":"'${NEW_COLOR}'"}}}'
echo "Traffic switched to $NEW_COLOR environment"
# Optionally scale down old environment
# kubectl scale deployment user-service-${OLD_COLOR} --replicas=0
else
echo "Health check failed. Keeping traffic on $OLD_COLOR"
exit 1
fi
kill $PF_PID
4. Canary Deployment
Định nghĩa: Deploy new version to small subset of users/traffic, gradually increase nếu metrics look good.
Đặc điểm: - Risk mitigation - Gradual rollout - Real user feedback - Complex traffic management - Requires monitoring
# canary-deployment.yaml
# Stable version (90% traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-stable
labels:
app: user-service
version: stable
spec:
replicas: 9 # 90% của traffic
selector:
matchLabels:
app: user-service
version: stable
template:
metadata:
labels:
app: user-service
version: stable
spec:
containers:
- name: user-service
image: mycompany/user-service:1.0.0
ports:
- containerPort: 8080
---
# Canary version (10% traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-canary
labels:
app: user-service
version: canary
spec:
replicas: 1 # 10% của traffic
selector:
matchLabels:
app: user-service
version: canary
template:
metadata:
labels:
app: user-service
version: canary
spec:
containers:
- name: user-service
image: mycompany/user-service:2.0.0
ports:
- containerPort: 8080
---
# Service pointing to both versions
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service # Both stable and canary
ports:
- port: 80
targetPort: 8080
Istio Canary với Virtual Service:
# istio-canary.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: user-service
spec:
http:
- match:
- headers:
canary:
exact: "true"
route:
- destination:
host: user-service
subset: canary
weight: 100
- route:
- destination:
host: user-service
subset: stable
weight: 90
- destination:
host: user-service
subset: canary
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: user-service
spec:
host: user-service
subsets:
- name: stable
labels:
version: stable
- name: canary
labels:
version: canary
Automated Canary với Flagger:
# flagger-canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: user-service
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: user-service
progressDeadlineSeconds: 60
service:
port: 80
targetPort: 8080
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 30s
webhooks:
- name: acceptance-test
type: pre-rollout
url: http://flagger-loadtester.test/
timeout: 30s
metadata:
type: bash
cmd: "curl -sd 'test' http://user-service-canary/api/users/health"
- name: load-test
url: http://flagger-loadtester.test/
timeout: 5s
metadata:
cmd: "hey -z 1m -q 10 -c 2 http://user-service-canary/"
5. A/B Testing Deployment
Định nghĩa: Deploy multiple versions simultaneously để test different features với different user groups.
# ab-testing-deployment.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: user-service-ab
spec:
http:
- match:
- headers:
user-type:
exact: "premium"
route:
- destination:
host: user-service
subset: version-a
weight: 100
- match:
- headers:
region:
exact: "us-west"
route:
- destination:
host: user-service
subset: version-b
weight: 100
- route:
- destination:
host: user-service
subset: version-a
weight: 50
- destination:
host: user-service
subset: version-b
weight: 50
Database Migration Strategies
Backward Compatible Migrations
// Version 1.0.0 - Original schema
@Entity
public class User {
@Id
private Long id;
private String email;
private String password;
// getters/setters
}
// Version 2.0.0 - Add new field (backward compatible)
@Entity
public class User {
@Id
private Long id;
private String email;
private String password;
@Column(nullable = true) // Nullable cho backward compatibility
private String firstName;
@Column(nullable = true)
private String lastName;
// getters/setters
}
Database Migration with Flyway
-- V2__add_user_names.sql
ALTER TABLE users
ADD COLUMN first_name VARCHAR(100) NULL,
ADD COLUMN last_name VARCHAR(100) NULL;
-- Update existing records with default values
UPDATE users
SET first_name = 'Unknown', last_name = 'User'
WHERE first_name IS NULL OR last_name IS NULL;
Zero-Downtime Database Changes
# Phase 1: Deploy app version that can handle both old and new schema
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-migration-phase1
spec:
replicas: 3
template:
spec:
containers:
- name: user-service
image: mycompany/user-service:1.5.0 # Supports both schemas
env:
- name: SPRING_PROFILES_ACTIVE
value: "migration-phase1"
// Application code for migration phase
@Service
public class UserService {
public User createUser(CreateUserRequest request) {
User user = new User();
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword()));
// Handle both old and new schema
if (request.getFirstName() != null) {
user.setFirstName(request.getFirstName());
}
if (request.getLastName() != null) {
user.setLastName(request.getLastName());
}
return userRepository.save(user);
}
// Gracefully handle missing fields
public UserResponse toResponse(User user) {
UserResponse response = new UserResponse();
response.setId(user.getId());
response.setEmail(user.getEmail());
// Provide defaults if fields are null
response.setFirstName(user.getFirstName() != null ?
user.getFirstName() : "Unknown");
response.setLastName(user.getLastName() != null ?
user.getLastName() : "User");
return response;
}
}
CI/CD Pipeline với Multiple Strategies
GitHub Actions với Strategy Selection
# .github/workflows/deploy.yml
name: Deploy with Strategy
on:
push:
branches: [ main ]
env:
DEPLOYMENT_STRATEGY: ${{ github.event.inputs.strategy || 'rolling' }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Deploy Rolling Update
if: env.DEPLOYMENT_STRATEGY == 'rolling'
run: |
kubectl set image deployment/user-service \
user-service=mycompany/user-service:${{ github.sha }}
kubectl rollout status deployment/user-service
- name: Deploy Blue-Green
if: env.DEPLOYMENT_STRATEGY == 'blue-green'
run: |
./scripts/blue-green-deploy.sh ${{ github.sha }}
- name: Deploy Canary
if: env.DEPLOYMENT_STRATEGY == 'canary'
run: |
kubectl apply -f k8s/canary/
kubectl set image deployment/user-service-canary \
user-service=mycompany/user-service:${{ github.sha }}
ArgoCD với Multiple Environments
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service-prod
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/user-service
targetRevision: HEAD
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
Monitoring Deployments
Prometheus Metrics cho Deployments
// Java application metrics
@Component
public class DeploymentMetrics {
private final Counter deploymentCounter;
private final Gauge applicationVersion;
private final Timer deploymentDuration;
public DeploymentMetrics(MeterRegistry meterRegistry) {
this.deploymentCounter = Counter.builder("application.deployments.total")
.description("Total number of deployments")
.tag("strategy", "rolling") // or blue-green, canary
.register(meterRegistry);
this.applicationVersion = Gauge.builder("application.version.info")
.description("Application version information")
.register(meterRegistry, this, DeploymentMetrics::getVersionNumber);
this.deploymentDuration = Timer.builder("application.deployment.duration")
.description("Deployment duration")
.register(meterRegistry);
}
@EventListener
public void handleDeploymentStart(DeploymentStartEvent event) {
deploymentCounter.increment();
// Start timing
}
private double getVersionNumber() {
String version = System.getenv("APP_VERSION");
// Convert version to numeric for Prometheus
return version != null ? parseVersion(version) : 0.0;
}
}
Grafana Dashboard cho Deployments
{
"dashboard": {
"title": "Deployment Monitoring",
"panels": [
{
"title": "Deployment Frequency",
"type": "stat",
"targets": [
{
"expr": "increase(application_deployments_total[24h])",
"legendFormat": "Deployments/Day"
}
]
},
{
"title": "Deployment Success Rate",
"type": "stat",
"targets": [
{
"expr": "rate(application_deployments_total{status=\"success\"}[24h]) / rate(application_deployments_total[24h]) * 100",
"legendFormat": "Success Rate %"
}
]
},
{
"title": "Error Rate During Deployment",
"type": "graph",
"targets": [
{
"expr": "rate(http_server_requests_seconds_count{status=~\"5..\"}[5m])",
"legendFormat": "5xx Error Rate"
}
]
}
]
}
}
Best Practices
1. Strategy Selection
- Development: Recreate (simple, cost-effective)
- Staging: Rolling update (matches production)
- Production: Blue-green hoặc canary (based on risk tolerance)
2. Health Checks
- Implement comprehensive health checks
- Use startup, liveness, và readiness probes
- Include dependency health checks
3. Rollback Strategy
- Always have rollback plan
- Automate rollback triggers
- Test rollback procedures regularly
4. Database Migrations
- Use backward-compatible changes
- Separate schema changes từ application deployment
- Test migrations thoroughly
5. Monitoring và Alerting
- Monitor key metrics during deployments
- Set up alerts cho deployment failures
- Track deployment frequency và success rate
Deployment strategies are critical cho maintaining high availability và reducing deployment risks trong production environments.