Blue-Green Deployments for React Apps

Loading

Blue-green deployments minimize downtime and risk by maintaining two identical production environments (Blue and Green) and switching traffic between them. Here’s how to implement this pattern with React applications:

Core Implementation Strategies

1. DNS-Based Blue-Green Deployment

// deployment-script.js (Route 53 example)
const AWS = require('aws-sdk');
const route53 = new AWS.Route53();

async function switchTraffic({ blueStack, greenStack, domain }) {
  const params = {
    ChangeBatch: {
      Changes: [{
        Action: 'UPSERT',
        ResourceRecordSet: {
          Name: domain,
          Type: 'A',
          AliasTarget: {
            HostedZoneId: greenStack.hostedZoneId,
            DNSName: greenStack.distributionDomain,
            EvaluateTargetHealth: false
          }
        }
      }]
    },
    HostedZoneId: blueStack.hostedZoneId
  };

  await route53.changeResourceRecordSets(params).promise();
  console.log(`Traffic switched to Green environment`);
}

2. Load Balancer Approach

# AWS CloudFormation template snippet
Resources:
  BlueTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Port: 80
      Protocol: HTTP
      VpcId: !Ref VPC
      HealthCheckPath: /health

  GreenTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Port: 80
      Protocol: HTTP
      VpcId: !Ref VPC
      HealthCheckPath: /health

  Listener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 443
      Protocol: HTTPS
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref BlueTargetGroup

CI/CD Pipeline Integration

3. GitHub Actions Blue-Green Workflow

name: Blue-Green Deployment

on:
  push:
    branches: [main]

jobs:
  deploy-green:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3

      - name: Build React App
        run: npm run build

      - name: Deploy to Green Environment
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
        run: |
          aws s3 sync build/ s3://green-bucket --delete
          aws cloudfront create-invalidation --distribution-id $GREEN_DISTRIBUTION --paths "/*"

  smoke-test:
    needs: deploy-green
    runs-on: ubuntu-latest
    steps:
      - run: |
          # Run smoke tests against green environment
          curl -I https://green.example.com/health

  switch-traffic:
    needs: smoke-test
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
        run: |
          # Update Route53 to point to green environment
          aws route53 change-resource-record-sets --cli-input-json file://switch-to-green.json

Kubernetes Implementation

4. Kubernetes Blue-Green with Services

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-app-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: react-app
      version: blue
  template:
    metadata:
      labels:
        app: react-app
        version: blue
    spec:
      containers:
      - name: react-app
        image: react-app:1.0.0
        ports:
        - containerPort: 80

# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-app-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: react-app
      version: green
  template:
    metadata:
      labels:
        app: react-app
        version: green
    spec:
      containers:
      - name: react-app
        image: react-app:1.1.0
        ports:
        - containerPort: 80

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: react-app
spec:
  selector:
    app: react-app
    version: blue # Initially points to blue
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

5. Kubernetes Traffic Switching

# Switch service to green deployment
kubectl patch service react-app -p '{"spec":{"selector":{"version":"green"}}}'

# Rollback to blue if needed
kubectl patch service react-app -p '{"spec":{"selector":{"version":"blue"}}}'

Advanced Techniques

6. Canary Analysis Before Full Cutover

// Weighted DNS routing for gradual traffic shift
const weights = {
  blue: 70,
  green: 30
};

async function shiftTraffic(weights) {
  const params = {
    ChangeBatch: {
      Changes: [{
        Action: 'UPSERT',
        ResourceRecordSet: {
          Name: 'app.example.com',
          Type: 'CNAME',
          TTL: 60,
          ResourceRecords: [
            { Value: 'blue-elb.example.com' },
            { Value: 'green-elb.example.com' }
          ],
          Weight: weights.blue
        }
      }, {
        Action: 'UPSERT',
        ResourceRecordSet: {
          Name: 'app.example.com',
          Type: 'CNAME',
          TTL: 60,
          ResourceRecords: [
            { Value: 'green-elb.example.com' }
          ],
          Weight: weights.green
        }
      }]
    },
    HostedZoneId: 'Z2FDTNDATAQYW2'
  };

  await route53.changeResourceRecordSets(params).promise();
}

7. Database Migration Strategy

// Database versioning approach
async function migrateData() {
  // Check which environment is active
  const activeEnv = await getActiveEnvironment();

  if (activeEnv === 'blue') {
    // Migrate data to green database
    await migrateDatabase('blue-db', 'green-db');
  } else {
    // Migrate data to blue database
    await migrateDatabase('green-db', 'blue-db');
  }
}

async function migrateDatabase(source, target) {
  // Implementation depends on your database
  // Typically involves schema changes and data migration
}

Monitoring and Rollback

8. Health Check Endpoint

// health.js (Express endpoint)
router.get('/health', (req, res) => {
  const health = {
    status: 'OK',
    version: process.env.APP_VERSION,
    environment: process.env.ENVIRONMENT_NAME,
    timestamp: new Date().toISOString(),
    dependencies: {
      database: checkDatabase(),
      cache: checkCache()
    }
  };

  res.status(200).json(health);
});

function checkDatabase() {
  // Implementation specific to your database
  return { status: 'OK', responseTime: 42 };
}

9. Automated Rollback Script

// rollback.js
async function rollback() {
  try {
    const metrics = await fetchMetrics();

    if (metrics.errorRate > 0.1 || metrics.latency > 2000) {
      console.log('Metrics threshold exceeded, initiating rollback');
      await switchTraffic({
        blueStack: greenConfig,
        greenStack: blueConfig,
        domain: 'app.example.com'
      });
      await notifyTeam('Rollback initiated due to performance degradation');
    }
  } catch (error) {
    console.error('Rollback failed:', error);
    await notifyTeam('Emergency rollback required!');
  }
}

setInterval(rollback, 300000); // Check every 5 minutes

Best Practices Checklist

  1. Environment Setup
  • [ ] Create identical blue and green environments
  • [ ] Ensure database compatibility
  • [ ] Configure monitoring for both environments
  1. Deployment Process
  • [ ] Automate deployment to inactive environment
  • [ ] Implement smoke tests
  • [ ] Use weighted traffic shifting for canary testing
  1. Traffic Switching
  • [ ] Plan for DNS TTL considerations
  • [ ] Implement session affinity if needed
  • [ ] Test switchover procedure
  1. Database Strategy
  • [ ] Use backward-compatible database changes
  • [ ] Implement data migration scripts
  • [ ] Test rollback procedures
  1. Monitoring
  • [ ] Set up health checks
  • [ ] Monitor key metrics during switchover
  • [ ] Implement automated rollback triggers
  1. Documentation
  • [ ] Document switchover procedure
  • [ ] Maintain runbooks for rollback
  • [ ] Record previous deployments
  1. Testing
  • [ ] Test in staging environment first
  • [ ] Conduct failure scenario testing
  • [ ] Validate rollback procedure

Leave a Reply

Your email address will not be published. Required fields are marked *