Automated Application Deployment
# Automated Application Deployment ## Introduction Automated application deployment eliminates manual steps in releasing software, reducing errors, increasing deployment frequency, and enabling faster feedback loops. This tutorial covers deployment strategies, pipeline automation, container-based deployment, rollback procedures, and production deployment patterns. ## Learning Objectives By the end of this tutorial, you will be able to: - Design automated deployment pipelines - Implement blu
# Automated Application Deployment
Introduction
Automated application deployment eliminates manual steps in releasing software, reducing errors, increasing deployment frequency, and enabling faster feedback loops. This tutorial covers deployment strategies, pipeline automation, container-based deployment, rollback procedures, and production deployment patterns.
Learning Objectives
By the end of this tutorial, you will be able to:
- Design automated deployment pipelines
- Implement blue-green, canary, and rolling deployment strategies
- Deploy containerized applications with Docker and Kubernetes
- Implement rollback procedures for failed deployments
- Use feature flags for gradual rollouts
- Automate database migrations
- Secure deployment pipelines
Technical Background
Deployment Strategies
flowchart TD
Deploy[Deployment] --> Rolling[Rolling Update]
Deploy --> BlueGreen[Blue-Green]
Deploy --> Canary[Canary]
Rolling -->|Gradual replacement| New[New Version]
BlueGreen -->|Switch traffic| Traffic[Traffic Switch]
Canary -->|Small percentage| CanaryTraffic[Canary Traffic]
subgraph Strategies
Rolling
BlueGreen
Canary
end| Strategy | Description | Risk | Rollback Speed | |----------|-------------|------|----------------| | Rolling | Replace instances gradually | Low | Fast | | Blue-Green | Switch traffic between environments | Very Low | Instant | | Canary | Route small % traffic to new version | Lowest | Fast | | Recreate | Stop old, start new | High | Slow |
Deployment Pipeline
Commit --> Build --> Test --> Package --> Deploy Staging --> Test Staging --> Approve --> Deploy Production --> MonitorPrerequisites
- Containerized application (Docker images)
- Container registry (Docker Hub, ECR, ACR, GCR)
- Target platform (Kubernetes, ECS, or VMs)
- CI/CD platform (Jenkins, GitHub Actions, GitLab CI)
- Database migration tool
Hardware and Software Requirements
| Component | Requirement | |-----------|-------------| | Container Runtime | Docker | | Orchestration | Kubernetes, ECS, or similar | | Registry | Docker Hub, ECR, ACR, or GCR | | CI/CD Platform | Jenkins, GitHub Actions, GitLab CI | | Load Balancer | NGINX, AWS ALB, or cloud LB |
Step-by-Step Implementation
Phase 1: Containerize Application
#### Dockerfile
# Multi-stage build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S nodejs && adduser -S nextjs -G nodejs
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]#### Build and Push Image
# Build image
docker build -t myregistry.com/myapp:${BUILD_NUMBER} .
# Push to registry
docker push myregistry.com/myapp:${BUILD_NUMBER}
docker push myregistry.com/myapp:latestPhase 2: Kubernetes Deployment Manifests
#### Deployment with Rolling Update
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: production
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: myregistry.com/myapp:v1.2.3
ports:
- containerPort: 3000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: production
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 3000
type: LoadBalancerPhase 3: Blue-Green Deployment
# k8s/blue-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-blue
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: blue
template:
metadata:
labels:
app: my-app
version: blue
spec:
containers:
- name: my-app
image: myregistry.com/myapp:v1.2.3
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-green
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: green
template:
metadata:
labels:
app: my-app
version: green
spec:
containers:
- name: my-app
image: myregistry.com/myapp:v1.2.4
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: production
spec:
selector:
app: my-app
version: blue
ports:
- port: 80
targetPort: 3000#### Switch Traffic
# Switch to green
kubectl patch service my-app -n production \
-p '{"spec":{"selector":{"version":"green"}}}'
# Verify green is healthy
kubectl rollout status deployment/my-app-green -n production
# Scale down blue after verification
kubectl scale deployment my-app-blue -n production --replicas=0Phase 4: Canary Deployment
#### Canary with Argo Rollouts
# k8s/rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: my-app-rollout
namespace: production
spec:
replicas: 5
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 5m}
- setWeight: 100
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: myregistry.com/myapp:v1.2.4Phase 5: Automated Deployment Pipeline
#### GitHub Actions Deployment
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
docker build -t myregistry.com/myapp:${{ github.sha }} .
docker push myregistry.com/myapp:${{ github.sha }}
- name: Deploy to staging
run: |
kubectl set image deployment/my-app \
my-app=myregistry.com/myapp:${{ github.sha }} \
-n staging
kubectl rollout status deployment/my-app -n staging --timeout=300s
- name: Run smoke tests
run: |
curl -f https://staging.myapp.com/health || exit 1
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Blue-green deploy
run: |
# Deploy to green
kubectl apply -f k8s/green.yaml
kubectl rollout status deployment/my-app-green -n production --timeout=300s
# Smoke test green
curl -f https://green.myapp.com/health || exit 1
# Switch traffic
kubectl patch service my-app -n production \
-p '{"spec":{"selector":{"version":"green"}}}'Phase 6: Database Migrations
#### Migration Script
-- migrations/001_create_users.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);#### Migration with Flyway
# Run migrations
flyway -url=jdbc:postgresql://db:5432/app \
-user=app_user \
-password=${DB_PASSWORD} \
migrate#### Migration in Deployment Pipeline
- name: Run database migrations
run: |
kubectl create job --from=cronjob/db-migration \
db-migration-${{ github.sha }}
kubectl wait --for=condition=complete \
job/db-migration-${{ github.sha }} \
--timeout=300sPhase 7: Feature Flags
#### LaunchDarkly Integration
// Application code
const ldClient = LaunchDarkly.initialize('client-side-id');
if (ldClient.variation('new-checkout-flow', false)) {
renderNewCheckout();
} else {
renderOldCheckout();
}#### Deployment with Feature Flags
- name: Enable feature flag for canary
run: |
curl -X POST https://app.launchdarkly.com/api/v2/flags/my-project/new-checkout \
-H "Authorization: ${LD_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"variations": {"on": true, "off": false}}'Phase 8: Rollback Procedures
#### Kubernetes Rollback
# View rollout history
kubectl rollout history deployment/my-app -n production
# Rollback to previous revision
kubectl rollout undo deployment/my-app -n production
# Rollback to specific revision
kubectl rollout undo deployment/my-app -n production --to-revision=3
# Check rollout status
kubectl rollout status deployment/my-app -n production#### Automated Rollback in Pipeline
- name: Deploy with rollback on failure
run: |
kubectl set image deployment/my-app \
my-app=myregistry.com/myapp:${{ github.sha }} \
-n production
if ! kubectl rollout status deployment/my-app -n production --timeout=300s; then
echo "Deployment failed, rolling back..."
kubectl rollout undo deployment/my-app -n production
exit 1
fiExpected Output
- Containerized application deployed to Kubernetes
- Automated deployment pipeline with quality gates
- Blue-green or canary deployment strategy implemented
- Automated database migrations
- Rollback capability for failed deployments
- Feature flags for gradual rollouts
Verification Procedures
| Check | Method | Expected Result | |-------|--------|-----------------| | Image build | `docker build` | Image built successfully | | Image push | `docker push` | Image in registry | | Deployment | `kubectl rollout status` | Deployment successful | | Health check | `curl /health` | Returns 200 OK | | Rollback | `kubectl rollout undo` | Previous version restored | | Smoke test | Run test suite | All tests pass |
Troubleshooting Scenarios
| Issue | Diagnosis | Resolution | |-------|-----------|------------| | ImagePullBackOff | Wrong image tag or registry auth | Verify image tag; check registry credentials | | CrashLoopBackOff | Application crashing on startup | Check application logs; fix configuration | | Deployment stuck | Readiness probe failing | Fix application; increase probe timeout | | Rollback fails | Previous revision not available | Maintain revision history | | Database migration fails | Migration script error | Fix migration; run manually if needed | | Canary metrics bad | New version has issues | Pause rollout; rollback canary |
Best Practices
- **Deploy small changes:** Smaller deployments are easier to rollback
- **Automate everything:** Manual steps introduce errors
- **Test in production-like environment:** Staging should match production
- **Use feature flags:** Enable gradual rollouts and quick rollbacks
- **Monitor during deployment:** Watch metrics and logs during rollout
- **Have rollback plan:** Test rollback procedures regularly
- **Version everything:** Application code, infrastructure, configuration
- **Deploy during business hours:** Team available to respond to issues
Security Considerations
- **Image scanning:** Scan container images for vulnerabilities
- **Runtime security:** Use Kubernetes Pod Security Policies or OPA Gatekeeper
- **Secret management:** Store secrets in Kubernetes secrets or external secret manager
- **Network policies:** Restrict pod-to-pod communication
- **Pipeline security:** Restrict who can trigger production deployments
- **Supply chain security:** Verify base images and dependencies
Conclusion
Automated application deployment enables teams to release software frequently, reliably, and with minimal risk. By implementing containerized deployments, automated pipelines, blue-green/canary strategies, database migrations, and rollback procedures, organizations can achieve continuous delivery. The key is to automate consistently, test thoroughly, and always be ready to rollback.
References
- Kubernetes Deployments: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Argo Rollouts: https://argoproj.github.io/argo-rollouts/
- Docker Best Practices: https://docs.docker.com/develop/dev-best-practices/
- Feature Flags: https://martinfowler.com/articles/feature-toggles.html
- Blue-Green Deployment: https://martinfowler.com/bliki/BlueGreenDeployment.html
- Canary Releases: https://martinfowler.com/bliki/CanaryRelease.html