autoscaling
This commit is contained in:
parent
0c974b3f44
commit
af495d72be
462
autoscaling.py
Normal file
462
autoscaling.py
Normal file
@ -0,0 +1,462 @@
|
||||
import boto3
|
||||
import base64
|
||||
from USER_DATA import user_data
|
||||
import json
|
||||
import time
|
||||
|
||||
# Configuration variables
|
||||
PREFIX = "s464863"
|
||||
AMI_ID = "ami-0b5eea76982371e91"
|
||||
INSTANCE_TYPE = "t2.micro"
|
||||
SECURITY_GROUP_NAME = f"{PREFIX}-sg"
|
||||
REGION = "us-east-1"
|
||||
AWS_RESOURCES_FILE="aws_resources.json"
|
||||
|
||||
# Object to store AWS resources
|
||||
aws_resources = {}
|
||||
|
||||
def create_vpc(ec2_client):
|
||||
# Create VPC
|
||||
response = ec2_client.create_vpc(
|
||||
CidrBlock='10.0.0.0/16',
|
||||
TagSpecifications=[
|
||||
{
|
||||
'ResourceType': 'vpc',
|
||||
'Tags': [{'Key': 'Name', 'Value': f"{PREFIX}-vpc"}]
|
||||
}
|
||||
]
|
||||
)
|
||||
vpc_id = response['Vpc']['VpcId']
|
||||
print(f"Created VPC with ID: {vpc_id}")
|
||||
|
||||
# Enable DNS support and hostnames
|
||||
ec2_client.modify_vpc_attribute(VpcId=vpc_id, EnableDnsSupport={'Value': True})
|
||||
ec2_client.modify_vpc_attribute(VpcId=vpc_id, EnableDnsHostnames={'Value': True})
|
||||
print("Enabled DNS support and hostnames.")
|
||||
|
||||
return vpc_id
|
||||
|
||||
|
||||
def create_subnet(ec2_client, vpc_id, cidr_block, availability_zone):
|
||||
# Create subnet
|
||||
response = ec2_client.create_subnet(
|
||||
VpcId=vpc_id,
|
||||
CidrBlock=cidr_block,
|
||||
AvailabilityZone=availability_zone,
|
||||
TagSpecifications=[
|
||||
{
|
||||
'ResourceType': 'subnet',
|
||||
'Tags': [{'Key': 'Name', 'Value': f"{PREFIX}-subnet"}]
|
||||
}
|
||||
]
|
||||
)
|
||||
subnet_id = response['Subnet']['SubnetId']
|
||||
print(f"Created Subnet with ID: {subnet_id}")
|
||||
|
||||
# Public IP addresses for instances in the subnet
|
||||
ec2_client.modify_subnet_attribute(SubnetId=subnet_id, MapPublicIpOnLaunch={'Value': True})
|
||||
print("Configured subnet to auto-assign public IP addresses.")
|
||||
|
||||
return subnet_id
|
||||
|
||||
|
||||
def create_internet_gateway(ec2_client, vpc_id):
|
||||
# Create Internet Gateway
|
||||
response = ec2_client.create_internet_gateway(
|
||||
TagSpecifications=[
|
||||
{
|
||||
'ResourceType': 'internet-gateway',
|
||||
'Tags': [{'Key': 'Name', 'Value': f"{PREFIX}-igw"}]
|
||||
}
|
||||
]
|
||||
)
|
||||
igw_id = response['InternetGateway']['InternetGatewayId']
|
||||
print(f"Created Internet Gateway with ID: {igw_id}")
|
||||
|
||||
# Attach Internet Gateway to VPC
|
||||
ec2_client.attach_internet_gateway(InternetGatewayId=igw_id, VpcId=vpc_id)
|
||||
print("Attached Internet Gateway to VPC.")
|
||||
|
||||
return igw_id
|
||||
|
||||
|
||||
def create_route_table(ec2_client, vpc_id, subnet_id, igw_id):
|
||||
# Create Route Table
|
||||
response = ec2_client.create_route_table(
|
||||
VpcId=vpc_id,
|
||||
TagSpecifications=[
|
||||
{
|
||||
'ResourceType': 'route-table',
|
||||
'Tags': [{'Key': 'Name', 'Value': f"{PREFIX}-rt"}]
|
||||
}
|
||||
]
|
||||
)
|
||||
route_table_id = response['RouteTable']['RouteTableId']
|
||||
print(f"Created Route Table with ID: {route_table_id}")
|
||||
|
||||
# Create route to Internet Gateway
|
||||
ec2_client.create_route(
|
||||
RouteTableId=route_table_id,
|
||||
DestinationCidrBlock='0.0.0.0/0',
|
||||
GatewayId=igw_id
|
||||
)
|
||||
print("Added route to Internet Gateway in Route Table.")
|
||||
|
||||
# Associate Route Table with Subnet
|
||||
ec2_client.associate_route_table(RouteTableId=route_table_id, SubnetId=subnet_id)
|
||||
print("Associated Route Table with Subnet.")
|
||||
|
||||
return route_table_id
|
||||
|
||||
|
||||
def create_key_pair(ec2_client, key_name, save_to_file):
|
||||
# Create key pair
|
||||
response = ec2_client.create_key_pair(KeyName=key_name)
|
||||
|
||||
# Save private key to file
|
||||
private_key = response['KeyMaterial']
|
||||
with open(save_to_file, 'w') as file:
|
||||
file.write(private_key)
|
||||
|
||||
print(f"Key pair '{key_name}' created and saved to '{save_to_file}'.")
|
||||
return response['KeyName']
|
||||
|
||||
|
||||
def create_security_group(ec2_client, vpc_id):
|
||||
group_name = f"{PREFIX}-sg"
|
||||
|
||||
# Create Security Group
|
||||
response = ec2_client.create_security_group(
|
||||
GroupName=group_name,
|
||||
Description=f"Security group for {PREFIX} webservices",
|
||||
VpcId=vpc_id
|
||||
)
|
||||
|
||||
security_group_id = response['GroupId']
|
||||
print(f"Security group '{group_name}' created with ID: {security_group_id}")
|
||||
|
||||
# Set ingress rules
|
||||
ec2_client.authorize_security_group_ingress(
|
||||
GroupId=security_group_id,
|
||||
IpPermissions=[
|
||||
{
|
||||
'IpProtocol': 'tcp',
|
||||
'FromPort': 22,
|
||||
'ToPort': 22,
|
||||
'IpRanges': [{'CidrIp': '0.0.0.0/0', 'Description': 'SSH access'}]
|
||||
},
|
||||
{
|
||||
'IpProtocol': 'tcp',
|
||||
'FromPort': 8080,
|
||||
'ToPort': 8080,
|
||||
'IpRanges': [{'CidrIp': '0.0.0.0/0', 'Description': 'HTTP access'}]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
print("Ingress rules added for SSH (22) and HTTP (80).")
|
||||
return security_group_id
|
||||
|
||||
|
||||
def create_launch_template(ec2_client, key_name, security_group_id):
|
||||
# Create Launch Template
|
||||
response = ec2_client.create_launch_template(
|
||||
LaunchTemplateName=f"{PREFIX}-lt",
|
||||
LaunchTemplateData={
|
||||
'ImageId': AMI_ID,
|
||||
'InstanceType': INSTANCE_TYPE,
|
||||
'SecurityGroupIds': [security_group_id],
|
||||
'KeyName': key_name,
|
||||
'UserData': base64.b64encode(user_data.encode('utf-8')).decode('utf-8')
|
||||
}
|
||||
)
|
||||
|
||||
print(f"Launch Template created with ID: {response['LaunchTemplate']['LaunchTemplateId']}")
|
||||
return response['LaunchTemplate']['LaunchTemplateId']
|
||||
|
||||
|
||||
def create_target_group(elbv2_client, vpc_id):
|
||||
# Create Target Group
|
||||
response = elbv2_client.create_target_group(
|
||||
Name=f"{PREFIX}-tg",
|
||||
Protocol='HTTP',
|
||||
Port=8080,
|
||||
VpcId=vpc_id,
|
||||
TargetType='instance',
|
||||
IpAddressType='ipv4',
|
||||
HealthCheckProtocol='HTTP',
|
||||
HealthCheckPort='8080',
|
||||
HealthCheckPath='/factor/6',
|
||||
HealthCheckIntervalSeconds=30,
|
||||
HealthCheckTimeoutSeconds=5,
|
||||
HealthyThresholdCount=3,
|
||||
UnhealthyThresholdCount=3,
|
||||
)
|
||||
|
||||
print(f"Target Group created with ARN: {response['TargetGroups'][0]['TargetGroupArn']}")
|
||||
return response['TargetGroups'][0]['TargetGroupArn']
|
||||
|
||||
|
||||
def create_load_balancer(elbv2_client, subnet_ids, security_group_id):
|
||||
# Create Load Balancer
|
||||
response = elbv2_client.create_load_balancer(
|
||||
Name=f"{PREFIX}-lb",
|
||||
Subnets=subnet_ids,
|
||||
SecurityGroups=[security_group_id],
|
||||
Scheme='internet-facing',
|
||||
Type='application',
|
||||
IpAddressType='ipv4'
|
||||
)
|
||||
|
||||
load_balancer_arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||
print(f"Load Balancer created with ARN: {load_balancer_arn}")
|
||||
return load_balancer_arn
|
||||
|
||||
|
||||
def create_load_balancer_listener(elbv2_client, load_balancer_arn, target_group_arn):
|
||||
# Create Load Balancer Listener
|
||||
response = elbv2_client.create_listener(
|
||||
LoadBalancerArn=load_balancer_arn,
|
||||
Protocol='HTTP',
|
||||
Port=8080,
|
||||
DefaultActions=[
|
||||
{
|
||||
'Type': 'forward',
|
||||
'TargetGroupArn': target_group_arn
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
print(f"Listener created with ARN: {response['Listeners'][0]['ListenerArn']}")
|
||||
return response['Listeners'][0]['ListenerArn']
|
||||
|
||||
|
||||
def create_auto_scaling_group(autoscaling_client, launch_template_id, target_group_arn, subnet_id_1, subnet_id_2):
|
||||
# Create Auto Scaling Group
|
||||
response = autoscaling_client.create_auto_scaling_group(
|
||||
AutoScalingGroupName=f"{PREFIX}-asg",
|
||||
LaunchTemplate={
|
||||
'LaunchTemplateId': launch_template_id,
|
||||
'Version': '$Latest'
|
||||
},
|
||||
MinSize=2,
|
||||
MaxSize=5,
|
||||
DesiredCapacity=2,
|
||||
TargetGroupARNs=[target_group_arn],
|
||||
AvailabilityZones=[f"{REGION}a", f"{REGION}b"],
|
||||
HealthCheckType='ELB',
|
||||
HealthCheckGracePeriod=300,
|
||||
VPCZoneIdentifier=f"{subnet_id_1},{subnet_id_2}",
|
||||
Tags=[
|
||||
{
|
||||
'Key': 'Name',
|
||||
'Value': f"{PREFIX}-asg",
|
||||
'PropagateAtLaunch': True
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
print(f"Auto Scaling Group created with ARN: {response['AutoScalingGroups'][0]['AutoScalingGroupARN']}")
|
||||
return response['AutoScalingGroups'][0]['AutoScalingGroupARN']
|
||||
|
||||
def put_scaling_policies(autoscaling_client, asg_arn):
|
||||
# Put Scaling Policies
|
||||
up = autoscaling_client.put_scaling_policy(
|
||||
AutoScalingGroupName=f"{PREFIX}-asg",
|
||||
PolicyName=f"{PREFIX}-scale-up",
|
||||
PolicyType='TargetTrackingScaling',
|
||||
AdjustmentType="ChangeInCapacity",
|
||||
ScalingAdjustment=1,
|
||||
MetricAggregationType="Average",
|
||||
Cooldown=180,
|
||||
TargetTrackingConfiguration={
|
||||
'PredefinedMetricSpecification': {
|
||||
'PredefinedMetricType': 'ASGAverageCPUUtilization'
|
||||
},
|
||||
'TargetValue': 70.0,
|
||||
'DisableScaleIn': False
|
||||
}
|
||||
)
|
||||
|
||||
print(f"Scale-up policy created with ARN: {up['PolicyARN']}")
|
||||
|
||||
down = autoscaling_client.put_scaling_policy(
|
||||
AutoScalingGroupName=f"{PREFIX}-asg",
|
||||
PolicyName=f"{PREFIX}-scale-down",
|
||||
PolicyType='TargetTrackingScaling',
|
||||
AdjustmentType="ChangeInCapacity",
|
||||
ScalingAdjustment=1,
|
||||
MetricAggregationType="Average",
|
||||
Cooldown=180,
|
||||
TargetTrackingConfiguration={
|
||||
'PredefinedMetricSpecification': {
|
||||
'PredefinedMetricType': 'ASGAverageCPUUtilization'
|
||||
},
|
||||
'TargetValue': 30.0,
|
||||
'DisableScaleIn': False
|
||||
}
|
||||
)
|
||||
|
||||
print(f"Scale-down policy created with ARN: {down['PolicyARN']}")
|
||||
return up['PolicyARN'], down['PolicyARN']
|
||||
|
||||
def create_cloudwatch_alarms(cloudwatch_client, asg_name, up_sp, down_sp):
|
||||
# Create CloudWatch Alarms
|
||||
response = cloudwatch_client.put_metric_alarm(
|
||||
AlarmName=f"{PREFIX}-scale-up",
|
||||
ComparisonOperator='GreaterThanThreshold',
|
||||
EvaluationPeriods=1,
|
||||
MetricName='CPUUtilization',
|
||||
Namespace='AWS/EC2',
|
||||
Period=60,
|
||||
Statistic='Average',
|
||||
Threshold=70.0,
|
||||
ActionsEnabled=True,
|
||||
AlarmActions=[up_sp],
|
||||
AlarmDescription='Scale-up alarm',
|
||||
Dimensions=[
|
||||
{
|
||||
'Name': 'AutoScalingGroupName',
|
||||
'Value': f"{PREFIX}-asg"
|
||||
}
|
||||
],
|
||||
Unit='Percent'
|
||||
)
|
||||
|
||||
print(f"Scale-up alarm created with ARN: {response['AlarmArn']}")
|
||||
|
||||
response = cloudwatch_client.put_metric_alarm(
|
||||
AlarmName=f"{PREFIX}-scale-down",
|
||||
ComparisonOperator='LessThanThreshold',
|
||||
EvaluationPeriods=1,
|
||||
MetricName='CPUUtilization',
|
||||
Namespace='AWS/EC2',
|
||||
Period=60,
|
||||
Statistic='Average',
|
||||
Threshold=30.0,
|
||||
ActionsEnabled=True,
|
||||
AlarmActions=[down_sp],
|
||||
AlarmDescription='Scale-down alarm',
|
||||
Dimensions=[
|
||||
{
|
||||
'Name': 'AutoScalingGroupName',
|
||||
'Value': f"{PREFIX}-asg"
|
||||
}
|
||||
],
|
||||
Unit='Percent'
|
||||
)
|
||||
|
||||
print(f"Scale-down alarm created with ARN: {response['AlarmArn']}")
|
||||
|
||||
# Main function
|
||||
def main():
|
||||
# EC2 client
|
||||
ec2_client = boto3.client(
|
||||
'ec2',
|
||||
region_name=REGION
|
||||
)
|
||||
|
||||
# Load Balancer client
|
||||
elbv2_client = boto3.client(
|
||||
'elbv2',
|
||||
region_name=REGION
|
||||
)
|
||||
|
||||
# Auto Scaling client
|
||||
autoscaling_client = boto3.client(
|
||||
'autoscaling',
|
||||
region_name=REGION
|
||||
)
|
||||
|
||||
# CloudWatch client
|
||||
cloudwatch_client = boto3.client(
|
||||
'cloudwatch',
|
||||
region_name=REGION
|
||||
)
|
||||
|
||||
# Create VPC
|
||||
print("Creating VPC...")
|
||||
vpc_id = create_vpc(ec2_client)
|
||||
|
||||
# Create first subnet
|
||||
print("Creating first subnet...")
|
||||
subnet_id_1 = create_subnet(ec2_client, vpc_id, cidr_block='10.0.1.0/24', availability_zone='us-east-1a')
|
||||
|
||||
# Create second subnet
|
||||
print("Creating second subnet...")
|
||||
subnet_id_2 = create_subnet(ec2_client, vpc_id, cidr_block='10.0.2.0/24', availability_zone='us-east-1b')
|
||||
|
||||
# Create Internet Gateway
|
||||
print("Creating Internet Gateway...")
|
||||
igw_id = create_internet_gateway(ec2_client, vpc_id)
|
||||
|
||||
# Create Route Table
|
||||
print("Creating Route Table...")
|
||||
route_table_id = create_route_table(ec2_client, vpc_id, subnet_id_1, igw_id)
|
||||
|
||||
# Create key pair
|
||||
print("Creating key pair...")
|
||||
key_name = create_key_pair(ec2_client, f"{PREFIX}-key", f"{PREFIX}-key.pem")
|
||||
|
||||
# Create security group
|
||||
print("Creating security group...")
|
||||
security_group_id = create_security_group(ec2_client, vpc_id)
|
||||
|
||||
# Create Launch Template
|
||||
print("Creating Launch Template...")
|
||||
launch_template_id = create_launch_template(ec2_client, key_name, security_group_id)
|
||||
|
||||
# Create Target Group for ALB
|
||||
print("Creating Target Group...")
|
||||
target_group_arn = create_target_group(elbv2_client, vpc_id)
|
||||
|
||||
# Create Load Balancer
|
||||
print("Creating Load Balancer...")
|
||||
load_balancer_arn = create_load_balancer(elbv2_client, [subnet_id_1, subnet_id_2], security_group_id)
|
||||
|
||||
# Create Load Balancer Listener
|
||||
print("Creating Load Balancer Listener...")
|
||||
listener_arn = create_load_balancer_listener(elbv2_client, load_balancer_arn, target_group_arn)
|
||||
|
||||
# Auto Scaling Group
|
||||
print("Creating Auto Scaling Group...")
|
||||
asg_arn = create_auto_scaling_group(autoscaling_client, launch_template_id, target_group_arn, subnet_id_1, subnet_id_2)
|
||||
|
||||
# Scaling Policies
|
||||
print("Creating Scaling Policies...")
|
||||
up_sp, down_sp = put_scaling_policies(autoscaling_client, asg_arn)
|
||||
|
||||
# CloudWatch Alarms
|
||||
print("Creating CloudWatch Alarms...")
|
||||
create_cloudwatch_alarms(cloudwatch_client, f"{PREFIX}-asg", up_sp, down_sp)
|
||||
|
||||
# Load Balancer DNS name
|
||||
response = elbv2_client.describe_load_balancers(
|
||||
LoadBalancerArns=[load_balancer_arn]
|
||||
)
|
||||
dns_name = response['LoadBalancers'][0]['DNSName']
|
||||
print(f"Load Balancer DNS name: {dns_name}")
|
||||
|
||||
# Save AWS resources to file
|
||||
aws_resources = {
|
||||
'vpc_id': vpc_id,
|
||||
'subnet_ids': [subnet_id_1, subnet_id_2],
|
||||
'igw_id': igw_id,
|
||||
'route_table_id': route_table_id,
|
||||
'key_name': key_name,
|
||||
'security_group_id': security_group_id,
|
||||
'launch_template_id': launch_template_id,
|
||||
'target_group_arn': target_group_arn,
|
||||
'load_balancer_arn': load_balancer_arn,
|
||||
'listener_arn': listener_arn,
|
||||
'asg_name': f"{PREFIX}-asg",
|
||||
'up_sp_arn': up_sp,
|
||||
'down_sp_arn': down_sp,
|
||||
'dns_name': dns_name,
|
||||
}
|
||||
|
||||
with open(AWS_RESOURCES_FILE, 'w') as file:
|
||||
json.dump(aws_resources, file, indent=4)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user