Feat: Adds base project
This commit is contained in:
240
infra/ecs_alb/ecs.py
Normal file
240
infra/ecs_alb/ecs.py
Normal file
@@ -0,0 +1,240 @@
|
||||
import pulumi
|
||||
import pulumi_aws as aws
|
||||
import conf as config
|
||||
import iam
|
||||
import ecr
|
||||
import json
|
||||
|
||||
def deploy_app(config_ecs_app, app_ecs_cluster, alb_security_group, app_load_balancer_arn):
|
||||
lb_configs = config_ecs_app["lb_configs"]
|
||||
target_groups = []
|
||||
load_balancers = []
|
||||
|
||||
for lb_config in lb_configs:
|
||||
tg = aws.lb.TargetGroup(f"app-target-group-{lb_config['listener_port']}",
|
||||
port=lb_config["target_port"],
|
||||
protocol="HTTP",
|
||||
vpc_id=config.network["vpc_id"],
|
||||
target_type="ip",
|
||||
health_check=aws.lb.TargetGroupHealthCheckArgs(
|
||||
path="/",
|
||||
protocol="HTTP",
|
||||
port="traffic-port",
|
||||
healthy_threshold=2,
|
||||
unhealthy_threshold=2,
|
||||
timeout=5,
|
||||
interval=30,
|
||||
matcher="200-499",
|
||||
),
|
||||
)
|
||||
aws.lb.Listener(f"app-listener-{lb_config['listener_port']}",
|
||||
load_balancer_arn=app_load_balancer_arn,
|
||||
port=lb_config["listener_port"],
|
||||
protocol="HTTP",
|
||||
default_actions=[aws.lb.ListenerDefaultActionArgs(
|
||||
type="forward",
|
||||
target_group_arn=tg.arn,
|
||||
)],
|
||||
)
|
||||
target_groups.append(tg)
|
||||
load_balancers.append(aws.ecs.ServiceLoadBalancerArgs(
|
||||
target_group_arn=tg.arn,
|
||||
container_name=f"{config.project_name}-{config_ecs_app['task_name']}-{config.environment}-service",
|
||||
container_port=lb_config["target_port"],
|
||||
))
|
||||
|
||||
# Build and Push ECR
|
||||
# ecr_repos = ecr.create_ecr_repo(config_ecs_app['ecr_repo_name'])
|
||||
# assert ('ecr_image_tag' in config_ecs_app.keys()) != ('ecr_image_digest' in config_ecs_app.keys()), 'User must provide either tag or image_digest, but not both, to identify image version'
|
||||
if 'ecr_image_tag' in config_ecs_app.keys():
|
||||
ecr_repo_image = ecr.get_image(config_ecs_app['ecr_repo_name'], image_tag=config_ecs_app['ecr_image_tag'])
|
||||
elif 'ecr_image_digest' in config_ecs_app.keys():
|
||||
ecr_repo_image = ecr.get_image(config_ecs_app['ecr_repo_name'], image_digest=config_ecs_app['ecr_image_digest'])
|
||||
|
||||
|
||||
# Log Group Setup #TODO move into ecs
|
||||
app_log_group = aws.cloudwatch.LogGroup(f"{config.project_name}-{config_ecs_app['task_name']}-log-group", retention_in_days=7)
|
||||
|
||||
|
||||
# if key
|
||||
# ssm_parameter, key = kms.setup_kms()
|
||||
# iam.create_execution_role_with_keys(ssm_parameter, key)
|
||||
# IAM Roles Setup
|
||||
app_execution_role = iam.create_execution_role()
|
||||
app_task_role = iam.create_task_role()
|
||||
|
||||
# summarization_repo_image = config_ecs_app['ecr_image']
|
||||
|
||||
if config_ecs_app['use_load_balancer']:
|
||||
environemnt_variables = [dict(name=k, value=v) for k,v in config_ecs_app['env_variables'].items()]
|
||||
print(environemnt_variables)
|
||||
# ECS Task Definition Setup
|
||||
app_task_definition = aws.ecs.TaskDefinition(f"{config.project_name}-{config_ecs_app['task_name']}-task-definition",
|
||||
family=f"{config.project_name}-{config_ecs_app['task_name']}-{config.environment}",
|
||||
cpu=config_ecs_app["cpu"],
|
||||
memory=config_ecs_app["memory"],
|
||||
network_mode="awsvpc",
|
||||
execution_role_arn=app_execution_role.arn,
|
||||
task_role_arn=app_task_role.arn,
|
||||
requires_compatibilities=["FARGATE"],
|
||||
container_definitions=pulumi.Output.all(ecr_repo_image.image_uri,
|
||||
# ecr_repo_image.image_digest,
|
||||
app_log_group.name,
|
||||
environemnt_variables,
|
||||
# config_ecs_app["secret_name"],
|
||||
).apply(lambda args: json.dumps([{
|
||||
"name": f"{config.project_name}-{config_ecs_app['task_name']}-{config.environment}-service",
|
||||
"image": args[0],
|
||||
"cpu": 0,
|
||||
"portMappings": [
|
||||
{
|
||||
"name": lb_cfg["name"],
|
||||
"containerPort": lb_cfg["container_port"],
|
||||
"hostPort": lb_cfg["target_port"],
|
||||
"protocol": "tcp",
|
||||
} for lb_cfg in lb_configs
|
||||
],
|
||||
"essential": True,
|
||||
"logConfiguration": {
|
||||
"logDriver": "awslogs",
|
||||
"options": {
|
||||
"awslogs-group": args[1],
|
||||
"awslogs-region": config.aws_region,
|
||||
"awslogs-stream-prefix": "pulumi-langserve",
|
||||
},
|
||||
},
|
||||
"environment": args[2],
|
||||
}])),
|
||||
)
|
||||
|
||||
# ECS Security Group Setup
|
||||
app_ecs_security_group = aws.ec2.SecurityGroup(f"{config.project_name}-{config_ecs_app['task_name']}-ecs-security-group",
|
||||
vpc_id=config.network["vpc_id"],
|
||||
ingress=[aws.ec2.SecurityGroupIngressArgs(
|
||||
protocol="-1",
|
||||
from_port=0,
|
||||
to_port=0,
|
||||
security_groups=[alb_security_group.id],
|
||||
)],
|
||||
egress=[aws.ec2.SecurityGroupEgressArgs(
|
||||
protocol="-1",
|
||||
from_port=0,
|
||||
to_port=0,
|
||||
cidr_blocks=["0.0.0.0/0"],
|
||||
)],
|
||||
)
|
||||
|
||||
# Security Group Rules for Ingress
|
||||
for sg_name, sg_id in config_ecs_app["sgs_allowing_ingress"].items():
|
||||
aws.ec2.SecurityGroupRule(f"sgr-{sg_name}-allow_in_from-{config.project_name}",
|
||||
type="ingress",
|
||||
from_port=0,
|
||||
to_port=0,
|
||||
protocol="-1",
|
||||
security_group_id=sg_id,
|
||||
source_security_group_id=app_ecs_security_group.id,
|
||||
description=f"Allow from {config.project_name} ECS SG",
|
||||
)
|
||||
|
||||
# Service Discovery Namespace Setup
|
||||
app_service_discovery_namespace = aws.servicediscovery.PrivateDnsNamespace(f"{config.project_name}-{config_ecs_app['task_name']}-service-discovery-namespace",
|
||||
name=f"{config.environment}.{config.project_name}.local",
|
||||
vpc=config.network["vpc_id"],
|
||||
)
|
||||
|
||||
# ECS Service Setup
|
||||
app_service = aws.ecs.Service(f"{config.project_name}-{config_ecs_app['task_name']}-service",
|
||||
cluster=app_ecs_cluster.arn,
|
||||
task_definition=app_task_definition.arn,
|
||||
desired_count=config_ecs_app["desired_count"],
|
||||
launch_type="FARGATE",
|
||||
network_configuration=aws.ecs.ServiceNetworkConfigurationArgs(
|
||||
assign_public_ip=True,
|
||||
security_groups=[app_ecs_security_group.id],
|
||||
subnets=config.network["ecs_subnet_ids"],
|
||||
),
|
||||
load_balancers=load_balancers,
|
||||
scheduling_strategy="REPLICA",
|
||||
service_connect_configuration=aws.ecs.ServiceServiceConnectConfigurationArgs(
|
||||
enabled=True,
|
||||
namespace=app_service_discovery_namespace.arn,
|
||||
),
|
||||
tags={"Name": f"{config.project_name}-{config_ecs_app['task_name']}-{config.environment}"},
|
||||
)
|
||||
|
||||
#defining an auto-scaling for summarization
|
||||
scalable_target = aws.appautoscaling.Target("app-svc-target",
|
||||
max_capacity=config_ecs_app['auto_scaling']['max_capacity'],
|
||||
min_capacity=config_ecs_app['auto_scaling']['min_capacity'],
|
||||
resource_id=pulumi.Output.all(app_ecs_cluster.name, app_service.name).apply(lambda args: f"service/{args[0]}/{args[1]}"),
|
||||
scalable_dimension="ecs:service:DesiredCount",
|
||||
service_namespace="ecs",
|
||||
)
|
||||
|
||||
# Define an auto-scaling policy on CPU utilization
|
||||
scaling_policy = aws.appautoscaling.Policy("app-svc-policy",
|
||||
policy_type="TargetTrackingScaling",
|
||||
resource_id=scalable_target.resource_id,
|
||||
scalable_dimension="ecs:service:DesiredCount",
|
||||
service_namespace="ecs",
|
||||
target_tracking_scaling_policy_configuration={
|
||||
"target_value": config_ecs_app['auto_scaling']['target_value'], # Target CPU utilization (30%)
|
||||
"predefined_metric_specification": {
|
||||
"predefined_metric_type": "ECSServiceAverageCPUUtilization"
|
||||
},
|
||||
},
|
||||
)
|
||||
else:
|
||||
# classification_repo_image = ecr_repo_images['ai-med-exam-classification']['ecr_image']
|
||||
# ECS without Load Balancer
|
||||
new_ecs_task_definition = aws.ecs.TaskDefinition("classification-theia-poc-task-definition",
|
||||
family="classification-theia-poc",
|
||||
cpu=config_ecs_app["cpu"],
|
||||
memory=config_ecs_app["memory"],
|
||||
network_mode="awsvpc",
|
||||
execution_role_arn=app_execution_role.arn,
|
||||
task_role_arn=app_task_role.arn,
|
||||
requires_compatibilities=["FARGATE"],
|
||||
container_definitions=pulumi.Output.all(ecr_repo_image.image_uri,
|
||||
# classification_repo_image.image_digest,
|
||||
app_log_group.name).apply(lambda args: json.dumps([{
|
||||
"name": "classification-theia-poc-service",
|
||||
"image": args[0],
|
||||
"cpu": 0,
|
||||
"portMappings": [
|
||||
{
|
||||
"name": "api",
|
||||
"containerPort": 80, # Define the container port without Load Balancer
|
||||
"hostPort": 80,
|
||||
"protocol": "tcp",
|
||||
}
|
||||
],
|
||||
"essential": True,
|
||||
"logConfiguration": {
|
||||
"logDriver": "awslogs",
|
||||
"options": {
|
||||
"awslogs-group": args[1],
|
||||
"awslogs-region": config.aws_region,
|
||||
"awslogs-stream-prefix": "pulumi-classification-theia-poc",
|
||||
},
|
||||
},
|
||||
}])),
|
||||
)
|
||||
# ecs without load balancer
|
||||
new_ecs_service = aws.ecs.Service("classification-theia-poc-service",
|
||||
cluster=app_ecs_cluster.arn,
|
||||
task_definition=new_ecs_task_definition.arn,
|
||||
desired_count=config_ecs_app["desired_count"],
|
||||
launch_type="FARGATE",
|
||||
network_configuration=aws.ecs.ServiceNetworkConfigurationArgs(
|
||||
assign_public_ip=True,
|
||||
security_groups=[app_ecs_security_group.id],
|
||||
subnets=config.network["ecs_subnet_ids"],
|
||||
),
|
||||
scheduling_strategy="REPLICA",
|
||||
service_connect_configuration=aws.ecs.ServiceServiceConnectConfigurationArgs(
|
||||
enabled=True,
|
||||
namespace=app_service_discovery_namespace.arn,
|
||||
),
|
||||
tags={"Name": "classification-theia-poc"},
|
||||
)
|
||||
Reference in New Issue
Block a user