Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Running cron jobs in AWS Auto Scaling group is tricky. When you deploy the same code and configuration to all instances in the group, cron job would run on all of them. You may not want that. This script detects the first instance in the group and allows only this instance to run the job. IAM user used by this script needs to have permissions to…
#!/usr/bin/env ruby
require 'syslog'
require 'net/http'
require 'aws-sdk'
Syslog.open
AWS.config({
:access_key_id => '<iam user key>',
:secret_access_key => '<iam user secret>'
})
metadata_endpoint = 'http://169.254.169.254/latest/meta-data/'
instance_id = Net::HTTP.get( URI.parse( metadata_endpoint + 'instance-id' ) )
auto_scaling = AWS::AutoScaling.new
auto_scaling.groups.each { |group|
instance = group.ec2_instances.filter('instance-state-name', 'running').first
if( instance.instance_id == instance_id )
command = ARGV * ' '
Syslog.alert( 'running cron on ' + instance_id + ': ' + command )
`#{command}`
end
}
#!/bin/bash
source "/usr/local/rvm/scripts/rvm"
cd "$(dirname "$0")"
./aws_autoscaling_cron.rb "$@"
{
"Statement": [
{
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"ec2:DescribeInstanceAttribute",
"ec2:DescribeInstanceStatus",
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": [
"*"
]
}
]
}
#run a command every day at midnight
0 0 * * * ubuntu /aws_autoscaling_cron.sh <command> <parameters> > /dev/null 2> /dev/null
@hetul99
Copy link

hetul99 commented May 6, 2020

I am running this on Amazon Linux EC2. Will I need to change anything in crontab commands? Also what to pass in **<command>** and **<parameters>** in crontab?

@kixorz
Copy link
Author

kixorz commented May 6, 2020

@hetul99
Copy link

hetul99 commented May 7, 2020

I have configured everything accordingly still showing me following error in /var/spool/mail/ec2-user
/aws_autoscaling_cron.sh: line 4: ./aws_autoscaling_cron.rb: Permission denied
I have used my user's Acces key and Secret access key also with required permission. But still showing this error.

@kixorz
Copy link
Author

kixorz commented May 7, 2020

@hetul99
Copy link

hetul99 commented May 7, 2020

Tried. Still showing the same error !! Also when I am running ruby aws_autoscaling_cron.rb it is showing the following error:
/usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in require': cannot load such file -- aws-sdk (LoadError) from /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in require'
from aws_autoscaling_cron.rb:4:in `

'

I tried to download ruby SDK from following command sudo gem install aws-sdk but it seems that package is not being found and so not getting downloaded. Can this be the reason?(I think Access denied permission should not be shown for this sdk missing error)

@kixorz
Copy link
Author

kixorz commented May 7, 2020

@leytonreed
Copy link

leytonreed commented May 12, 2020

Just in case anyone else finds this useful - I didn't want to install Ruby on an instance, and so ported the logic to bash (requiring the same IAM policy).

/opt/asg-cron.sh

#!/bin/bash

# Collect some information about this instance
MY_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
MY_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/.$//')
MY_ASG=$(aws autoscaling describe-auto-scaling-instances --region $MY_REGION --instance-ids $MY_ID --query "AutoScalingInstances[].AutoScalingGroupName" --output text)

# Query the ASG
FIRST_ID=$(aws autoscaling describe-auto-scaling-groups --region $MY_REGION --auto-scaling-group-name $MY_ASG --query "AutoScalingGroups[].Instances[0].InstanceId" --output text)

if [ "$FIRST_ID" == "$MY_ID" ]; then
        exit 0
else
        exit 1
fi

Then in a CRON, you can configure:

* * * * * /bin/bash /opt/asg-cron.sh && /path/to/your/cron/task --and params

Prerequisites:

  • The curl and aws binaries are installed and executable. (You might need to update the paths for your system)
  • The configured EC2 Instance Profile uses an IAM role with the correct policy attached
  • ...or ~/.aws/config contains credentials for an IAM user or role which has the correct policy attached

@timbuckingham
Copy link

timbuckingham commented Aug 10, 2021

Thanks @leytonreed -- for anyone else who ran into an issue with the bash script, your auto scaling group name may have spaces in it. You'll want to wrap $MY_ASG in quotes:

FIRST_ID=$(aws autoscaling describe-auto-scaling-groups --region $MY_REGION --auto-scaling-group-name "${MY_ASG}" --query "AutoScalingGroups[].Instances[0].InstanceId" --output text)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment