air-tech-assessment/air-tech/__main__.py
Alexander Hosking cf369c6a3a This is nearly working in all Pulumi.
Permissions are not correct in code to allow the images
to be pulled by the ECS tasks. As such, they will not start
and run without some manual intervention.

Pulumi will happily let the process sit at this stage
forever.
2023-09-07 00:49:03 -04:00

217 lines
6.6 KiB
Python

import pulumi
from pulumi import Config, Output, export
import pulumi_aws as aws
from pulumi_aws import acm, alb, ecs, ec2, lb, iam, ecr
import pulumi_awsx as awsx
import json
config = Config()
# container_port = config.get_int("containerPort", 80)
cpu = config.get_int("cpu", 512)
memory = config.get_int("memory", 128)
# Create a VPC
vpc = ec2.Vpc("production", cidr_block="10.0.0.0/16")
# Create a Gateway
ig = ec2.InternetGateway("internet-gateway", vpc_id=vpc.id)
cert = acm.Certificate(
"air-tech",
domain_name="air-tech.ahosking.com",
validation_method="DNS",
)
# Public Subnet
public_subnet = ec2.Subnet(
"public-subnet",
vpc_id=vpc.id,
cidr_block="10.0.1.0/26",
availability_zone="us-east-2a",
# Allow the Internet Gateway to handle public traffic
map_public_ip_on_launch=True
)
public_subnet2 = ec2.Subnet(
"public-subnet2",
vpc_id=vpc.id,
cidr_block="10.0.2.0/26",
availability_zone="us-east-2b",
# Allow the Internet Gateway to handle public traffic
map_public_ip_on_launch=True
)
# Associate the Gateway to a route
route_table = ec2.RouteTable('route-table', vpc_id=vpc.id)
route = ec2.Route('route', route_table_id=route_table.id,
destination_cidr_block='0.0.0.0/0', gateway_id=ig.id)
# Private Subnet
private_subnet = ec2.Subnet(
"private-subnet",
vpc_id=vpc.id,
cidr_block="10.0.3.0/26",
availability_zone="us-east-2a",
map_public_ip_on_launch=False
)
private_subnet2 = ec2.Subnet(
"private-subnet2",
vpc_id=vpc.id,
cidr_block="10.0.4.0/26",
availability_zone="us-east-2b",
map_public_ip_on_launch=False
)
repo = ecr.Repository("repo")
# Create an IAM role
ecs_task_execution_role = iam.Role("ecsExecutionRole",
path="/",
assume_role_policy=iam.get_policy_document(statements=[{
"actions": ["sts:AssumeRole"],
"principals": {
"type": "Service",
"identifiers": ["ecs-tasks.amazonaws.com"]
}
}
]).json,
)
# Attach a policy to the execution role that will allow it to pull images from ECR
iam.RolePolicy("accessECRImages",
role=ecs_task_execution_role.id,
policy={
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
],
"Resource": repo.repository_arn
}
]
}
)
image_web = awsx.ecr.Image(
"image_web",
repository_url=repo.url,
path=".",
dockerfile=".\infra-web\Dockerfile")
image_api = awsx.ecr.Image(
"image_api",
repository_url=repo.url,
path=".",
dockerfile=".\infra-api\Dockerfile")
security_group = aws.ec2.SecurityGroup(
"securityGroup",
vpc_id=vpc.id,
egress=[aws.ec2.SecurityGroupEgressArgs(
from_port=0,
to_port=0,
protocol="-1",
cidr_blocks=["0.0.0.0/0"],
ipv6_cidr_blocks=["::/0"],
)])
# Create an ECS Cluster
cluster = ecs.Cluster("cluster")
pulumi.export("certificateArn", cert.arn)
loadbalancer = lb.LoadBalancer(
"loadbalancer",
load_balancer_type="application",
security_groups=[security_group.id],
subnets=[public_subnet.id, public_subnet2.id])
target_group = lb.TargetGroup('target-group',
port=5000,
protocol="HTTP",
target_type="ip",
vpc_id=vpc.id)
# Create a listener for the ALB at port 80
listener = lb.Listener('listener',
load_balancer_arn=loadbalancer.arn,
port=80,
default_actions=[{
'type': "forward",
'target_group_arn': target_group.arn # Forward to our target group
}])
web_sg = ec2.SecurityGroup('web-sg',
vpc_id=vpc.id,
ingress=[
{
'protocol': 'tcp',
'from_port': 80,
'to_port': 80,
'cidr_blocks': ['0.0.0.0/0'],
}
],
egress=[
{
'protocol': '-1',
'from_port': 0,
'to_port': 0,
'cidr_blocks': ['0.0.0.0/0'],
}
]
)
api = awsx.ecs.FargateService(
"api",
cluster=cluster.arn,
network_configuration={
'assignPublicIp': "false",
'subnets': [private_subnet.id],
'securityGroups': [web_sg.id]
},
task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
name="theApi",
image=image_api.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=5000,
host_port=5000,
)],
),
))
service = awsx.ecs.FargateService(
"web",
cluster=cluster.arn,
network_configuration={
'assignPublicIp': "true",
'subnets': [public_subnet.id],
'securityGroups': [web_sg.id]
},
# assign_public_ip=True,
task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
name="theOne",
image=image_web.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=5000,
host_port=5000,
target_group=target_group,
)],
),
),
opts=pulumi.ResourceOptions(depends_on=[api, target_group])
)