Skip to main content
Auto Scaling Group Modules 2.0.0Last updated in version 2.0.0

Auto Scaling Group with Rolling Deployment Module

View Source Release Notes

This Terraform Module creates an Auto Scaling Group (ASG) that can do a zero-downtime rolling deployment. That means every time you update your app (e.g. publish a new AMI), all you have to do is run terraform apply and the new version of your app will automatically roll out across your Auto Scaling Group. Note that this module only creates the ASG and it's up to you to create all the other related resources, such as the launch template, ELB, and security groups.

note

This module used to use Launch configurations but has been updated to use Launch templates. This has been recommended by AWS for some time and Launch configurations will finally be deprecated entirely on Dec 31st 2023.

What's an Auto Scaling Group?

An Auto Scaling Group (ASG) is used to manage a cluster of EC2 Instances. It can enforce pre-defined rules about how many instances to run in the cluster, scale the number of instances up or down depending on traffic, and automatically restart instances if they go down.

How does rolling deployment work?

Since Terraform does not have rolling deployment built in (see https://github.com/hashicorp/terraform/issues/1552), we are faking it using the create_before_destroy lifecycle property. This approach is based on the rolling deploy strategy used by HashiCorp itself, as described by Paul Hinze here. As a result, every time you update your launch templates (e.g. by specifying a new AMI to deploy), Terraform will:

  1. Create a new ASG with the new launch templates.
  2. Wait for the new ASG to deploy successfully and for the instances to register with the load balancer (if you associated an ELB or ALB with this ASG).
  3. Destroy the old ASG.
  4. Since the old ASG is only removed once the new ASG instances are registered with the ELB and serving traffic, there will be no downtime. Moreover, if anything went wrong while rolling out the new ASG, it will be marked as tainted (i.e. marked for deletion next time) and the original ASG will be left unchanged, so again, there is no downtime.

Each rolling deploy creates a brand new aws_autoscaling_group resource (its name is derived from the launch template's name and version), so it always comes up at the desired_capacity you configure. Once that ASG exists, the resource's lifecycle.ignore_changes = [desired_capacity] means Terraform will not fight any auto scaling policies or alarms that subsequently change that ASG's live capacity: terraform apply on an unchanged launch template won't reset capacity back down (or up) to the configured value.

How do you change desired_capacity?

Updating desired_capacity on its own has no effect to an existing ASG (because of lifecycle.ignore_changes). This is a deliberate choice that also stops Terraform from reverting auto scaling policy adjustments. To change desired_capacity, you must use one of the options below:

  • Let auto scaling own it: Manage capacity with scaling policies and scheduled actions. Treat desired_capacity purely as the starting size for each newly created ASG (recommended for dynamically-sized ASGs).
  • Change as part of deploy: Changing desired_capacity together with the launch template does take effect, since the deploy creates a brand new ASG and the new value is applied at creation time. Note that prior versions of this module had different behavior since a Python script would read the old ASG's live capacity on every redeploy and use that instead of the configured value.
  • Set it out-of-band: If the desired capacity is set from the AWS console or cli, Terraform will leave it alone.
note

Migration guide: prior versions of this module used an external Python script (get-desired-capacity.py) to look up the previous ASG's live desired_capacity and carry it forward into the replacement ASG on every rolling redeploy. That script (and its vendored boto3 dependency) has been removed: it required a working python3 on whatever machine ran terraform apply, which broke repeatedly as Python/boto3 versions moved (see #242), and there's no equivalent native Terraform data source that can safely stand in for it (the AWS provider's aws_autoscaling_group data source errors when the ASG doesn't exist yet, which is always true on a first apply). If you relied on capacity surviving a redeploy: that behavior is gone. A rolling redeploy now always starts the new ASG at the configured desired_capacity. If you use auto scaling policies or scheduled actions to manage capacity, they will re-adjust the new ASG after each deploy the same way they would for any newly created ASG.

Sample Usage

main.tf

# ------------------------------------------------------------------------------------------------------
# DEPLOY GRUNTWORK'S ASG-ROLLING-DEPLOY MODULE
# ------------------------------------------------------------------------------------------------------

module "asg_rolling_deploy" {

source = "git::git@github.com:gruntwork-io/terraform-aws-asg.git//modules/asg-rolling-deploy?ref=v2.0.0"

# ----------------------------------------------------------------------------------------------------
# REQUIRED VARIABLES
# ----------------------------------------------------------------------------------------------------

# The desired number of EC2 Instances to run in the ASG when it is first
# created. Auto scaling policies may change this value afterwards, and this
# module sets lifecycle.ignore_changes on it, so changing this variable on its
# own has NO effect on existing ASG (terraform apply will report no change).
# It only takes effect when a new ASG is created (by a launch template
# change). Setting this to null will let AWS default the initial capacity to
# min_size.
desired_capacity = <number>

# The ID and version of the Launch Template to use for each EC2 instance in
# this ASG. The version value MUST be an output of the Launch Template
# resource itself. This ensures that a new ASG is created every time a new
# Launch Template version is created.
launch_template = <object(
id = string
name = string
version = string
)>

# The maximum number of EC2 Instances to run in the ASG
max_size = <number>

# The minimum number of EC2 Instances to run in the ASG
min_size = <number>

# A list of subnet ids in the VPC were the EC2 Instances should be deployed
vpc_subnet_ids = <list(string)>

# ----------------------------------------------------------------------------------------------------
# OPTIONAL VARIABLES
# ----------------------------------------------------------------------------------------------------

# Override the auto-generated ASG name with this value.
asg_name = ""

# Capacity Rebalancing helps you maintain workload availability by proactively
# augmenting your fleet with a new Spot Instance before a running instance is
# interrupted by Amazon EC2
autoscaling_capacity_rebalance = false

# Defines the action the Auto Scaling group should take when the lifecycle
# hook timeout elapses or if an unexpected failure occurs. The value for this
# parameter can be either CONTINUE or ABANDON. The default value for this
# parameter is ABANDON.
autoscaling_lifecycle_hook_default_result = null

# Defines the amount of time, in seconds, that can elapse before the lifecycle
# hook times out. When the lifecycle hook times out, Auto Scaling performs the
# action defined in the DefaultResult parameter
autoscaling_lifecycle_hook_heartbeat_timeout = null

# Required if enable_autoscaling_lifecycle_hook is enabled. Instance state to
# which you want to attach the lifecycle hook. For a list of lifecycle hook
# types, see
# https://docs.aws.amazon.com/cli/latest/reference/autoscaling/describe-lifecycle-hook-types.html#examples
autoscaling_lifecycle_lifecycle_transition = null

# Contains additional information that you want to include any time Auto
# Scaling sends a message to the notification target.
autoscaling_lifecycle_notification_metadata = []

# ARN of the notification target that Auto Scaling will use to notify you when
# an instance is in the transition state for the lifecycle hook.
autoscaling_lifecycle_notification_target_arn = null

# ARN of the IAM role that allows the Auto Scaling group to publish to the
# specified notification target.
autoscaling_lifecycle_role_arn = null

# A list of custom tags to apply to the EC2 Instances in this ASG. Each item
# in this list should be a map with the parameters key, value, and
# propagate_at_launch.
custom_tags = []

# Timeout value for deletion operations on autoscale groups.
deletion_timeout = "10m"

# Toggles if the autoscaling_lifecycle_hook will be enabled or not. If
# enabled, the aws_autoscaling_lifecycle_hook resource will be created and
# attached to the ALB. Make sure you set all autoscaling_lifecycle_* variables
# to desired values if enabled.
enable_autoscaling_lifecycle_hook = false

# A list of metrics the ASG should enable for monitoring all instances in a
# group. The allowed values are GroupMinSize, GroupMaxSize,
# GroupDesiredCapacity, GroupInServiceInstances, GroupPendingInstances,
# GroupStandbyInstances, GroupTerminatingInstances, GroupTotalInstances.
enabled_metrics = []

# Time, in seconds, after an EC2 Instance comes into service before checking
# health.
health_check_grace_period = 300

# A list of Elastic Load Balancer (ELB) names to associate with this ASG. If
# you're using the Application Load Balancer (ALB), see var.target_group_arns.
load_balancers = []

# The maximum amount of time, in seconds, that an instance inside an ASG can
# be in service, values must be either equal to 0 or between 604800 and
# 31536000 seconds.
max_instance_lifetime = null

# Wait for this number of EC2 Instances to show up healthy in the load
# balancer on creation.
min_elb_capacity = 0

# Define policy using spot and on-demand instances.
mixed_instance_policy = null

# The key for the tag that will be used to associate a unique identifier with
# this ASG. This identifier will persist between redeploys of the ASG, even
# though the underlying ASG is being deleted and replaced with a different
# one.
tag_asg_id_key = "AsgId"

# A list of Application Load Balancer (ALB) target group ARNs to associate
# with this ASG. If you're using the Elastic Load Balancer (ELB), see
# var.load_balancers.
target_group_arns = []

# A list of policies to decide how the instances in the auto scale group
# should be terminated. The allowed values are OldestInstance, NewestInstance,
# OldestLaunchTemplate, AllocationStrategy, ClosestToNextInstanceHour,
# Default.
termination_policies = []

# Whether or not ELB or ALB health checks should be enabled. If set to true,
# the load_balancers or target_groups_arns variable should be set depending on
# the load balancer type you are using. Useful for testing connectivity before
# health check endpoints are available.
use_elb_health_checks = true

# A maximum duration that Terraform should wait for the EC2 Instances to be
# healthy before timing out.
wait_for_capacity_timeout = "10m"

}


Reference

Required

desired_capacitynumberrequired

The desired number of EC2 Instances to run in the ASG when it is first created. Auto scaling policies may change this value afterwards, and this module sets lifecycle.ignore_changes on it, so changing this variable on its own has NO effect on existing ASG (terraform apply will report no change). It only takes effect when a new ASG is created (by a launch template change). Setting this to null will let AWS default the initial capacity to min_size.

launch_templateobject(…)required

The ID and version of the Launch Template to use for each EC2 instance in this ASG. The version value MUST be an output of the Launch Template resource itself. This ensures that a new ASG is created every time a new Launch Template version is created.

object({
id = string
name = string
version = string
})
max_sizenumberrequired

The maximum number of EC2 Instances to run in the ASG

min_sizenumberrequired

The minimum number of EC2 Instances to run in the ASG

vpc_subnet_idslist(string)required

A list of subnet ids in the VPC were the EC2 Instances should be deployed

Optional

asg_namestringoptional

Override the auto-generated ASG name with this value.

""

Capacity Rebalancing helps you maintain workload availability by proactively augmenting your fleet with a new Spot Instance before a running instance is interrupted by Amazon EC2

false

Defines the action the Auto Scaling group should take when the lifecycle hook timeout elapses or if an unexpected failure occurs. The value for this parameter can be either CONTINUE or ABANDON. The default value for this parameter is ABANDON.

null

Defines the amount of time, in seconds, that can elapse before the lifecycle hook times out. When the lifecycle hook times out, Auto Scaling performs the action defined in the DefaultResult parameter

null

Required if enable_autoscaling_lifecycle_hook is enabled. Instance state to which you want to attach the lifecycle hook. For a list of lifecycle hook types, see https://docs.aws.amazon.com/cli/latest/reference/autoscaling/describe-lifecycle-hook-types.html#examples

null

Contains additional information that you want to include any time Auto Scaling sends a message to the notification target.

Any types represent complex values of variable type. For details, please consult `variables.tf` in the source repo.
[]

ARN of the notification target that Auto Scaling will use to notify you when an instance is in the transition state for the lifecycle hook.

null

ARN of the IAM role that allows the Auto Scaling group to publish to the specified notification target.

null
custom_tagslist(object(…))optional

A list of custom tags to apply to the EC2 Instances in this ASG. Each item in this list should be a map with the parameters key, value, and propagate_at_launch.

list(object({
key = string
value = string
propagate_at_launch = bool
}))
[]
Example
   default = [
{
key = "foo"
value = "bar"
propagate_at_launch = true
},
{
key = "baz"
value = "blah"
propagate_at_launch = true
}
]

deletion_timeoutstringoptional

Timeout value for deletion operations on autoscale groups.

"10m"

Toggles if the autoscaling_lifecycle_hook will be enabled or not. If enabled, the aws_autoscaling_lifecycle_hook resource will be created and attached to the ALB. Make sure you set all autoscaling_lifecycle_* variables to desired values if enabled.

false
enabled_metricslist(string)optional

A list of metrics the ASG should enable for monitoring all instances in a group. The allowed values are GroupMinSize, GroupMaxSize, GroupDesiredCapacity, GroupInServiceInstances, GroupPendingInstances, GroupStandbyInstances, GroupTerminatingInstances, GroupTotalInstances.

[]
Example
   enabled_metrics = [
"GroupDesiredCapacity",
"GroupInServiceInstances",
"GroupMaxSize",
"GroupMinSize",
"GroupPendingInstances",
"GroupStandbyInstances",
"GroupTerminatingInstances",
"GroupTotalInstances"
]

Time, in seconds, after an EC2 Instance comes into service before checking health.

300
load_balancerslist(string)optional

A list of Elastic Load Balancer (ELB) names to associate with this ASG. If you're using the Application Load Balancer (ALB), see target_group_arns.

[]
max_instance_lifetimenumberoptional

The maximum amount of time, in seconds, that an instance inside an ASG can be in service, values must be either equal to 0 or between 604800 and 31536000 seconds.

null
min_elb_capacitynumberoptional

Wait for this number of EC2 Instances to show up healthy in the load balancer on creation.

0

Define policy using spot and on-demand instances.

Any types represent complex values of variable type. For details, please consult `variables.tf` in the source repo.
null
tag_asg_id_keystringoptional

The key for the tag that will be used to associate a unique identifier with this ASG. This identifier will persist between redeploys of the ASG, even though the underlying ASG is being deleted and replaced with a different one.

"AsgId"
target_group_arnslist(string)optional

A list of Application Load Balancer (ALB) target group ARNs to associate with this ASG. If you're using the Elastic Load Balancer (ELB), see load_balancers.

[]
termination_policieslist(string)optional

A list of policies to decide how the instances in the auto scale group should be terminated. The allowed values are OldestInstance, NewestInstance, OldestLaunchTemplate, AllocationStrategy, ClosestToNextInstanceHour, Default.

[]

Whether or not ELB or ALB health checks should be enabled. If set to true, the load_balancers or target_groups_arns variable should be set depending on the load balancer type you are using. Useful for testing connectivity before health check endpoints are available.

true

A maximum duration that Terraform should wait for the EC2 Instances to be healthy before timing out.

"10m"