Resolving AWS Lifecycle Hooks

Wouter van der Meulen
Wouter van der Meulen
Dec 23 2022
Posted in Engineering & Technology

AWS lifecycle hooks, blessing or curse?

Resolving AWS Lifecycle Hooks

AWS Lifecycle Hooks are a feature of Auto Scaling that allow you to perform custom actions during specified lifecycle events for an EC2 instance in an Auto Scaling group. These custom actions can be used to pause the instance launch or termination process to allow for additional tasks to be performed, such as installing software or gracefully shutting down an application.

There are two types of lifecycle hooks: launch and termination. Launch hooks are triggered when an instance is launched, while termination hooks are triggered when an instance is terminated.

As always, my experience with the AWS documentation is that it's not always the best, so I decided to put together a quick guide.

The Basics

To use lifecycle hooks, you first need to create the hook on the auto-scaling group. This can be done through the AWS console or through the AWS CLI. For the former, simply go to the Auto Scaling group and click on the "Lifecycle hooks" tab. For the latter, you can use the following command:

aws autoscaling put-lifecycle-hook \
    --lifecycle-hook-name my-hook \
    --auto-scaling-group-name my-asg \
    --lifecycle-transition autoscaling:EC2_INSTANCE_LAUNCHING \
    --default-result ABANDON

This creates a launch hook called my-hook on the auto-scaling group my-asg. The --lifecycle-transition parameter specifies the event that triggers the hook. In this case, the hook will be triggered when an instance is launched. The --default-result parameter specifies the default action to take if the hook is not resolved within the timeout period. In this case, the instance will stop if it isn't resolved within the timeout period. The default timeout period is 3600 seconds.

While the hook is active, the instance will be in a Pending:Wait state. This means that the instance is waiting for the hook to be resolved. To resolve the hook, you can use the following command:

aws autoscaling complete-lifecycle-action \
    --lifecycle-hook-name my-hook \
    --auto-scaling-group-name my-asg \
    --lifecycle-action-result CONTINUE \
    --instance-id your-instance-id

CONTINUE, in this case, means the lifecycle hook is resolved and the instance can continue to launch. If you want to abort the instance launch, you can use ABANDON instead.

The Use Cases

Lifecycle hooks can be used for a variety of use cases. One of the proposed examples mentions installing software on the instance, pre-launch. But in my opinion, the AMI in your Scale Group should not need additional setup.

Another use case is to gracefully shut down an application. This is especially useful if you have a long-running process that needs to be stopped before the instance is terminated. In this case, you would use a termination hook. The hook will be triggered when the instance is terminated. You can then use the hook to gracefully shut down the application. Once the application is shut down, you can resolve the hook and the instance will be terminated.

One of my favorite use cases is to use a hook to perform some additional checks before the instance is launched. For example, AWS Load Balancers check if the instance is healthy before it is added to the target group. But what if you're running background workers in your scale groups? That's when you don't have a load balancer to check if the instance is healthy. You can simply resolve your hook at the end of your boot script.

The Template

To make it easier to resolve your hook, you can use the following template. This script will get the instance id, region and autoscaling group name. All you need to do is insert your boot script and resolve the hook at the end.

#!/bin/bash

## These functions make it easier to get the instance id and region
function get_target_state {
  echo $(curl -s http://169.254.169.254/latest/meta-data/autoscaling/target-lifecycle-state)
}

function get_instance_id {
  echo $(curl -s http://169.254.169.254/latest/meta-data/instance-id)
}

function get_region {
  echo $(curl --silent http://169.254.169.254/latest/dynamic/instance-identity/document | jq -r .region)
}

## This function gets the autoscaling group name of the current instance, very convenient
function get_autoscaling_group_name {

  local instance_id=$(get_instance_id)
  local region=$(get_region)

  aws autoscaling describe-auto-scaling-instances \
    --region $region \
    --instance-ids $instance_id \
    --query 'AutoScalingInstances[].AutoScalingGroupName' \
    --output text
}

function complete_lifecycle_action {
  instance_id=$(get_instance_id)
  group_name=$(get_autoscaling_group_name)
  lifecycle_hook_name='your_lifecycle_hook_name'
  region=$(get_region)

  echo $(aws autoscaling complete-lifecycle-action \
    --lifecycle-hook-name $lifecycle_hook_name \
    --auto-scaling-group-name $group_name \
    --lifecycle-action-result CONTINUE \
    --instance-id $instance_id \
    --region $region)
}

## Your boot script goes here ##

  # Do stuff here

## Resolve the lifecycle hook

complete_lifecycle_action

Done

And there you have it, a quick guide on how to use lifecycle hooks from your EC2 instances.

As always, we hope you liked this article and if you have anything to add, we are available via our Support Channel.

Keep up-to-date with the latest news