Terraform Zero-Downtime Deployments - Blue-Green and Rolling Updates

Key Takeaway

How to achieve zero-downtime deployments with Terraform using blue-green, rolling updates, and create_before_destroy. Step-by-step guide with code examples a...

Table of Contents

Zero-Downtime Deployment Strategies

Infrastructure changes shouldn’t cause outages. Here are battle-tested patterns for zero-downtime deployments with Terraform.

Strategy 1: create_before_destroy

The simplest approach — create the new resource before destroying the old one:

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    create_before_destroy = true
  }
}

Strategy 2: Blue-Green With ALB

Maintain two environments, switch traffic between them:

variable "active_color" {
  default = "blue"  # Change to "green" to switch
}

resource "aws_lb_target_group" "blue" {
  name     = "app-blue"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
}

resource "aws_lb_target_group" "green" {
  name     = "app-green"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
}

resource "aws_lb_listener_rule" "app" {
  listener_arn = aws_lb_listener.front.arn

  action {
    type             = "forward"
    target_group_arn = var.active_color == "blue" ? aws_lb_target_group.blue.arn : aws_lb_target_group.green.arn
  }

  condition {
    path_pattern { values = ["/*"] }
  }
}

Strategy 3: Rolling Updates With ASG

resource "aws_launch_template" "app" {
  name_prefix   = "app-"
  image_id      = var.ami_id
  instance_type = var.instance_type

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "app" {
  desired_capacity = 3
  max_size         = 6
  min_size         = 3

  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }

  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 66
      instance_warmup        = 300
    }
  }
}

Strategy 4: Weighted DNS Routing

resource "aws_route53_record" "app" {
  zone_id = var.zone_id
  name    = "app.example.com"
  type    = "A"

  weighted_routing_policy {
    weight = var.active_color == "blue" ? 100 : 0
  }

  set_identifier = "blue"
  alias {
    name    = aws_lb.blue.dns_name
    zone_id = aws_lb.blue.zone_id
  }
}

Best Practices

  1. Always use create_before_destroy for stateless resources
  2. Health checks are critical — ALB health checks prevent routing to unhealthy instances
  3. Test the rollback — switching back should be as simple as changing a variable
  4. Use prevent_destroy on databases — data loss isn’t zero-downtime
  5. Canary deployments — route 5% of traffic first, then gradually increase

Learn More

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.