| 16 | from constructs import Construct |
| 17 | |
| 18 | class EcsStack(NestedStack): |
| 19 | |
| 20 | def __init__(self, scope: Construct, construct_id: str, vpc: ec2.Vpc, frontend_repository: ecr_assets.DockerImageAsset, backend_data_repository: ecr_assets.DockerImageAsset, **kwargs) -> None: |
| 21 | super().__init__(scope, construct_id, **kwargs) |
| 22 | # Creating the ECS Cluster and the cloud map namespace |
| 23 | ecs_cluster = ecs.Cluster(self, "ECSCluster", |
| 24 | vpc=vpc, |
| 25 | cluster_name="App-Service-Connect-Cluster", |
| 26 | container_insights=True) |
| 27 | default_cloud_map_namespace=ecs_cluster.add_default_cloud_map_namespace(name="scapp.local", use_for_service_connect=True, type=servicediscovery.NamespaceType.DNS_PRIVATE) |
| 28 | # Creating the Cloudwatch log group where ECS Logs will be stored |
| 29 | ECSServiceLogGroup = logs.LogGroup(self, "ECSServiceLogGroup", |
| 30 | log_group_name=f"{ecs_cluster.cluster_name}-service", |
| 31 | removal_policy=RemovalPolicy.DESTROY, |
| 32 | retention=logs.RetentionDays.FIVE_DAYS, |
| 33 | ) |
| 34 | # Creating the task and execution IAM roles that the containers will assume to read and write to cloudwatch, Task Execution |
| 35 | # Role will read from ECR |
| 36 | ECSTaskIamRole = iam.Role(self, "ECSTaskIamRole", |
| 37 | assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"), |
| 38 | managed_policies=[ |
| 39 | iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchFullAccess"), |
| 40 | ], |
| 41 | ) |
| 42 | TaskExecutionRole = iam.Role(self, "TaskexecutionRole", |
| 43 | assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"), |
| 44 | managed_policies=[ |
| 45 | iam.ManagedPolicy.from_aws_managed_policy_name("AmazonEC2ContainerRegistryReadOnly"), |
| 46 | iam.ManagedPolicy.from_aws_managed_policy_name("CloudWatchLogsFullAccess"), |
| 47 | ], |
| 48 | ) |
| 49 | # ECS Security group, this will allow access from the Load Balancer and allow LAN access so that the |
| 50 | # ECS containers can talk to eachother on port 5001 (which is the port that the backend uses) |
| 51 | ECSSecurityGroup = ec2.SecurityGroup(self, "ECSSecurityGroup", |
| 52 | vpc=vpc, |
| 53 | description="ECS Security Group", |
| 54 | allow_all_outbound=True, |
| 55 | ) |
| 56 | ECSSecurityGroup.add_ingress_rule(ec2.Peer.ipv4(vpc.vpc_cidr_block), ec2.Port.tcp(5001), description="All traffic within VPC",) |
| 57 | # Task definitions for the frontend and backend |
| 58 | frontend_definition = ecs.FargateTaskDefinition( |
| 59 | self, f"FrontendTaskDefinition", |
| 60 | family="frontend", |
| 61 | cpu=256, |
| 62 | memory_limit_mib=512, |
| 63 | task_role=TaskExecutionRole, |
| 64 | execution_role=ECSTaskIamRole |
| 65 | ) |
| 66 | backend_definition = ecs.FargateTaskDefinition( |
| 67 | self, f"BackendTaskDefinition", |
| 68 | family="backend", |
| 69 | cpu=256, |
| 70 | memory_limit_mib=512, |
| 71 | task_role=TaskExecutionRole, |
| 72 | execution_role=ECSTaskIamRole |
| 73 | ) |
| 74 | |
| 75 | # Containers for each application, when the frontend is hit on /get-data it makes a call to the backend endpoint /data |