Deploying Applications on Cloud Infrastructure

3 Nov 2026, 19:0915 min readby ITYantra Admin

# Deploying Applications on Cloud Infrastructure ## Introduction Deploying applications on cloud infrastructure requires a different approach than traditional data center deployments. Cloud environ

# Deploying Applications on Cloud Infrastructure

Introduction

Deploying applications on cloud infrastructure requires a different approach than traditional data center deployments. Cloud environments enable automated provisioning, elastic scaling, and rapid iteration through CI/CD pipelines, containerization, and infrastructure as code.

This tutorial covers application deployment strategies on cloud infrastructure, including CI/CD pipelines, containerization with Docker and Kubernetes, serverless deployment, blue-green and canary deployments, infrastructure as code, and deployment best practices.

By the end of this guide, you will be able to deploy and manage applications on cloud infrastructure using modern DevOps practices.

Technical Background

Deployment Strategies

| Strategy | Description | Risk | Downtime | Rollback Speed | |----------|-------------|------|----------|----------------| | Recreate | Stop old, start new | High | Yes | Slow | | Rolling | Replace instances gradually | Medium | No | Medium | | Blue-Green | Switch traffic between environments | Low | No | Fast | | Canary | Route small % traffic to new version | Low | No | Fast | | A/B Testing | Route traffic based on user segments | Low | No | Fast |

Cloud Deployment Models

| Model | Description | Best For | |-------|-------------|----------| | Lift-and-Shift | Move VMs as-is to cloud | Legacy migration | | Containerize | Package apps in containers | Microservices migration | | Refactor | Modify app for cloud-native | Cloud optimization | | Rebuild | Rewrite app using cloud services | New development | | Replace | Replace with SaaS | Non-differentiating workloads |

CI/CD Pipeline Stages

Code Commit → Build → Test → Security Scan → Package → Deploy to Staging → Integration Test → Deploy to Production → Monitor

Prerequisites

  • Cloud provider account
  • Version control repository (Git)
  • Container registry (Docker Hub, ECR, ACR, GCR)
  • CI/CD platform (GitHub Actions, GitLab CI, Jenkins, Azure DevOps)
  • Understanding of containers and orchestration

Architecture

CI/CD Pipeline Architecture

graph LR
    subgraph Develop [Development]
        Code[Code Commit]
        Build[Build]
        Test[Unit Tests]
    end
    
    subgraph Package [Package]
        Image[Container Image Build]
        Scan[Security Scan]
        Push[Push to Registry]
    end
    
    subgraph Staging [Staging Environment]
        DeployStaging[Deploy to Staging]
        TestStaging[Integration Tests]
    end
    
    subgraph Production [Production Environment]
        Approval[Manual Approval]
        DeployProd[Deploy to Production]
        Verify[Smoke Tests]
        Monitor[Monitoring]
    end
    
    Code --> Build --> Test --> Image --> Scan --> Push --> DeployStaging --> TestStaging --> Approval --> DeployProd --> Verify --> Monitor

Blue-Green Deployment Architecture

Traffic Router
     │
     ├──▶ Blue Environment (v1.0) ──▶ Active
     │
     └──▶ Green Environment (v2.0) ──▶ Standby
                          │
                          ◀── Switch traffic after validation

Canary Deployment Architecture

Traffic Router
     │
     ├── 95% ──▶ Stable Version (v1.0)
     │
     └── 5% ──▶ Canary Version (v2.0)
                    │
                    ◀── Monitor metrics, then increase %

Step-by-Step Implementation

Step 1: Containerize Application

**Purpose**: Package application in Docker container for cloud deployment.

**Dockerfile Example**:

# Multi-stage build for Node.js application
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 --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

**Commands**:

# Build Docker image
docker build -t my-company/web-app:1.0.0 .
docker build -t my-company/web-app:latest .

# Test container locally
docker run -d -p 3000:3000 --name web-app-test my-company/web-app:1.0.0

# Push to container registry
docker tag my-company/web-app:1.0.0 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app:1.0.0
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app:1.0.0
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app:latest

# Verify image in registry
aws ecr describe-images --repository-name web-app

**Expected output**: Container image built, tested, and pushed to registry.

**Verification**:

  • Container runs locally and responds on port 3000
  • Image pushed to registry successfully
  • Image scan results available (if configured)

Step 2: Create CI/CD Pipeline

**Purpose**: Automate build, test, and deployment processes.

**GitHub Actions Example** (`.github/workflows/deploy.yml`):

name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: 123456789012.dkr.ecr.us-east-1.amazonaws.com
  IMAGE_NAME: web-app

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
        
      - name: Log in to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
        
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          
      - name: Run unit tests
        run: |
          docker run ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} npm test
          
      - name: Run security scan
        run: |
          docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
            aquasec/trivy:latest image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
            
  deploy-staging:
    needs: build-and-test
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy to staging
        run: |
          aws ecs update-service --cluster staging --service web-app --force-new-deployment
          
  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to production (blue-green)
        run: |
          ./scripts/blue-green-deploy.sh ${{ github.sha }}

**Expected output**: Automated pipeline builds, tests, and deploys application on code changes.

**Verification**:

  • Pipeline runs on code push
  • Build succeeds
  • Tests pass
  • Application deployed to staging and production

Step 3: Deploy to Kubernetes

**Purpose**: Deploy containerized application on Kubernetes cluster.

**Kubernetes Manifest Example** (`deployment.yaml`):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
    version: v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
        version: v1
    spec:
      containers:
      - name: web-app
        image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app:1.0.0
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: web-app
spec:
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: LoadBalancer
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

**Commands**:

# Apply manifests
kubectl apply -f deployment.yaml

# Check deployment status
kubectl rollout status deployment/web-app

# Check pods
kubectl get pods -l app=web-app

# Check service
kubectl get service web-app

# Scale deployment
kubectl scale deployment web-app --replicas=5

# Update image
kubectl set image deployment/web-app web-app=123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app:1.1.0

# Rollback if needed
kubectl rollout undo deployment/web-app

**Expected output**: Application deployed on Kubernetes with load balancing and auto-scaling.

**Verification**:

  • Pods running and ready
  • Service endpoint accessible
  • Auto-scaling based on CPU utilization
  • Health probes passing

Step 4: Implement Blue-Green Deployment

**Purpose**: Deploy new version with zero downtime and instant rollback.

**Blue-Green Deployment Script** (`scripts/blue-green-deploy.sh`):

#!/bin/bash
set -e

IMAGE_TAG=$1
CURRENT_COLOR=$(kubectl get service web-app -o jsonpath='{.spec.selector.color}')
NEW_COLOR="green"

if [ "$CURRENT_COLOR" = "green" ]; then
    NEW_COLOR="blue"
fi

echo "Deploying $IMAGE_TAG to $NEW_COLOR environment"

# Deploy new version to inactive environment
kubectl set image deployment/web-app-$NEW_COLOR web-app=$IMAGE_TAG
kubectl rollout status deployment/web-app-$NEW_COLOR --timeout=300s

# Run smoke tests against new environment
kubectl run smoke-test --image=curlimages/curl --rm -i --restart=Never -- \
    curl -f http://web-app-$NEW_COLOR:3000/health || exit 1

# Switch traffic to new environment
kubectl patch service web-app -p "{\"spec\":{\"selector\":{\"color\":\"$NEW_COLOR\"}}}"

echo "Traffic switched to $NEW_COLOR environment with version $IMAGE_TAG"

# Keep old environment for quick rollback (don't delete immediately)
echo "Previous environment ($CURRENT_COLOR) retained for rollback"

**Expected output**: New version deployed to inactive environment, traffic switched after validation.

**Verification**:

  • New version running in inactive environment
  • Smoke tests pass
  • Traffic switched to new version
  • Application accessible through service

Step 5: Implement Canary Deployment

**Purpose**: Gradually roll out new version to subset of users.

**Istio Canary Example**:

# DestinationRule for two versions
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: web-app
spec:
  host: web-app
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---
# VirtualService with 90/10 traffic split
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: web-app
spec:
  hosts:
  - web-app
  http:
  - route:
    - destination:
        host: web-app
        subset: v1
      weight: 90
    - destination:
        host: web-app
        subset: v2
      weight: 10

**Commands**:

# Apply Istio configuration
kubectl apply -f destination-rule.yaml
kubectl apply -f virtual-service.yaml

# Deploy v2 alongside v1
kubectl apply -f deployment-v2.yaml

# Monitor metrics
kubectl get destinationrule web-app -o yaml
kubectl get virtualservice web-app -o yaml

# Gradually increase v2 traffic
# Edit VirtualService to change weights (80/20, 60/40, etc.)

# Full cutover to v2
# Edit VirtualService to send 100% to v2

# Remove v1
kubectl delete deployment web-app-v1

**Expected output**: New version gradually rolled out with ability to rollback based on metrics.

**Verification**:

  • Both versions running simultaneously
  • Traffic split according to weights
  • Metrics (error rate, latency) acceptable for canary version
  • Full cutover completed successfully

Step 6: Implement Infrastructure as Code

**Purpose**: Define infrastructure and deployment configuration in code.

**Terraform Example** (`main.tf`):

provider "aws" {
  region = "us-east-1"
}

resource "aws_ecr_repository" "web_app" {
  name = "web-app"
  image_scanning_configuration {
    scan_on_push = true
  }
}

resource "aws_ecs_cluster" "production" {
  name = "production"
  setting {
    name  = "containerInsights"
    value = "enabled"
  }
}

resource "aws_ecs_service" "web_app" {
  name            = "web-app"
  cluster         = aws_ecs_cluster.production.id
  task_definition = aws_ecs_task_definition.web_app.arn
  desired_count   = 3
  launch_type     = "FARGATE"
  
  network_configuration {
    subnets         = [aws_subnet.private.*.id]
    security_groups = [aws_security_group.ecs_tasks.id]
    assign_public_ip = false
  }
  
  load_balancers {
    target_group_arn = aws_lb_target_group.web_app.arn
    container_name   = "web-app"
    container_port   = 3000
  }
}

resource "aws_lb" "web" {
  name               = "web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = [aws_subnet.public.*.id]
  
  enable_deletion_protection = true
}

resource "aws_lb_target_group" "web_app" {
  name     = "web-app-tg"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
  target_type = "ip"
  
  health_check {
    path = "/health"
    port = 3000
  }
}

**Commands**:

# Initialize Terraform
terraform init

# Review planned changes
terraform plan

# Apply changes
terraform apply -auto-approve

# Destroy infrastructure (when no longer needed)
terraform destroy -auto-approve

**Expected output**: Infrastructure defined and provisioned via code.

**Verification**:

  • Infrastructure resources created as defined
  • Changes reviewable before application
  • Infrastructure reproducible across environments

Configuration Examples

GitHub Actions Pipeline (Complete)

name: Build, Test, Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: docker-compose -f docker-compose.test.yml up --abort-on-container-exit
        
  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: Build and push image
        run: |
          docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .
          docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          
  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy to staging
        run: kubectl set image deployment/web-app web-app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
        
  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Blue-green deploy
        run: ./scripts/blue-green-deploy.sh ${{ github.sha }}

Helm Chart Example

web-app/
  Chart.yaml
  values.yaml
  templates/
    deployment.yaml
    service.yaml
    hpa.yaml
    ingress.yaml
    serviceaccount.yaml

**values.yaml**:

replicaCount: 3
image:
  repository: 123456789012.dkr.ecr.us-east-1.amazonaws.com/web-app
  tag: "1.0.0"
  pullPolicy: IfNotPresent
service:
  type: LoadBalancer
  port: 80
  targetPort: 3000
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

Verification

Deployment Verification

# Check deployment status
kubectl rollout status deployment/web-app

# Check pods
kubectl get pods -l app=web-app

# Check service
kubectl get service web-app

# Check ingress
kubectl get ingress web-app

# Test application
curl -f http://<load-balancer-dns>/health

# Check ECS service
aws ecs describe-services --cluster production --services web-app

# Check Lambda
aws lambda get-function --function-name process-image

Expected Results

  • Application deployed and running
  • Health checks passing
  • Load balancer distributing traffic
  • Auto-scaling configured
  • Pipeline automated (code push → deploy)

Troubleshooting

| Symptom | Possible Cause | Diagnostic Command | Corrective Action | Verification | |---------|---------------|-------------------|-------------------|--------------| | Pods CrashLoopBackOff | Application error, missing config | `kubectl logs <pod>` | Fix application code or config | Pods running | | Service unavailable | No healthy endpoints | `kubectl get endpoints` | Check pod readiness, service selector | Service has endpoints | | Deployment fails | Image pull error | `kubectl describe pod` | Fix image reference, registry auth | Deployment succeeds | | Pipeline fails | Test or build error | Pipeline logs | Fix code, update tests | Pipeline green | | Canary metrics degraded | New version has issues | Monitoring dashboard | Rollback canary (set weight to 0) | Stable metrics | | Auto-scaling not working | Metrics not available | `kubectl get hpa` | Install metrics server | HPA scaling |

Best Practices

1. **Use CI/CD pipelines**: Automate build, test, and deployment. 2. **Containerize applications**: Consistent environments across development and production. 3. **Use infrastructure as code**: Define infrastructure in Terraform/CloudFormation. 4. **Implement health checks**: Liveness and readiness probes for Kubernetes. 5. **Use blue-green or canary deployments**: Reduce deployment risk. 6. **Scan container images**: Security vulnerabilities in dependencies. 7. **Set resource requests and limits**: Prevent resource starvation. 8. **Implement rollback procedures**: Quick recovery from failed deployments. 9. **Monitor deployments**: Track deployment frequency, lead time, failure rate. 10. **Separate environments**: Development, staging, production with appropriate promotion gates.

Conclusion

Deploying applications on cloud infrastructure requires modern DevOps practices including containerization, CI/CD pipelines, infrastructure as code, and advanced deployment strategies. By containerizing applications, automating pipelines, using Kubernetes for orchestration, and implementing blue-green/canary deployments, organizations can deploy frequently with low risk. Infrastructure as code ensures consistency and reproducibility across environments.

References

  • Kubernetes Documentation (https://kubernetes.io/docs/)
  • Docker Documentation (https://docs.docker.com/)
  • AWS ECS Documentation (https://docs.aws.amazon.com/ecs/)
  • AWS EKS Documentation (https://docs.aws.amazon.com/eks/)
  • GitHub Actions Documentation (https://docs.github.com/actions)
  • Terraform Documentation (https://www.terraform.io/docs/)
  • Istio Documentation (https://istio.io/latest/docs/)
#cloud-computing#application-deployment#CI-CD#containers#Kubernetes#serverless#blue-green-deployment#infrastructure-as-code#DevOps