Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit cba9f2a

Browse files
committed
Add asg-simple-lifecycle
1 parent ca4962b commit cba9f2a

File tree

10 files changed

+477
-0
lines changed

10 files changed

+477
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
.PHONY: init ssh-key plan-vpc plan-subnets plan-gateway plan apply destroy clean
2+
3+
.DEFAULT_GOAL = help
4+
5+
TERRAFORM = "aws-env terraform"
6+
7+
# Hardcoding value of 3 minutes when we check if the plan file is stale
8+
STALE_PLAN_FILE := `find "tf.out" -mmin -3 | grep -q tf.out`
9+
10+
## Check if tf.out is stale (Older than 2 minutes)
11+
check-plan-file:
12+
@if ! ${STALE_PLAN_FILE} ; then \
13+
echo "ERROR: Stale tf.out plan file (older than 3 minutes)!"; \
14+
exit 1; \
15+
fi
16+
17+
## Runs terraform get and terraform init for env
18+
init:
19+
$terraform init
20+
21+
## Create ssh key
22+
ssh-key:
23+
@ssh-keygen -q -N "" -b 4096 -C "SSH key for vpc-scenario-1 example" -f ./id_rsa
24+
25+
## use 'terraform plan' to 'target' the vpc in the vpc module
26+
plan-vpc:
27+
@terraform plan \
28+
-target="module.vpc.module.vpc" \
29+
-out=tf.out
30+
31+
## use 'terraform plan' to 'target' the public subnets in the vpc module
32+
plan-subnets:
33+
@terraform plan \
34+
-target="module.vpc.module.public-subnets" \
35+
-out=tf.out
36+
37+
## use 'terraform plan' to 'target' the public gateway in the vpc module
38+
plan-gateway:
39+
@terraform plan \
40+
-target="module.vpc.module.public-gateway" \
41+
-out=tf.out
42+
43+
## use 'terraform plan' to map out updates to apply
44+
plan:
45+
@terraform plan -out=tf.out
46+
47+
## use 'terraform apply' to apply updates in a 'tf.out' plan file
48+
apply: check-plan-file
49+
@terraform apply tf.out
50+
51+
## use 'terraform destroy' to remove all resources from AWS
52+
destroy:
53+
@terraform destroy
54+
55+
## rm -rf all files and state
56+
clean:
57+
@rm -f tf.out
58+
@rm -f id_rsa
59+
@rm -f id_rsa.pub
60+
@rm -f terraform.tfvars
61+
@rm -f terraform.*.backup
62+
@rm -f terraform.tfstate
63+
64+
## Show help screen.
65+
help:
66+
@echo "Please use \`make <target>' where <target> is one of\n\n"
67+
@awk '/^[a-zA-Z\-\_0-9]+:/ { \
68+
helpMessage = match(lastLine, /^## (.*)/); \
69+
if (helpMessage) { \
70+
helpCommand = substr($$1, 0, index($$1, ":")-1); \
71+
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
72+
printf "%-30s %s\n", helpCommand, helpMessage; \
73+
} \
74+
} \
75+
{ lastLine = $$0 }' $(MAKEFILE_LIST)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Example of basic ASG integration with lifecycle hooks
2+
3+
The difference between this and the one one is that we aren't using
4+
any load balancers in this example.
5+
6+
## Environment creation and deployment
7+
8+
To use this example set up AWS credentials and then run the commands in the
9+
following order:
10+
11+
```
12+
make ssh-key
13+
make init
14+
make plan-vpc
15+
make apply
16+
make plan-subnets
17+
make apply
18+
make plan-gateway
19+
make apply
20+
make plan
21+
make apply
22+
```
23+
24+
## Testing
25+
26+
Get the public IP address of the newly created ec2 web instance with the AWS console.
27+
28+
SSH into the machine with the command:
29+
30+
```
31+
ssh -i id_rsa ec2-user@<ec2-ip-address>
32+
```
33+
34+
You can see in the machine that `lifecycled` daemon would be
35+
running. You can check the status of the service using
36+
37+
```
38+
systemctl status lifecycled.service
39+
```
40+
41+
42+
## Test the Notification
43+
44+
To generate a notification for a launch event, update the Auto Scaling group by increasing the desired capacity of the Auto Scaling group by 1. You receive a notification within a few minutes after instance launch.
45+
46+
To change the desired capacity using the console
47+
48+
Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/.
49+
50+
On the navigation pane, under Auto Scaling, choose Auto Scaling Groups.
51+
52+
Select your Auto Scaling group.
53+
54+
On the Details tab, choose Edit.
55+
56+
For Desired, decrease the current value by 1.
57+
58+
Choose Save.
59+
60+
After a few minutes, you'll see that the lifecycle-handler.sh script will be executed and it's side effect operation will be performed.
61+
62+
63+
## Destruction
64+
65+
To destroy the test environment run the following commands:
66+
67+
```
68+
make destroy
69+
make clean
70+
```
71+
72+
## Notes
73+
- This example was last tested with `Terraform v0.11.11`
74+
- This example assumes AWS credentials setup with access to the **us-east-2** region.
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
resource "aws_autoscaling_group" "cluster" {
2+
name = "${var.name_prefix}-${aws_launch_configuration.cluster.name}"
3+
launch_configuration = aws_launch_configuration.cluster.id
4+
vpc_zone_identifier = module.vpc.public_subnet_ids
5+
6+
min_size = 1
7+
desired_capacity = 2
8+
max_size = 4
9+
10+
lifecycle {
11+
create_before_destroy = true
12+
}
13+
14+
initial_lifecycle_hook {
15+
name = "${var.name_prefix}-lifecycle"
16+
default_result = "CONTINUE"
17+
heartbeat_timeout = 60
18+
lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING"
19+
notification_target_arn = aws_sns_topic.main.arn
20+
role_arn = aws_iam_role.lifecycle_hook.arn
21+
}
22+
}
23+
24+
# Launch Config for the ASG
25+
resource "aws_launch_configuration" "cluster" {
26+
name_prefix = var.name_prefix
27+
image_id = data.aws_ami.linux2.id
28+
instance_type = "t2.nano"
29+
key_name = aws_key_pair.main.key_name
30+
iam_instance_profile = aws_iam_instance_profile.ec2.name
31+
security_groups = [aws_security_group.main.id]
32+
33+
user_data = data.template_file.main.rendered
34+
35+
lifecycle {
36+
create_before_destroy = true
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#cloud-config
2+
write_files:
3+
- path: "/etc/systemd/system/lifecycled.service"
4+
permissions: "0644"
5+
owner: "root"
6+
content: |
7+
[Unit]
8+
Description=Autoscale Lifecycle Daemon
9+
Requires=network-online.target
10+
After=network-online.target
11+
12+
[Service]
13+
Type=simple
14+
Restart=on-failure
15+
RestartSec=30s
16+
TimeoutStopSec=5m
17+
18+
Environment="AWS_REGION=${region}"
19+
ExecStart=/usr/local/bin/lifecycled --no-spot --sns-topic=${lifecycle_topic} --handler=/usr/local/scripts/lifecycle-handler.sh --json
20+
21+
[Install]
22+
WantedBy=multi-user.target
23+
- path: "/usr/local/scripts/lifecycle-handler.sh"
24+
permissions: "0744"
25+
owner: "root"
26+
content: |
27+
#! /usr/bin/bash
28+
29+
set -euo pipefail
30+
31+
echo "hello from the handler"
32+
curl http://3.22.77.147
33+
sleep 120
34+
echo "goodbye from the handler"
35+
runcmd:
36+
- |
37+
wget https://github.com/buildkite/lifecycled/releases/download/v3.0.2/lifecycled-linux-amd64
38+
cp ./lifecycled-linux-amd64 /usr/local/bin/lifecycled
39+
chmod +x /usr/local/bin/lifecycled
40+
chown root:root /usr/local/bin/lifecycled
41+
echo "lifecycled installed"
42+
- |
43+
systemctl enable lifecycled.service --now
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Use the latest Amazon Linux 2 AMI
2+
data "aws_ami" "linux2" {
3+
owners = ["amazon"]
4+
most_recent = true
5+
6+
filter {
7+
name = "virtualization-type"
8+
values = ["hvm"]
9+
}
10+
11+
filter {
12+
name = "architecture"
13+
values = ["x86_64"]
14+
}
15+
16+
filter {
17+
name = "root-device-type"
18+
values = ["ebs"]
19+
}
20+
21+
filter {
22+
name = "name"
23+
values = ["amzn2-ami*gp2"]
24+
}
25+
}
26+
27+
data "aws_availability_zones" "available" {
28+
}
29+
30+
data "aws_region" "current" {
31+
}
32+
33+
# Cloud init script for the autoscaling group
34+
data "template_file" "main" {
35+
template = file("${path.module}/cloud-config.yml")
36+
37+
vars = {
38+
region = data.aws_region.current.name
39+
lifecycle_topic = aws_sns_topic.main.arn
40+
}
41+
}
42+
43+
# Instance profile for the autoscaling group.
44+
data "aws_iam_policy_document" "permissions" {
45+
statement {
46+
effect = "Allow"
47+
48+
actions = [
49+
"sns:Subscribe",
50+
"sns:Unsubscribe",
51+
]
52+
53+
resources = [
54+
aws_sns_topic.main.arn,
55+
]
56+
}
57+
58+
statement {
59+
effect = "Allow"
60+
61+
actions = [
62+
"autoscaling:RecordLifecycleActionHeartbeat",
63+
"autoscaling:CompleteLifecycleAction",
64+
]
65+
66+
resources = ["*"]
67+
}
68+
}
69+
70+
data "aws_iam_policy_document" "ec2_assume" {
71+
statement {
72+
effect = "Allow"
73+
actions = ["sts:AssumeRole"]
74+
75+
principals {
76+
type = "Service"
77+
identifiers = ["ec2.amazonaws.com"]
78+
}
79+
}
80+
}
81+
82+
data "aws_iam_policy_document" "asg_assume" {
83+
statement {
84+
effect = "Allow"
85+
actions = ["sts:AssumeRole"]
86+
87+
principals {
88+
type = "Service"
89+
identifiers = ["autoscaling.amazonaws.com"]
90+
}
91+
}
92+
}
93+
94+
data "aws_iam_policy_document" "asg_permissions" {
95+
statement {
96+
effect = "Allow"
97+
98+
resources = [
99+
aws_sns_topic.main.arn,
100+
]
101+
102+
actions = [
103+
"sns:Publish",
104+
]
105+
}
106+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
locals {
2+
az_count = length(var.public_subnet_cidrs)
3+
azs = slice(
4+
data.aws_availability_zones.available.names,
5+
0,
6+
local.az_count)
7+
}

0 commit comments

Comments
 (0)