예제 #1
0
    def __init__(self, scope: core.Construct, id: str, config: ContainerPipelineConfiguration, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # VPC
        vpc = ec2.Vpc(self, "TheVPC",
                      cidr="10.0.0.0/16",
                      nat_gateways=1,
                      )

        # IAM roles
        service_task_def_exe_role = iam.Role(
            self, "ServiceTaskDefExecutionRole",
            assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com')
            )

        service_task_def_exe_role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name('service-role/AmazonECSTaskExecutionRolePolicy'))

        service_task_def_role = iam.Role(
            self, 'ServiceTaskDefTaskRole',
            assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com')
        )

        # Fargate cluster
        cluster = ecs.Cluster(
            scope=self,
            id="ecs-cluster",
            cluster_name=config.ProjectName + "-" + config.stage,
            vpc=vpc
        )

        load_balancer = elbv2.ApplicationLoadBalancer(
            self, "load_balancer",
            vpc=vpc,
            internet_facing=True
        )

        # Security Group
        service_sg = ec2.SecurityGroup(self, "service_sg", vpc=vpc)
        service_sg.connections.allow_from(load_balancer, ec2.Port.tcp(80));

        # ECR Repo
        image_repo = ecr.Repository.from_repository_name(self, "image_repo",
                                                         repository_name=config.ProjectName
                                                         )

        log_group = logs.LogGroup(self, "log_group",
                                  log_group_name=config.ProjectName + "-" + config.stage,
                                  removal_policy=core.RemovalPolicy.DESTROY,
                                  retention=None
                                  )
        # ECS Task Def
        fargate_task_definition = ecs.FargateTaskDefinition(
            scope=self,
            id="fargate_task_definition",
            cpu=1024,
            memory_limit_mib=2048,
            execution_role=service_task_def_exe_role,
            task_role=service_task_def_role,
            family=config.ProjectName + "-" + config.stage
        )

        container = fargate_task_definition.add_container(
            id="fargate_task_container",
            image=ecs.ContainerImage.from_ecr_repository(repository=image_repo, tag='release')
        )

        container.add_port_mappings(ecs.PortMapping(container_port=8080, host_port=8080, protocol=ecs.Protocol.TCP))

        # ECS Fargate Service
        fargate_service = ecs.FargateService(
            scope=self,
            id="fargate_service",
            security_group=service_sg,
            cluster=cluster,
            desired_count=2,
            deployment_controller=ecs.DeploymentController(type=ecs.DeploymentControllerType.ECS),
            task_definition=fargate_task_definition,
            service_name=config.ProjectName + "-" + config.stage
        )

        # Main Env
        listern_health_check_main = elbv2.HealthCheck(
            healthy_http_codes='200',
            interval=core.Duration.seconds(5),
            healthy_threshold_count=2,
            unhealthy_threshold_count=3,
            timeout=core.Duration.seconds(4)
        )
        # Test Env
        listern_health_check_test = elbv2.HealthCheck(
            healthy_http_codes='200',
            interval=core.Duration.seconds(5),
            healthy_threshold_count=2,
            unhealthy_threshold_count=3,
            timeout=core.Duration.seconds(4)
        )

        listener_main = load_balancer.add_listener("load_balancer_listener_1",
                                                   port=80,
                                                   )

        listern_main_targets = listener_main.add_targets("load_balancer_target_1", port=8080,
                                                         health_check=listern_health_check_main,
                                                         targets=[fargate_service]
                                                         )

        # Alarms: monitor 500s on target group
        aws_cloudwatch.Alarm(self, "TargetGroup5xx",
                             metric=listern_main_targets.metric_http_code_target(elbv2.HttpCodeTarget.TARGET_5XX_COUNT),
                             threshold=1,
                             evaluation_periods=1,
                             period=core.Duration.minutes(1)
                             )

        # Alarms: monitor unhealthy hosts on target group
        aws_cloudwatch.Alarm(self, "TargetGroupUnhealthyHosts",
                             metric=listern_main_targets.metric('UnHealthyHostCount'),
                             threshold=1,
                             evaluation_periods=1,
                             period=core.Duration.minutes(1)
                             )

        core.CfnOutput(self, "lburl",
                       value=load_balancer.load_balancer_dns_name,
                       export_name="LoadBalancerUrl"
                       )
예제 #2
0
from aws_cdk import (aws_autoscaling as autoscaling, aws_ec2 as ec2,
                     aws_elasticloadbalancingv2 as elbv2, aws_ecs as ecs, App,
                     CfnOutput, Duration, Stack)

app = App()
stack = Stack(app, "aws-ec2-integ-ecs")

# Create a cluster
vpc = ec2.Vpc(stack, "MyVpc", max_azs=2)

cluster = ecs.Cluster(stack, 'EcsCluster', vpc=vpc)

asg = autoscaling.AutoScalingGroup(
    stack,
    "DefaultAutoScalingGroup",
    instance_type=ec2.InstanceType.of(ec2.InstanceClass.STANDARD5,
                                      ec2.InstanceSize.MICRO),
    machine_image=ecs.EcsOptimizedImage.amazon_linux2(),
    vpc=vpc,
)
capacity_provider = ecs.AsgCapacityProvider(stack,
                                            "AsgCapacityProvider",
                                            auto_scaling_group=asg)
cluster.add_asg_capacity_provider(capacity_provider)

# Create Task Definition
task_definition = ecs.Ec2TaskDefinition(stack, "TaskDef")
container = task_definition.add_container(
    "web",
    image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample"),
    memory_limit_mib=256)
예제 #3
0
    def __init__(self, scope: core.Construct, id: str, *, app_env: str, vpc: ec2.Vpc, rds: rds.CfnDBInstance,
                 repository: ecr.Repository, log_group: logs.LogGroup, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        cluster = ecs.Cluster(self, 'staff-cluster', cluster_name=f'staff-cluster-{app_env}', vpc=vpc)

        # task definition
        task_definition = ecs.FargateTaskDefinition(self, f'staff-task-def-{app_env}', cpu=512, memory_limit_mib=1024)
        admin_url = _.from_string_parameter_name(self, "admin_url", f'/{app_env}/ssm/ADMIN_URL')
        db_name = _.from_string_parameter_name(self, "database_name", f'/{app_env}/ssm/DATABASE_NAME')
        test_db_name = _.from_string_parameter_name(self, "test_database_name", f'/{app_env}/ssm/TEST_DATABASE_NAME')
        db_user = _.from_string_parameter_name(self, "database_user", f'/{app_env}/ssm/DATABASE_USER')
        db_pass = _.from_string_parameter_name(self, "database_pass", f'/{app_env}/ssm/DATABASE_PASSWORD')
        db_port = _.from_string_parameter_name(self, "database_port", f'/{app_env}/ssm/DATABASE_PORT')
        email_host_user = _.from_string_parameter_name(self, "email_host_user", f'/{app_env}/ssm/EMAIL_HOST_USER')
        email_host_pass = _.from_string_parameter_name(self, "email_host_pass", f'/{app_env}/ssm/EMAIL_HOST_PASSWORD')
        broker_url = _.from_string_parameter_name(self, "celery_broker_url", f'/{app_env}/ssm/CELERY_BROKER_URL')
        backend = _.from_string_parameter_name(self, "celery_result_backend", f'/{app_env}/ssm/CELERY_RESULT_BACKEND')
        log_level = _.from_string_parameter_name(self, "celery_log_level", f'/{app_env}/ssm/CELERY_LOG_LEVEL')
        gen_queue = _.from_string_parameter_name(self, "celery_general_queue", f'/{app_env}/ssm/CELERY_GENERAL_QUEUE')
        report_queue = _.from_string_parameter_name(self, "celery_report_queue", f'/{app_env}/ssm/CELERY_REPORT_QUEUE')
        system_email = _.from_string_parameter_name(self, "system_email", f'/{app_env}/ssm/SYSTEM_EMAIL')
        system_password = _.from_string_parameter_name(self, "system_password", f'/{app_env}/ssm/SYSTEM_PASSWORD')

        task_definition_params = {
            'image': ecs.ContainerImage.from_ecr_repository(repository, tag=app_env),
            'environment': {
                    'ENV': f'{app_env}',
                    'PROJECT': 'ssm',
                    'PYTHONPATH': '/var/staff/ssm/',
                    'CORS_ORIGIN_ALLOW_ALL': 'True',
                    'DJANGO_SETTINGS_MODULE': 'ssm.settings',
                    'DATABASE_HOST': rds.attr_endpoint_address,
             },
            'secrets': {
                    'ADMIN_URL': ecs.Secret.from_ssm_parameter(admin_url),
                    'DATABASE_NAME': ecs.Secret.from_ssm_parameter(db_name),
                    'TEST_DATABASE_NAME': ecs.Secret.from_ssm_parameter(test_db_name),
                    'DATABASE_USER': ecs.Secret.from_ssm_parameter(db_user),
                    'DATABASE_PASSWORD': ecs.Secret.from_ssm_parameter(db_pass),
                    'DATABASE_PORT': ecs.Secret.from_ssm_parameter(db_port),
                    'EMAIL_HOST_USER': ecs.Secret.from_ssm_parameter(email_host_user),
                    'EMAIL_HOST_PASSWORD': ecs.Secret.from_ssm_parameter(email_host_pass),
                    'CELERY_BROKER_URL': ecs.Secret.from_ssm_parameter(broker_url),
                    'CELERY_RESULT_BACKEND': ecs.Secret.from_ssm_parameter(backend),
                    'CELERY_LOG_LEVEL': ecs.Secret.from_ssm_parameter(log_level),
                    'CELERY_GENERAL_QUEUE': ecs.Secret.from_ssm_parameter(gen_queue),
                    'CELERY_REPORT_QUEUE': ecs.Secret.from_ssm_parameter(report_queue),
                    'SYSTEM_EMAIL': ecs.Secret.from_ssm_parameter(system_email),
                    'SYSTEM_PASSWORD': ecs.Secret.from_ssm_parameter(system_password),
             },
            'logging': ecs.LogDriver(stream_prefix='ecs-', log_group=log_group)
        }
        container = task_definition.add_container("web", **task_definition_params)
        container.add_port_mappings(container_port=80)

        # fargate service
        service_sg_params = {
            'security_group_name': f'staff-fargate-service-security-group-{app_env}',
            'description': f'staff balancer security group for {app_env}',
            'vpc': vpc,
        }
        service_sc = ec2.SecurityGroup(self, f'staff-balancer-security-group', **service_sg_params)
        service_sc.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80), 'allow 80 port access from the world')
        service_sc.add_egress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80), '')
        service_params = {
            'service_name': 'staff-fargate-service',
            'cluster': cluster,
            'task_definition': task_definition,
            'desired_count': 1,
            'assign_public_ip': True,
            'security_group': service_sc,
            'vpc_subnets': vpc.public_subnets,
        }
        service = ecs.FargateService(self, 'staff-fargate-service', **service_params)

        # application load balancer
        balancer_sg_params = {
            'security_group_name': f'staff-balancer-security-group-{app_env}',
            'description': f'staff balancer security group for {app_env}',
            'vpc': vpc,
        }
        balancer_sc = ec2.SecurityGroup(self, f'staff-balancer-security-group', **balancer_sg_params)
        balancer_sc.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80), 'allow 80 port access from the world')
        balancer_sc.add_egress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80), '')

        balancer_params = {
            'http2_enabled': True,
            'ip_address_type': elbv2.IpAddressType.IPV4,
            'security_group': balancer_sc,
            'vpc': vpc,
            'deletion_protection': False,
            'internet_facing': True,
            'load_balancer_name': f'staff-application-balancer-{app_env}',
            'vpc_subnets': vpc.public_subnets,
        }
        balancer = elbv2.ApplicationLoadBalancer(self, 'staff-application-balancer', **balancer_params)
        listener = balancer.add_listener('staff-listener', open=True, port=80)
        listener.add_target_groups('staff-target-group', target_groups=[service.load_balancer_target(
            container_name='web', container_port=80,
        )])
예제 #4
0
driveropts={
    "type": "nfs",
    "device":device_set,
    "o": efs_to_connect
    #"o": "addr=fs-XXXXXX.efs.us-east-1.amazonaws.com,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"

}

docker_vol_config=ecs.DockerVolumeConfiguration(driver='local', scope=ecs.Scope.TASK, driver_opts=driveropts, labels=None)

docker_volume=ecs.Volume(name='docker_vol',docker_volume_configuration=docker_vol_config)

efs_mount=ecs.MountPoint(container_path='/efs',read_only=True, source_volume='docker_vol')

cluster = ecs.Cluster(
    stack, "wes-onetest-ecs",
    vpc=vpc
)
cluster.add_capacity("DefaultAutoScalingGroup",
                     instance_type=ec2.InstanceType("c5.xlarge"), key_name='aws-eb',max_capacity=4,machine_image=amitouse,
                     desired_capacity=2,min_capacity=2)

# Create a task definition with its own elastic network interface

iam.ServicePrincipal('task')

task_definition_vistaweb = ecs.Ec2TaskDefinition(
    stack, "west-onetest-task-vistaweb",
    network_mode=ecs.NetworkMode.AWS_VPC,
    volumes=[docker_volume]
)
    def __init__(self, scope: core.Construct, construct_id: str,
                 properties: WordpressStackProperties, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        database = rds.ServerlessCluster(
            self,
            "WordpressServerless",
            engine=rds.DatabaseClusterEngine.AURORA_MYSQL,
            default_database_name="WordpressDatabase",
            vpc=properties.vpc,
            scaling=rds.ServerlessScalingOptions(
                auto_pause=core.Duration.seconds(0)),
            deletion_protection=False,
            backup_retention=core.Duration.days(7),
            removal_policy=core.RemovalPolicy.DESTROY,
        )

        file_system = efs.FileSystem(
            self,
            "WebRoot",
            vpc=properties.vpc,
            performance_mode=efs.PerformanceMode.GENERAL_PURPOSE,
            throughput_mode=efs.ThroughputMode.BURSTING,
        )

        # docker context directory
        docker_context_path = os.path.dirname(__file__) + "../../src"

        # upload images to ecr
        nginx_image = ecr_assets.DockerImageAsset(
            self,
            "Nginx",
            directory=docker_context_path,
            file="Docker.nginx",
        )

        wordpress_image = ecr_assets.DockerImageAsset(
            self,
            "Php",
            directory=docker_context_path,
            file="Docker.wordpress",
        )

        cluster = ecs.Cluster(self,
                              'ComputeResourceProvider',
                              vpc=properties.vpc)

        wordpress_volume = ecs.Volume(
            name="WebRoot",
            efs_volume_configuration=ecs.EfsVolumeConfiguration(
                file_system_id=file_system.file_system_id))

        event_task = ecs.FargateTaskDefinition(self,
                                               "WordpressTask",
                                               volumes=[wordpress_volume])

        #
        # webserver
        #
        nginx_container = event_task.add_container(
            "Nginx",
            image=ecs.ContainerImage.from_docker_image_asset(nginx_image))

        nginx_container.add_port_mappings(ecs.PortMapping(container_port=80))

        nginx_container_volume_mount_point = ecs.MountPoint(
            read_only=True,
            container_path="/var/www/html",
            source_volume=wordpress_volume.name)
        nginx_container.add_mount_points(nginx_container_volume_mount_point)

        #
        # application server
        #
        app_container = event_task.add_container(
            "Php",
            environment={
                'WORDPRESS_DB_HOST': database.cluster_endpoint.hostname,
                'WORDPRESS_TABLE_PREFIX': 'wp_'
            },
            secrets={
                'WORDPRESS_DB_USER':
                ecs.Secret.from_secrets_manager(database.secret,
                                                field="username"),
                'WORDPRESS_DB_PASSWORD':
                ecs.Secret.from_secrets_manager(database.secret,
                                                field="password"),
                'WORDPRESS_DB_NAME':
                ecs.Secret.from_secrets_manager(database.secret,
                                                field="dbname"),
            },
            image=ecs.ContainerImage.from_docker_image_asset(wordpress_image))
        app_container.add_port_mappings(ecs.PortMapping(container_port=9000))

        container_volume_mount_point = ecs.MountPoint(
            read_only=False,
            container_path="/var/www/html",
            source_volume=wordpress_volume.name)
        app_container.add_mount_points(container_volume_mount_point)

        #
        # create service
        #
        wordpress_service = ecs.FargateService(
            self,
            "InternalService",
            task_definition=event_task,
            platform_version=ecs.FargatePlatformVersion.VERSION1_4,
            cluster=cluster,
        )

        #
        # scaling
        #
        scaling = wordpress_service.auto_scale_task_count(min_capacity=2,
                                                          max_capacity=50)
        scaling.scale_on_cpu_utilization(
            "CpuScaling",
            target_utilization_percent=85,
            scale_in_cooldown=core.Duration.seconds(120),
            scale_out_cooldown=core.Duration.seconds(30),
        )

        #
        # network acl
        #
        database.connections.allow_default_port_from(wordpress_service,
                                                     "wordpress access to db")
        file_system.connections.allow_default_port_from(wordpress_service)

        #
        # external access
        #
        wordpress_service.connections.allow_from(
            other=properties.load_balancer, port_range=ec2.Port.tcp(80))

        http_listener = properties.load_balancer.add_listener(
            "HttpListener",
            port=80,
        )

        http_listener.add_targets(
            "HttpServiceTarget",
            protocol=elbv2.ApplicationProtocol.HTTP,
            targets=[wordpress_service],
            health_check=elbv2.HealthCheck(healthy_http_codes="200,301,302"))
예제 #6
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # ******* Database table
        audiobooksDB = aws_dynamodb.Table(
            self,
            "audiobooksDB",
            partition_key=aws_dynamodb.Attribute(
                name="id", type=aws_dynamodb.AttributeType.STRING),
            read_capacity=2,
            write_capacity=2,
            billing_mode=aws_dynamodb.BillingMode.PROVISIONED)

        # ******* Lambda functions
        book_upload_lambda_function = aws_lambda.Function(
            self,
            "HandleBookUploadLambda",
            handler='app.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            code=aws_lambda.Code.from_asset(
                '../Functions/handlers/handle_book_upload'))
        polly_audio_lambda_function = aws_lambda.Function(
            self,
            "HandlePollyAudioLambda",
            handler='app.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            code=aws_lambda.Code.from_asset(
                '../Functions/handlers/handle_polly_audio'),
            timeout=core.Duration.seconds(120))

        # ******* S3 upload buckets
        BookUploadBucket = aws_s3.Bucket(self, "BookUploadBucket")
        AudioUploadBucket = aws_s3.Bucket(self, "AudioUploadBucket")
        VideoUploadBucket = aws_s3.Bucket(self, "VideoUploadBucket")
        ImageUploadBucket = aws_s3.Bucket(self, "ImageUploadBucket")

        # ******* Create S3 event source
        book_upload_lambda_function.add_event_source(
            S3EventSource(BookUploadBucket,
                          events=[aws_s3.EventType.OBJECT_CREATED],
                          filters=[{
                              "suffix": '.txt'
                          }]))
        # ******* Create SNS topic
        PollySNSTopic = aws_sns.Topic(self, "PollySNSTopic")
        PollySNSTopic.add_subscription(
            aws_sns_subscriptions.LambdaSubscription(
                polly_audio_lambda_function))

        # ******* Book function environment variables
        book_upload_lambda_function.add_environment("TABLE_NAME",
                                                    audiobooksDB.table_name)
        book_upload_lambda_function.add_environment(
            "AUDIO_S3_BUCKET", AudioUploadBucket.bucket_name)
        book_upload_lambda_function.add_environment("SNS_TOPIC",
                                                    PollySNSTopic.topic_arn)

        # ******* Book function permissions
        audiobooksDB.grant_write_data(book_upload_lambda_function)
        BookUploadBucket.grant_read(book_upload_lambda_function)
        AudioUploadBucket.grant_write(book_upload_lambda_function)
        PollySNSTopic.grant_publish(book_upload_lambda_function)
        book_upload_lambda_function.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["polly:*"], resources=["*"]))

        # ******* Fargate container permissions
        role = aws_iam.Role(
            self,
            "FargateContainerRole",
            assumed_by=aws_iam.ServicePrincipal("ecs-tasks.amazonaws.com"))
        role.add_to_policy(
            aws_iam.PolicyStatement(
                actions=["s3:PutObject"],
                resources=[VideoUploadBucket.bucket_arn + "/*"]))
        role.add_to_policy(
            aws_iam.PolicyStatement(
                actions=["s3:GetObject"],
                resources=[AudioUploadBucket.bucket_arn + "/*"]))
        role.add_to_policy(
            aws_iam.PolicyStatement(
                actions=["s3:GetObject"],
                resources=[ImageUploadBucket.bucket_arn + "/*"]))

        # ******* Fargate container
        vpc = aws_ec2.Vpc(self, "CdkFargateVpc", max_azs=2)
        cluster = aws_ecs.Cluster(self, 'FargateCluster', vpc=vpc)
        image = aws_ecs.ContainerImage.from_asset(
            "../Functions/ECSContainerFiles")
        task_definition = aws_ecs.FargateTaskDefinition(
            self,
            "FargateContainerTaskDefinition",
            execution_role=role,
            task_role=role,
            cpu=1024,
            memory_limit_mib=3072)

        port_mapping = aws_ecs.PortMapping(container_port=80, host_port=80)
        container = task_definition.add_container(
            "Container",
            image=image,
            logging=aws_ecs.AwsLogDriver(
                stream_prefix="videoProcessingContainer"))
        container.add_port_mappings(port_mapping)

        # ******* Audio function environment variables
        polly_audio_lambda_function.add_environment(
            "VIDEO_S3_BUCKET", VideoUploadBucket.bucket_name)
        polly_audio_lambda_function.add_environment(
            "TASK_DEFINITION_ARN", task_definition.task_definition_arn)
        polly_audio_lambda_function.add_environment("CLUSTER_ARN",
                                                    cluster.cluster_arn)
        polly_audio_lambda_function.add_environment("TABLE_NAME",
                                                    audiobooksDB.table_name)
        polly_audio_lambda_function.add_environment("CONTAINER_NAME",
                                                    container.container_name)
        polly_audio_lambda_function.add_environment("VPC_ID", str(vpc.vpc_id))

        # ******* Audio function permissions
        audiobooksDB.grant_read_write_data(polly_audio_lambda_function)
        polly_audio_lambda_function.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["ecs:RunTask"], resources=["*"]))
        polly_audio_lambda_function.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["iam:PassRole"], resources=["*"]))
        polly_audio_lambda_function.add_to_role_policy(
            aws_iam.PolicyStatement(actions=["ec2:DescribeSubnets"],
                                    resources=["*"]))
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # API Gateway needs to have resource policy granting FHIR Works on AWS lambda
        # execute permissions. Lambda function ARN will be passed during deployment as CDK context variable
        # FHIR Works lambda will need to have policy attached to its execution role
        # allowing it to invoke API
        # From --context resource-router-lambda-role="arn:aws:iam::123456789012:role/rolename"
        imported_resource_router_lambda_role = self.node.try_get_context(
            "resource-router-lambda-role"
        )
        # Amazon ECS on AWS Fargate container implementing connection manager
        # will be launched into a VPC that needs to have private and public subnets
        # and NAT gateway or instance
        # From --context vpc-id="vpc-123456"
        vpc_id = self.node.try_get_context("vpc-id")

        # The following parameters specify name of the HL7 server
        # that will be receiving transformed HL7v2 messages and TCP port
        # that it will be listening on
        # From --context hl7-server-name="hl7.example.com"
        # From --context hl7-port="2575"
        hl7_server_name = self.node.try_get_context("hl7-server-name")
        hl7_port = self.node.try_get_context("hl7-port")

        # In this proof of concept source of data for read interactions
        # is S3 bucket where mock HL7 server stores processed HL7 messages
        # From --context test-server-output-bucket-name="DOC-EXAMPLE-BUCKET"
        test_server_output_bucket_name = self.node.try_get_context(
            "test-server-output-bucket-name"
        )

        # SQS queue
        # Custom transform lambda communicates with Connectivity Manager using this SQS queue
        queue = sqs.Queue(
            self, f"{COMPONENT_PREFIX}Queue", encryption=sqs.QueueEncryption.KMS_MANAGED
        )

        # S3 Bucket to retrieve HL7v2 messages in proof of concept deployment
        test_server_output_bucket = s3.Bucket.from_bucket_name(
            self, f"{COMPONENT_PREFIX}OutputBucket", test_server_output_bucket_name
        )

        # Transform Lambda
        # Reference implementation of Custom Transform component of Transform Execution Environment

        transform_lambda = lambda_.Function(
            self,
            f"{COMPONENT_PREFIX}TransformLambda",
            handler="transform.handler",
            runtime=lambda_.Runtime.PYTHON_3_8,
            code=lambda_.Code.from_asset(
                path.join(dirname, "../../lambda"),
                bundling={
                    "image": lambda_.Runtime.PYTHON_3_8.bundling_docker_image,
                    "command": [
                        "bash",
                        "-c",
                        " && ".join(
                            [
                                "pip install --no-cache-dir -r requirements.txt -t /asset-output",
                                "(tar -c --exclude-from=exclude.lst -f - .)|(cd /asset-output; tar -xf -)",
                            ]
                        ),
                    ],
                },
            ),
            timeout=core.Duration.seconds(60),
            environment=dict(
                SQS_QUEUE=queue.queue_url,
                # The following parameter is optional
                S3_BUCKET_NAME=test_server_output_bucket_name,
            ),
        )
        queue.grant_send_messages(transform_lambda)

        # API Gateway with Lambda construct (using https://aws.amazon.com/solutions/constructs/patterns)
        # Reference implementation of Custom Transform component of Transform Execution Environment

        api_lambda = apigw_lambda.ApiGatewayToLambda(
            self,
            "ApiGw",
            existing_lambda_obj=transform_lambda,
            api_gateway_props=apigw.LambdaRestApiProps(
                handler=transform_lambda,
                proxy=False,
                rest_api_name=f"{COMPONENT_PREFIX_DASHES}-api",
                endpoint_export_name=f"{COMPONENT_PREFIX}ApiEndPoint",
                description=f"{COMPONENT_PREFIX} APIGW with Transform Lambda (FHIR to HL7v2)",
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.IAM,
                ),
                policy=iam.PolicyDocument(
                    statements=[
                        iam.PolicyStatement(
                            actions=["execute-api:Invoke"],
                            effect=iam.Effect.ALLOW,
                            principals=[
                                iam.ArnPrincipal(imported_resource_router_lambda_role),
                            ],
                            resources=["execute-api:/*/*/*"],
                        )
                    ]
                ),
            ),
        )
        rest_api = api_lambda.api_gateway
        persistence = rest_api.root.add_resource("persistence")
        resource_type = persistence.add_resource("{resource_type}")
        resource_type.add_method("POST")
        resource_id = resource_type.add_resource("{id}")
        resource_id.add_method("GET")
        resource_id.add_method("PUT")
        resource_id.add_method("DELETE")

        # ECS Fargate Container (HL7v2 sender)
        # This container implements Connectivity Manager component
        # of Transform Execution Environment

        vpc = ec2.Vpc.from_lookup(self, "DefaultVpc", vpc_id=vpc_id)

        cluster = ecs.Cluster(self, f"{COMPONENT_PREFIX}Cluster", vpc=vpc)

        ecs_patterns.QueueProcessingFargateService(
            self,
            f"{COMPONENT_PREFIX}Service",
            cluster=cluster,
            image=ecs.ContainerImage.from_asset(path.join(dirname, "../../container")),
            queue=queue,
            desired_task_count=1,
            log_driver=ecs.LogDriver.aws_logs(
                stream_prefix=f"{COMPONENT_PREFIX}HL7Client",
                log_retention=logs.RetentionDays.ONE_DAY,
            ),
            environment=dict(
                SERVER_NAME=hl7_server_name,
                PORT_NUMBER=hl7_port,
            ),
        )

        # The following permission grants are needed to support
        # read interactions with integration transform
        test_server_output_bucket.grant_read(transform_lambda)

        transform_lambda.add_to_role_policy(
            iam.PolicyStatement(
                actions=["s3:ListBucket"],
                effect=iam.Effect.ALLOW,
                resources=[test_server_output_bucket.bucket_arn],
            )
        )
        transform_lambda.add_to_role_policy(
            iam.PolicyStatement(
                actions=["s3:GetObject"],
                effect=iam.Effect.ALLOW,
                resources=[test_server_output_bucket.arn_for_objects("*")],
            )
        )

        # CloudFormation Stack outputs
        # The following outputs needed to configure FHIR Works on AWS API interface
        core.CfnOutput(
            self,
            "TransformApiRootUrl",
            value=rest_api.url,
            export_name="TransformApiRootUrl",
        )
        core.CfnOutput(
            self,
            "TransformApiRegion",
            value=self.region,
            export_name="TransformApiRegion",
        )
        core.CfnOutput(
            self,
            "TransformApiAccountId",
            value=self.account,
            export_name="TransformApiAccountId",
        )
    def __init__(self, scope, id, **kwargs):
        super().__init__(scope, id, **kwargs)

        # Create random string to be used as suffix on some resource names
        resource_suffix = ''.join(
            random.choice(string.ascii_lowercase) for i in range(8))

        # Save it as SSM parameter to be used in runtime
        ssm.StringParameter(self,
                            "RESOURCE_SUFFIX",
                            string_value=resource_suffix,
                            parameter_name="RESOURCE_SUFFIX")

        # ====================================== VPC ======================================
        # Create VPC
        vpc = ec2.Vpc(self,
                      "sorterbot-vpc",
                      cidr="10.0.0.0/16",
                      enable_dns_support=True,
                      enable_dns_hostnames=True,
                      max_azs=2,
                      nat_gateways=0,
                      subnet_configuration=[
                          {
                              "subnetType": ec2.SubnetType.PUBLIC,
                              "name": "sorterbot-public-subnet-a",
                              "cidrMask": 24,
                          },
                          {
                              "subnetType": ec2.SubnetType.PUBLIC,
                              "name": "sorterbot-public-subnet-b",
                              "cidrMask": 24,
                          },
                      ])

        # Create security groups
        sg_vpc = ec2.SecurityGroup(self,
                                   "sorterbot-vpc-sg",
                                   vpc=vpc,
                                   allow_all_outbound=True,
                                   security_group_name="sorterbot-vpc-sg")
        sg_vpc.add_ingress_rule(sg_vpc, ec2.Port.all_traffic())

        sg_control = ec2.SecurityGroup(
            self,
            "sorterbot-control-sg",
            vpc=vpc,
            allow_all_outbound=True,
            security_group_name="sorterbot-control-sg")
        sg_control.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(22))
        sg_control.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(5432))
        sg_control.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(80))

        # ====================================== IAM ======================================
        cloud_role = iam.CfnRole(
            self,
            "SorterBotCloudRole",
            role_name="SorterBotCloudRole",
            assume_role_policy_document={
                "Version":
                "2012-10-17",
                "Statement": [{
                    "Sid": "",
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "ecs-tasks.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }]
            },
            managed_policy_arns=[
                "arn:aws:iam::aws:policy/AmazonS3FullAccess",
                "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
            ])

        # Create IAM policies
        iam.ManagedPolicy(self,
                          "SorterBotSecretsForECSPolicy",
                          managed_policy_name="SorterBotSecretsForECSPolicy",
                          roles=[cloud_role],
                          statements=[
                              iam.PolicyStatement(
                                  resources=["*"],
                                  actions=[
                                      "ssm:GetParameter", "ssm:GetParameters",
                                      "secretsmanager:GetSecretValue",
                                      "kms:Decrypt"
                                  ])
                          ])

        # ====================================== S3 ======================================
        # Create S3 buckets
        s3.Bucket(self,
                  f"sorterbot-{resource_suffix}",
                  bucket_name=f"sorterbot-{resource_suffix}",
                  removal_policy=core.RemovalPolicy.DESTROY)
        s3.Bucket(self,
                  f"sorterbot-weights-{resource_suffix}",
                  bucket_name=f"sorterbot-weights-{resource_suffix}",
                  removal_policy=core.RemovalPolicy.DESTROY)
        s3.Bucket(self,
                  f"sorterbot-static-{resource_suffix}",
                  bucket_name=f"sorterbot-static-{resource_suffix}",
                  removal_policy=core.RemovalPolicy.DESTROY,
                  cors=[
                      s3.CorsRule(allowed_methods=[s3.HttpMethods.GET],
                                  allowed_origins=["*"],
                                  allowed_headers=["*"])
                  ])

        # ====================================== EC2 ======================================
        # Create EC2 instance for Control Panel
        control_panel_instance = ec2.Instance(
            self,
            f"sorterbot-control-panel-{resource_suffix}",
            instance_name=
            f"sorterbot-control-panel-{resource_suffix}",  # Since deleted instances stay around for a while in terminated state, random suffix is needed to prevent errors when destroying stack # noqa: E501
            instance_type=ec2.InstanceType("t2.micro"),
            machine_image=ec2.MachineImage.latest_amazon_linux(
                generation=ec2.AmazonLinuxGeneration.AMAZON_LINUX_2),
            vpc=vpc,
            key_name="sorterbot",
            vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC),
            security_group=sg_control)

        control_panel_instance.add_to_role_policy(
            iam.PolicyStatement(resources=["*"],
                                actions=[
                                    "ec2:DescribeNetworkInterfaces",
                                    "ssm:GetParameter", "ecs:*", "s3:*"
                                ]))

        # ====================================== RDS ======================================
        # Declare connection details
        master_username = "******"
        master_user_password = core.SecretValue.ssm_secure("PG_PASS",
                                                           version="1")
        port = 5432

        # Create postgres database
        database = rds.DatabaseInstance(
            self,
            "sorterbot_postgres",
            allocated_storage=10,
            backup_retention=core.Duration.days(
                0
            ),  # Don't save backups since storing them is not covered by the Free Tier
            database_name="sorterbot",
            delete_automated_backups=True,
            deletion_protection=False,
            engine=rds.DatabaseInstanceEngine.POSTGRES,
            engine_version="11",
            instance_class=ec2.InstanceType("t2.micro"),  # Stay in Free Tier
            instance_identifier="sorterbot-postgres",
            master_username=master_username,
            master_user_password=master_user_password,
            port=port,
            storage_type=rds.StorageType.GP2,
            vpc=vpc,
            vpc_placement=ec2.SubnetSelection(
                subnet_type=ec2.SubnetType.PUBLIC
            ),  # Make DB publicly accessible (with credentials)
            removal_policy=core.RemovalPolicy.DESTROY)

        # Add ingress rule to allow external connections
        database.connections.allow_default_port_from_any_ipv4()

        # ====================================== ECR ======================================
        # Create ECR repository for Docker images
        ecr.Repository(self,
                       "sorterbot-ecr",
                       repository_name="sorterbot-ecr",
                       removal_policy=core.RemovalPolicy.DESTROY)

        # ====================================== ECS ======================================
        # Create ECS Cluster, Task Definition and Fargate Service
        ecs_cluster = ecs.Cluster(self,
                                  "sorterbot-ecs-cluster",
                                  vpc=vpc,
                                  cluster_name="sorterbot-ecs-cluster")
        task_definition = ecs.FargateTaskDefinition(
            self, "sorterbot-fargate-service", cpu=512, memory_limit_mib=4096)
        task_definition.add_container(
            "sorterbot-cloud-container",
            image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample"))
        ecs.FargateService(self,
                           "sorterbot-ecs-service",
                           cluster=ecs_cluster,
                           task_definition=task_definition,
                           assign_public_ip=True,
                           service_name="sorterbot-ecs-service",
                           desired_count=0,
                           security_group=sg_vpc)

        # Save resource suffix to disk to be used when destroying
        with open(
                Path(__file__).parents[1].joinpath("scripts", "variables",
                                                   "RESOURCE_SUFFIX"),
                "w") as outfile:
            outfile.write(resource_suffix)
예제 #9
0
##device_set=efsdns+":/"
#driveropts={
#    "type": "nfs",
#    "device":device_set,
#    "o": efs_to_connect
#    #"o": "addr=fs-XXXXXX.efs.us-east-1.amazonaws.com,nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport"

#}

#docker_vol_config=ecs.DockerVolumeConfiguration(driver='local', scope=ecs.Scope.TASK, driver_opts=driveropts, labels=None)

#docker_volume=ecs.Volume(name='docker_vol',docker_volume_configuration=docker_vol_config)

#efs_mount=ecs.MountPoint(container_path='/efs',read_only=True, source_volume='docker_vol')

cluster = ecs.Cluster(stack, "wes-ecs", vpc=vpc, cluster_name=App_Name)
print('cluster sec group ', str(type(cluster.autoscaling_group)))
#cluster.add_capacity("DefaultAutoScalingGroup",
#                     instance_type=ec2.InstanceType("c5.xlarge"), key_name='Vonc-Prod-Key',max_capacity=4,machine_image=amitouse,
#                     desired_capacity=2,min_capacity=2)

print('connections ', str(cluster.connections))
port = ec2.Port(protocol=ec2.Protocol.TCP,
                string_representation='inbound to container instances',
                from_port=22,
                to_port=22)
cluster.connections.add_security_group(app_security_group_import)
cluster.connections.allow_from_any_ipv4(port,
                                        'in bound to container instances')

# Create a task definition with its own elastic network interface
예제 #10
0
    def __init__(self, scope: core.Construct, id: str,
                 distributed_locust: bool, target_url: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        vpc_cidr = "10.51.0.0/16"
        number_of_slaves = 3
        ecs_instance_type = "c5.large"
        #Build new VPC
        vpc = ec2.Vpc(self,
                      "loadgenvpc",
                      cidr=vpc_cidr,
                      subnet_configuration=[{
                          "cidrMask": 24,
                          "name": "ecsvpc",
                          "subnetType": ec2.SubnetType.PUBLIC
                      }, {
                          "cidrMask":
                          24,
                          "name":
                          "ecsprivatevpc",
                          "subnetType":
                          ec2.SubnetType.PRIVATE,
                      }])

        #ECS cluster for the loadgen
        loadgen_cluster = ecs.Cluster(self, "Loadgen-Cluster", vpc=vpc)

        loadgen_cluster.add_capacity(
            "AsgSpot",
            max_capacity=2,
            min_capacity=2,
            desired_capacity=2,
            instance_type=ec2.InstanceType(ecs_instance_type),
            spot_price="0.07",
            # Enable the Automated Spot Draining support for Amazon ECS
            spot_instance_draining=True)
        #cloudmap for service discovery so slaves can lookup mast via dns
        loadgen_cluster.add_default_cloud_map_namespace(name="loadgen")

        #Create a graph widget to track reservation metrics for our cluster
        ecs_widget = cw.GraphWidget(
            left=[loadgen_cluster.metric_cpu_reservation()],
            right=[loadgen_cluster.metric_memory_reservation()],
            title="ECS - CPU and Memory Reservation",
        )

        #CloudWatch dashboard to monitor our stuff
        dashboard = cw.Dashboard(self, "Locustdashboard")
        dashboard.add_widgets(ecs_widget)

        if not distributed_locust:
            role = "standalone"
            locustContainer(self, "locust" + role, vpc, loadgen_cluster, role,
                            target_url)
        else:
            role = "master"
            master_construct = locustContainer(self, "locust" + role, vpc,
                                               loadgen_cluster, role,
                                               target_url)

            lb_widget = cw.GraphWidget(
                left=[
                    master_construct.lb.metric_active_connection_count(),
                    master_construct.lb.metric_target_response_time()
                ],
                right=[master_construct.lb.metric_request_count()],
                title="Load Balancer")

            dashboard.add_widgets(lb_widget)

            role = "slave"
            slave_construct = locustContainer(self, "locust" + role, vpc,
                                              loadgen_cluster, role,
                                              target_url, number_of_slaves)
            slave_construct.node.add_dependency(master_construct)
예제 #11
0
파일: app.py 프로젝트: arturo-ai/titiler
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        cpu: Union[int, float] = 256,
        memory: Union[int, float] = 512,
        mincount: int = 1,
        maxcount: int = 50,
        permissions: Optional[iam.PolicyStatement] = None,
        env: dict = {},
        code_dir: str = "./",
        **kwargs: Any,
    ) -> None:
        """Define stack."""
        super().__init__(scope, id, *kwargs)

        vpc = ec2.Vpc(self, f"{id}-vpc", max_azs=2)

        cluster = ecs.Cluster(self, f"{id}-cluster", vpc=vpc)

        task_env = DEFAULT_ENV.copy()
        task_env.update(
            dict(
                MODULE_NAME="titiler.main",
                VARIABLE_NAME="app",
                WORKERS_PER_CORE="1",
                LOG_LEVEL="error",
            ))
        task_env.update(env)

        fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(
            self,
            f"{id}-service",
            cluster=cluster,
            cpu=cpu,
            memory_limit_mib=memory,
            desired_count=mincount,
            public_load_balancer=True,
            listener_port=80,
            task_image_options=dict(
                image=ecs.ContainerImage.from_asset(
                    code_dir,
                    exclude=["cdk.out", ".git"],
                    file="Dockerfiles/ecs/Dockerfile",
                ),
                container_port=80,
                environment=task_env,
            ),
        )

        if permissions:
            fargate_service.task_definition.task_role.add_to_policy(
                permissions)

        scalable_target = fargate_service.service.auto_scale_task_count(
            min_capacity=mincount, max_capacity=maxcount)

        # https://github.com/awslabs/aws-rails-provisioner/blob/263782a4250ca1820082bfb059b163a0f2130d02/lib/aws-rails-provisioner/scaling.rb#L343-L387
        scalable_target.scale_on_request_count(
            "RequestScaling",
            requests_per_target=50,
            scale_in_cooldown=core.Duration.seconds(240),
            scale_out_cooldown=core.Duration.seconds(30),
            target_group=fargate_service.target_group,
        )

        # scalable_target.scale_on_cpu_utilization(
        #     "CpuScaling", target_utilization_percent=70,
        # )

        fargate_service.service.connections.allow_from_any_ipv4(
            port_range=ec2.Port(
                protocol=ec2.Protocol.ALL,
                string_representation="All port 80",
                from_port=80,
            ),
            description="Allows traffic on port 80 from NLB",
        )
예제 #12
0
    def __init__(self, scope: core.Construct, id: str, vpc: aws_ec2.Vpc,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # ECS Cluster
        # https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_ecs.README.html#clusters
        self.ecs_cluster = aws_ecs.Cluster(
            self, "ECSCluster", vpc=vpc, cluster_name="Fargate-microservices")

        # ECS Enable Cloud map
        self.ecs_cluster.add_default_cloud_map_namespace(name="service", )

        # ECS adding capacity
        self.asg = self.ecs_cluster.add_capacity(
            "ECSEC2Capacity",
            instance_type=aws_ec2.InstanceType(
                instance_type_identifier='t3.small'),
            min_capacity=0,
            max_capacity=10)

        core.CfnOutput(self,
                       "EC2AutoScalingGroupName",
                       value=self.asg.auto_scaling_group_name,
                       export_name="EC2ASGName")

        # Namespace details as CFN output
        self.namespace_outputs = {
            'ARN':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_arn,
            'NAME':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_name,
            'ID':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_id,
        }

        # Cluster Attributes
        self.cluster_outputs = {
            'NAME': self.ecs_cluster.cluster_name,
            'SECGRPS': str(self.ecs_cluster.connections.security_groups)
        }

        # When enabling EC2, we need the security groups "registered" to the cluster for imports in other service stacks
        if self.ecs_cluster.connections.security_groups:
            self.cluster_outputs['SECGRPS'] = str([
                x.security_group_id
                for x in self.ecs_cluster.connections.security_groups
            ][0])

        # Allow inbound 80 from ALB to Frontend Service

        self.services_80_sec_group = aws_ec2.SecurityGroup(
            self,
            "FrontendToBackendSecurityGroup",
            allow_all_outbound=True,
            description=
            "Security group to allow inbound 80 from ALB to Frontend Service",
            vpc=vpc)

        self.sec_grp_ingress_self_80 = aws_ec2.CfnSecurityGroupIngress(
            self,
            "InboundSecGrp3000",
            ip_protocol='TCP',
            source_security_group_id=self.services_80_sec_group.
            security_group_id,
            from_port=80,
            to_port=80,
            group_id=self.services_80_sec_group.security_group_id)

        # All Outputs required for other stacks to build
        core.CfnOutput(self,
                       "NSArn",
                       value=self.namespace_outputs['ARN'],
                       export_name="NSARN")
        core.CfnOutput(self,
                       "NSName",
                       value=self.namespace_outputs['NAME'],
                       export_name="NSNAME")
        core.CfnOutput(self,
                       "NSId",
                       value=self.namespace_outputs['ID'],
                       export_name="NSID")
        core.CfnOutput(self,
                       "FE2BESecGrp",
                       value=self.services_80_sec_group.security_group_id,
                       export_name="SecGrpId")
        core.CfnOutput(self,
                       "ECSClusterName",
                       value=self.cluster_outputs['NAME'],
                       export_name="ECSClusterName")
        core.CfnOutput(self,
                       "ECSClusterSecGrp",
                       value=self.cluster_outputs['SECGRPS'],
                       export_name="ECSSecGrpList")
        core.CfnOutput(self,
                       "ServicesSecGrp",
                       value=self.services_80_sec_group.security_group_id,
                       export_name="ServicesSecGrp")
예제 #13
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here

        #vpc = ec2.Vpc.from_lookup(self, 'VPC', is_default=True)

        vpc = ec2.Vpc(self, "MyVpc", max_azs=2)

        rdsInst = rds.DatabaseInstance(
            self,
            'SpringPetclinicDB',
            engine=rds.DatabaseInstanceEngine.MYSQL,
            instance_class=ec2.InstanceType('t2.medium'),
            master_username='******',
            database_name='petclinic',
            master_user_password=core.SecretValue('Welcome#123456'),
            vpc=vpc,
            deletion_protection=False,
            backup_retention=core.Duration.days(0),
            removal_policy=core.RemovalPolicy.DESTROY,
            #vpc_placement = ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC)
        )

        rdsInst.connections.allow_default_port_from_any_ipv4()

        cluster = ecs.Cluster(self, 'EcsCluster', vpc=vpc)

        asset = ecr_assets.DockerImageAsset(
            self,
            'spring-petclinic',
            directory='./docker/',
            build_args={
                'JAR_FILE': 'spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar'
            })

        cluster.add_capacity(
            "DefaultAutoScalingGroup",
            instance_type=ec2.InstanceType('t2.large'),
            vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PUBLIC),
            min_capacity=2)

        ecs_service = ecs_patterns.ApplicationLoadBalancedEc2Service(
            self,
            "Ec2Service",
            cluster=cluster,
            memory_limit_mib=1024,
            service_name='spring-petclinic',
            desired_count=2,
            task_image_options={
                "image": ecs.ContainerImage.from_docker_image_asset(asset),
                "container_name": 'spring-petclinic',
                "container_port": 8080,
                "environment": {
                    'SPRING_DATASOURCE_PASSWORD':
                    '******',
                    'SPRING_DATASOURCE_USERNAME':
                    '******',
                    'SPRING_PROFILES_ACTIVE':
                    'mysql',
                    'SPRING_DATASOURCE_URL':
                    'jdbc:mysql://' + rdsInst.db_instance_endpoint_address +
                    '/petclinic?useUnicode=true'
                }
            })
예제 #14
0
    def __init__(self, scope: core.Construct, id: str, ctx: object,
                 ecr_repository: ecr.Repository, kinesis_stream: ks.Stream,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self.ecr_repository = ecr_repository

        self.vpc = ec2.Vpc.from_vpc_attributes(self, "VPC",
                                               **ctx.vpc_props.dict())

        # CloudWatch Logs Group
        self.log_group = cwl.LogGroup(scope=self, id="logs")

        self.kinesis_stream = kinesis_stream

        # Create a new ECS cluster for our services
        self.cluster = ecs.Cluster(self, vpc=self.vpc, id=f"{id}_cluster")
        cluster_name_output = core.CfnOutput(scope=self,
                                             id="cluster-name-out",
                                             value=self.cluster.cluster_name,
                                             export_name=f"{id}-cluster-name")

        # Create a role for ECS to interact with AWS APIs with standard permissions
        self.ecs_exec_role = iam.Role(
            scope=self,
            id="ecs_logstash-exec_role",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
            managed_policies=([
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AmazonECSTaskExecutionRolePolicy")
            ]))
        # Grant ECS additional permissions to decrypt secrets from Secrets Manager that have been encrypted with our custom key
        if getattr(ctx, "secrets_key_arn", None) is not None:
            self.ecs_exec_role.add_to_policy(
                iam.PolicyStatement(actions=["kms:Decrypt"],
                                    effect=iam.Effect.ALLOW,
                                    resources=[ctx.secrets_key_arn]))
        # Grant ECS permissions to log to our log group
        self.log_group.grant_write(self.ecs_exec_role)

        # Load Balancer for Listening Services
        self.load_balancer = elb2.NetworkLoadBalancer(scope=self,
                                                      id=f"{id}-nlb",
                                                      vpc=self.vpc,
                                                      internet_facing=False,
                                                      cross_zone_enabled=True)

        # Create listener services
        service_names = []
        for service_name in getattr(ctx.inbound.services, "nlb", []):
            self.__create_nlb_service(service_name[0], ctx)
            service_names.append(service_name[0])

        for service_name in getattr(ctx.inbound.services, "cloudmap", []):
            self.__create_cloudmap_service(service_name[0], ctx)
            service_names.append(service_name[0])

        for service_name in getattr(ctx.inbound.services, "pull", []):
            self.__create_pull_service(service_name[0], ctx)
            service_names.append(service_name[0])

        service_names_output = core.CfnOutput(
            scope=self,
            id="service-names-out",
            value=",".join(service_names),
            export_name=f"{id}-service-names")
예제 #15
0
    def __init__(self, scope, id, vpc, **kwarg) -> None:
        super().__init__(scope, id, **kwarg)

        # cluster creation
        cluster = aws_ecs.Cluster(self, 'fargate-service-autoscaling', vpc=vpc)

        # service discovery creation
        sd_namespace = cluster.add_default_cloud_map_namespace(
            name="svc.test.local", vpc=vpc)
        aws_servicediscovery.Service(self,
                                     "svc.test.local",
                                     namespace=sd_namespace,
                                     load_balancer=True)

        # ECS role creation
        ecs_principle = aws_iam.ServicePrincipal('ecs-tasks.amazonaws.com')
        execution_role = aws_iam.Role(self,
                                      'execution-role',
                                      assumed_by=ecs_principle)
        execution_role.add_managed_policy(
            policy=aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="AWSCodeDeployRoleForECS"))
        execution_role.add_managed_policy(
            policy=aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="AmazonEC2ContainerRegistryReadOnly"))
        task_role = aws_iam.Role(self, 'task-role', assumed_by=ecs_principle)
        task_role.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="AWSAppMeshEnvoyAccess"))
        task_role.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="CloudWatchFullAccess"))
        task_role.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="AWSXRayDaemonWriteAccess"))

        # envoy ecr object
        envoy_ecr = aws_ecr.Repository.from_repository_attributes(
            self,
            'aws-envoy',
            repository_arn=core.Stack.of(self).format_arn(
                service="ecr",
                resource="aws-appmesh-envoy",
                account="840364872350"),
            repository_name="aws-appmesh-envoy")

        # colorteller image builds
        gateway_image = aws_ecs.ContainerImage.from_asset("./src/gateway")
        colorteller_image = aws_ecs.ContainerImage.from_asset(
            "./src/colorteller")

        # logging setup
        log_group = aws_logs.LogGroup(self,
                                      "/ecs/colorteller",
                                      retention=aws_logs.RetentionDays.ONE_DAY)
        gateway_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                      stream_prefix="gateway")
        black_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                    stream_prefix="black")
        blue_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                   stream_prefix="blue")
        red_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                  stream_prefix="red")
        white_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                    stream_prefix="white")
        tcpecho_ecs_logs = aws_ecs.LogDriver.aws_logs(log_group=log_group,
                                                      stream_prefix="tcpecho")

        # Mesh properties setup
        mesh_properties = aws_ecs.AppMeshProxyConfigurationProps(
            app_ports=[9080],
            proxy_egress_port=15001,
            proxy_ingress_port=15000,
            egress_ignored_i_ps=["169.254.170.2", "169.254.169.254"],
            ignored_uid=1337)

        # envoy ulimit defaults
        envoy_ulimit = aws_ecs.Ulimit(hard_limit=15000,
                                      name=aws_ecs.UlimitName.NOFILE,
                                      soft_limit=15000)

        # fargate task def - requires envoy proxy container, gateway app and x-ray
        gateway_task_def = aws_ecs.FargateTaskDefinition(
            self,
            "gateway_task",
            cpu=256,
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role,
            proxy_configuration=aws_ecs.AppMeshProxyConfiguration(
                container_name="envoy", properties=mesh_properties))
        gateway_task_def.add_container("gateway",
                                       logging=gateway_ecs_logs,
                                       environment={
                                           "SERVER_PORT":
                                           "9080",
                                           "STAGE":
                                           "v1.1",
                                           "COLOR_TELLER_ENDPOINT":
                                           "colorteller.svc.test.local:9080",
                                           "TCP_ECHO_ENDPOINT":
                                           "tcpecho.svc.test.local:2701"
                                       },
                                       image=gateway_image).add_port_mappings(
                                           aws_ecs.PortMapping(
                                               container_port=9080,
                                               protocol=aws_ecs.Protocol.TCP))
        gateway_task_def.add_container(
            "xray",
            logging=gateway_ecs_logs,
            image=aws_ecs.ContainerImage.from_registry(
                "amazon/aws-xray-daemon")).add_port_mappings(
                    aws_ecs.PortMapping(container_port=2000,
                                        protocol=aws_ecs.Protocol.UDP))
        gateway_envoy_container = gateway_task_def.add_container(
            "envoy",
            logging=gateway_ecs_logs,
            environment={
                "ENVOY_LOG_LEVEL": "debug",
                "ENABLE_ENVOY_XRAY_TRACING": "1",
                "ENABLE_ENVOY_STATS_TAGS": "1",
                "APPMESH_VIRTUAL_NODE_NAME":
                "mesh/ColorTellerAppMesh/virtualNode/gateway",
                "APPMESH_XDS_ENDPOINT": ""
            },
            image=aws_ecs.ContainerImage.from_ecr_repository(
                repository=envoy_ecr, tag="v1.12.1.1-prod"),
            essential=True,
            user="******",
            health_check=aws_ecs.HealthCheck(command=[
                "CMD-SHELL",
                "curl -s http://localhost:9901/ready |grep -q LIVE"
            ]))
        gateway_envoy_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9901,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15000,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15001,
                                protocol=aws_ecs.Protocol.TCP),
        )
        gateway_envoy_container.add_ulimits(envoy_ulimit)

        # black task def - requires color app, envoy and x-ray containers
        black_task_def = aws_ecs.FargateTaskDefinition(
            self,
            "black-task",
            cpu=256,
            family="black",
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role,
            proxy_configuration=aws_ecs.AppMeshProxyConfiguration(
                container_name="envoy", properties=mesh_properties))
        black_envoy_container = black_task_def.add_container(
            "envoy",
            logging=black_ecs_logs,
            environment={
                "ENVOY_LOG_LEVEL": "info",
                "ENABLE_ENVOY_XRAY_TRACING": "1",
                "ENABLE_ENVOY_STATS_TAGS": "1",
                "APPMESH_VIRTUAL_NODE_NAME":
                "mesh/ColorTellerAppMesh/virtualNode/black",
                "APPMESH_XDS_ENDPOINT": ""
            },
            image=aws_ecs.ContainerImage.from_ecr_repository(
                repository=envoy_ecr, tag="v1.12.1.1-prod"),
            essential=True,
            user="******",
            health_check=aws_ecs.HealthCheck(command=[
                "CMD-SHELL",
                "curl -s http://localhost:9901/ready |grep -q LIVE"
            ]))
        black_envoy_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9901,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15000,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15001,
                                protocol=aws_ecs.Protocol.TCP),
        )
        black_envoy_container.add_ulimits(envoy_ulimit)
        black_app_container = black_task_def.add_container(
            "black",
            logging=black_ecs_logs,
            environment={
                "COLOR": "black",
                "SERVER_PORT": "9080",
                "STAGE": "v1.1"
            },
            image=colorteller_image)
        black_app_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9080,
                                protocol=aws_ecs.Protocol.TCP))
        black_app_container.add_container_dependencies(
            aws_ecs.ContainerDependency(
                container=black_envoy_container,
                condition=aws_ecs.ContainerDependencyCondition.HEALTHY))
        black_task_def.add_container(
            "xray",
            logging=black_ecs_logs,
            image=aws_ecs.ContainerImage.from_registry(
                "amazon/aws-xray-daemon")).add_port_mappings(
                    aws_ecs.PortMapping(container_port=2000,
                                        protocol=aws_ecs.Protocol.UDP))

        # blue task def (same as black)
        blue_task_def = aws_ecs.FargateTaskDefinition(
            self,
            "blue-task",
            cpu=256,
            family="blue",
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role,
            proxy_configuration=aws_ecs.AppMeshProxyConfiguration(
                container_name="envoy", properties=mesh_properties))
        blue_envoy_container = blue_task_def.add_container(
            "envoy",
            logging=blue_ecs_logs,
            environment={
                "ENVOY_LOG_LEVEL": "info",
                "ENABLE_ENVOY_XRAY_TRACING": "1",
                "ENABLE_ENVOY_STATS_TAGS": "1",
                "APPMESH_VIRTUAL_NODE_NAME":
                "mesh/ColorTellerAppMesh/virtualNode/blue",
                "APPMESH_XDS_ENDPOINT": ""
            },
            image=aws_ecs.ContainerImage.from_ecr_repository(
                repository=envoy_ecr, tag="v1.12.1.1-prod"),
            essential=True,
            user="******",
            health_check=aws_ecs.HealthCheck(command=[
                "CMD-SHELL",
                "curl -s http://localhost:9901/ready |grep -q LIVE"
            ]))
        blue_envoy_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9901,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15000,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15001,
                                protocol=aws_ecs.Protocol.TCP),
        )
        blue_envoy_container.add_ulimits(envoy_ulimit)
        blue_app_container = blue_task_def.add_container(
            "blue",
            logging=blue_ecs_logs,
            environment={
                "COLOR": "black",
                "SERVER_PORT": "9080",
                "STAGE": "v1.1"
            },
            image=colorteller_image)
        blue_app_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9080,
                                protocol=aws_ecs.Protocol.TCP))
        blue_app_container.add_container_dependencies(
            aws_ecs.ContainerDependency(
                container=blue_envoy_container,
                condition=aws_ecs.ContainerDependencyCondition.HEALTHY))
        blue_task_def.add_container(
            "xray",
            logging=blue_ecs_logs,
            image=aws_ecs.ContainerImage.from_registry(
                "amazon/aws-xray-daemon")).add_port_mappings(
                    aws_ecs.PortMapping(container_port=2000,
                                        protocol=aws_ecs.Protocol.UDP))

        # red task def (same as black)
        red_task_def = aws_ecs.FargateTaskDefinition(
            self,
            "red-task",
            cpu=256,
            family="red-task",
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role,
            proxy_configuration=aws_ecs.AppMeshProxyConfiguration(
                container_name="envoy", properties=mesh_properties))
        red_envoy_container = red_task_def.add_container(
            "envoy",
            logging=red_ecs_logs,
            environment={
                "ENVOY_LOG_LEVEL": "info",
                "ENABLE_ENVOY_XRAY_TRACING": "1",
                "ENABLE_ENVOY_STATS_TAGS": "1",
                "APPMESH_VIRTUAL_NODE_NAME":
                "mesh/ColorTellerAppMesh/virtualNode/red",
                "APPMESH_XDS_ENDPOINT": ""
            },
            image=aws_ecs.ContainerImage.from_ecr_repository(
                repository=envoy_ecr, tag="v1.12.1.1-prod"),
            essential=True,
            user="******",
            health_check=aws_ecs.HealthCheck(command=[
                "CMD-SHELL",
                "curl -s http://localhost:9901/ready |grep -q LIVE"
            ]))
        red_envoy_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9901,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15000,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15001,
                                protocol=aws_ecs.Protocol.TCP),
        )
        red_envoy_container.add_ulimits(envoy_ulimit)
        red_app_container = red_task_def.add_container("red",
                                                       logging=red_ecs_logs,
                                                       environment={
                                                           "COLOR": "red",
                                                           "SERVER_PORT":
                                                           "9080",
                                                           "STAGE": "v1.2"
                                                       },
                                                       image=colorteller_image)
        red_app_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9080,
                                protocol=aws_ecs.Protocol.TCP))
        red_app_container.add_container_dependencies(
            aws_ecs.ContainerDependency(
                container=red_envoy_container,
                condition=aws_ecs.ContainerDependencyCondition.HEALTHY))
        red_task_def.add_container(
            "xray",
            logging=red_ecs_logs,
            image=aws_ecs.ContainerImage.from_registry(
                "amazon/aws-xray-daemon")).add_port_mappings(
                    aws_ecs.PortMapping(container_port=2000,
                                        protocol=aws_ecs.Protocol.UDP))

        # white task def (same as black) - colorteller.svc.test.local points to this service (because containers need something to resolve to or they fail)
        white_task_def = aws_ecs.FargateTaskDefinition(
            self,
            "white-task",
            cpu=256,
            family="white",
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role,
            proxy_configuration=aws_ecs.AppMeshProxyConfiguration(
                container_name="envoy", properties=mesh_properties))
        white_envoy_container = white_task_def.add_container(
            "envoy",
            logging=white_ecs_logs,
            environment={
                "ENVOY_LOG_LEVEL": "info",
                "ENABLE_ENVOY_XRAY_TRACING": "1",
                "ENABLE_ENVOY_STATS_TAGS": "1",
                "APPMESH_VIRTUAL_NODE_NAME":
                "mesh/ColorTellerAppMesh/virtualNode/white",
                "APPMESH_XDS_ENDPOINT": ""
            },
            image=aws_ecs.ContainerImage.from_ecr_repository(
                repository=envoy_ecr, tag="v1.12.1.1-prod"),
            essential=True,
            user="******",
            health_check=aws_ecs.HealthCheck(command=[
                "CMD-SHELL",
                "curl -s http://localhost:9901/ready |grep -q LIVE"
            ]))
        white_envoy_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9901,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15000,
                                protocol=aws_ecs.Protocol.TCP),
            aws_ecs.PortMapping(container_port=15001,
                                protocol=aws_ecs.Protocol.TCP),
        )
        white_envoy_container.add_ulimits(envoy_ulimit)
        white_app_container = white_task_def.add_container(
            "white",
            logging=white_ecs_logs,
            environment={
                "COLOR": "white",
                "SERVER_PORT": "9080",
                "STAGE": "v1.1"
            },
            image=colorteller_image)
        white_app_container.add_port_mappings(
            aws_ecs.PortMapping(container_port=9080,
                                protocol=aws_ecs.Protocol.TCP))
        white_app_container.add_container_dependencies(
            aws_ecs.ContainerDependency(
                container=white_envoy_container,
                condition=aws_ecs.ContainerDependencyCondition.HEALTHY))
        white_task_def.add_container(
            "xray",
            logging=white_ecs_logs,
            image=aws_ecs.ContainerImage.from_registry(
                "amazon/aws-xray-daemon")).add_port_mappings(
                    aws_ecs.PortMapping(container_port=2000,
                                        protocol=aws_ecs.Protocol.UDP))

        # tcpecho service (external docker image)
        tcpecho_task_def = aws_ecs.FargateTaskDefinition(
            self,
            'tcpecho-tasks',
            cpu=256,
            family="tcpecho",
            memory_limit_mib=512,
            execution_role=execution_role,
            task_role=task_role)
        tcpecho_task_def.add_container(
            "tcpecho",
            logging=tcpecho_ecs_logs,
            environment={
                "TCP_PORT": "2701",
                "NODE_NAME": "mesh/ColorTellerAppMesh/virtualNode/echo"
            },
            image=aws_ecs.ContainerImage.from_registry("cjimti/go-echo"),
            essential=True,
        ).add_port_mappings(
            aws_ecs.PortMapping(container_port=2701,
                                protocol=aws_ecs.Protocol.TCP))

        # adds task defs to fargate services - adds security group access to local vpc cidr block
        # all the services are treated the same way
        gateway_fargate_service = aws_ecs.FargateService(
            self,
            "gateway",
            cluster=cluster,
            task_definition=gateway_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="gateway"))
        gateway_fargate_service.connections.security_groups[
            0].add_ingress_rule(peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
                                connection=aws_ec2.Port.tcp(9080),
                                description="Allow http inbound from VPC")
        black_colorteller_fargate_service = aws_ecs.FargateService(
            self,
            "black",
            cluster=cluster,
            task_definition=black_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="black"))
        black_colorteller_fargate_service.connections.security_groups[
            0].add_ingress_rule(peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
                                connection=aws_ec2.Port.tcp(9080),
                                description="Allow http inbound from VPC")
        blue_colorteller_fargate_service = aws_ecs.FargateService(
            self,
            "blue",
            cluster=cluster,
            task_definition=blue_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="blue"))
        blue_colorteller_fargate_service.connections.security_groups[
            0].add_ingress_rule(peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
                                connection=aws_ec2.Port.tcp(9080),
                                description="Allow http inbound from VPC")
        red_colorteller_fargate_service = aws_ecs.FargateService(
            self,
            "red",
            cluster=cluster,
            task_definition=red_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="red"))
        red_colorteller_fargate_service.connections.security_groups[
            0].add_ingress_rule(peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
                                connection=aws_ec2.Port.tcp(9080),
                                description="Allow http inbound from VPC")
        white_colorteller_fargate_service = aws_ecs.FargateService(
            self,
            "white",
            cluster=cluster,
            task_definition=white_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="colorteller"))
        white_colorteller_fargate_service.connections.security_groups[
            0].add_ingress_rule(peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
                                connection=aws_ec2.Port.tcp(9080),
                                description="Allow http inbound from VPC")
        echo_fargate_service = aws_ecs.FargateService(
            self,
            "tcpecho",
            cluster=cluster,
            task_definition=tcpecho_task_def,
            desired_count=2,
            cloud_map_options=aws_ecs.CloudMapOptions(
                cloud_map_namespace=sd_namespace, name="tcpecho"))
        echo_fargate_service.connections.security_groups[0].add_ingress_rule(
            peer=aws_ec2.Peer.ipv4(vpc.vpc_cidr_block),
            connection=aws_ec2.Port.tcp(2701),
            description="Allow http inbound from VPC")

        # adds autoscaling policies to all services
        for service in [
                black_colorteller_fargate_service,
                blue_colorteller_fargate_service,
                red_colorteller_fargate_service,
                white_colorteller_fargate_service, gateway_fargate_service,
                echo_fargate_service
        ]:
            try:
                scaling = service.service.auto_scale_task_count(max_capacity=2)
            except AttributeError:
                scaling = service.auto_scale_task_count(max_capacity=2)
            scaling.scale_on_cpu_utilization(
                "CpuScaling",
                target_utilization_percent=50,
                scale_in_cooldown=core.Duration.seconds(60),
                scale_out_cooldown=core.Duration.seconds(60),
            )

        # configure loadbalancer to listen on port 80 and add targets to gateway and echo apps
        load_balancer = aws_elasticloadbalancingv2.ApplicationLoadBalancer(
            self, "lb", vpc=vpc, internet_facing=True)
        listener = load_balancer.add_listener("PublicListener",
                                              port=80,
                                              open=True)

        health_check = aws_elasticloadbalancingv2.HealthCheck(
            interval=core.Duration.seconds(60),
            path="/ping",
            port="9080",
            timeout=core.Duration.seconds(5))

        # attach ALB to ECS service
        listener.add_targets(
            "gateway",
            port=80,
            targets=[gateway_fargate_service, echo_fargate_service],
            health_check=health_check,
        )

        # outputs of ALB and cluster
        core.CfnOutput(self,
                       "LoadBalancerDNS",
                       value=load_balancer.load_balancer_dns_name)
        core.CfnOutput(self, "ClusterName", value=cluster.cluster_name)
예제 #16
0
파일: app.py 프로젝트: scottyhq/titiler
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        cpu: Union[int, float] = 256,
        memory: Union[int, float] = 512,
        mincount: int = 1,
        maxcount: int = 50,
        permissions: Optional[List[iam.PolicyStatement]] = None,
        env: Optional[Dict] = None,
        code_dir: str = "./",
        **kwargs: Any,
    ) -> None:
        """Define stack."""
        super().__init__(scope, id, *kwargs)

        permissions = permissions or []
        env = env or {}

        vpc = ec2.Vpc(self, f"{id}-vpc", max_azs=2)

        cluster = ecs.Cluster(self, f"{id}-cluster", vpc=vpc)

        task_env = env.copy()
        task_env.update(dict(LOG_LEVEL="error"))

        # GUNICORN configuration
        if settings.workers_per_core:
            task_env.update({"WORKERS_PER_CORE": str(settings.workers_per_core)})
        if settings.max_workers:
            task_env.update({"MAX_WORKERS": str(settings.max_workers)})
        if settings.web_concurrency:
            task_env.update({"WEB_CONCURRENCY": str(settings.web_concurrency)})

        fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(
            self,
            f"{id}-service",
            cluster=cluster,
            cpu=cpu,
            memory_limit_mib=memory,
            desired_count=mincount,
            public_load_balancer=True,
            listener_port=80,
            task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
                image=ecs.ContainerImage.from_registry(
                    f"public.ecr.aws/developmentseed/titiler:{settings.image_version}",
                ),
                container_port=80,
                environment=task_env,
            ),
        )
        fargate_service.target_group.configure_health_check(path="/ping")

        for perm in permissions:
            fargate_service.task_definition.task_role.add_to_policy(perm)

        scalable_target = fargate_service.service.auto_scale_task_count(
            min_capacity=mincount, max_capacity=maxcount
        )

        # https://github.com/awslabs/aws-rails-provisioner/blob/263782a4250ca1820082bfb059b163a0f2130d02/lib/aws-rails-provisioner/scaling.rb#L343-L387
        scalable_target.scale_on_request_count(
            "RequestScaling",
            requests_per_target=50,
            scale_in_cooldown=core.Duration.seconds(240),
            scale_out_cooldown=core.Duration.seconds(30),
            target_group=fargate_service.target_group,
        )

        # scalable_target.scale_on_cpu_utilization(
        #     "CpuScaling", target_utilization_percent=70,
        # )

        fargate_service.service.connections.allow_from_any_ipv4(
            port_range=ec2.Port(
                protocol=ec2.Protocol.ALL,
                string_representation="All port 80",
                from_port=80,
            ),
            description="Allows traffic on port 80 from ALB",
        )
예제 #17
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here

        # Create a VPC
        myvpc = ec2.Vpc(self, "CDKVPC", cidr=vars.cidr)

        # SG for ELB creation
        websitefrontendSG = ec2.SecurityGroup(
            self,
            'websitefrontendSG',
            vpc=myvpc,
            security_group_name='websitefrontendSG')
        websitefrontendSG.add_ingress_rule(peer=ec2.Peer.ipv4('0.0.0.0/0'),
                                           connection=ec2.Port.tcp(80))
        websitefrontendSG.add_ingress_rule(peer=ec2.Peer.ipv4('0.0.0.0/0'),
                                           connection=ec2.Port.tcp(443))

        # Create ALB in VPC
        alb = elb.ApplicationLoadBalancer(
            self,
            'websitefrontend-public',
            vpc=myvpc,
            load_balancer_name='websitefrontend-public',
            security_group=websitefrontendSG,
            internet_facing=True)

        # Add target group to ALB
        catalogtargetgroup = elb.ApplicationTargetGroup(
            self,
            'CatalogTargetGroup',
            port=80,
            vpc=myvpc,
            target_type=elb.TargetType.IP)

        if not vars.sslcert:
            # Add http listener to ALB
            alblistenerhttp = elb.ApplicationListener(
                self,
                'alblistenerhttp',
                load_balancer=alb,
                default_target_groups=[catalogtargetgroup],
                port=80)

        if vars.sslcert:
            # Add http listener to ALB
            alblistenerhttp = elb.ApplicationListener(
                self,
                'alblistenerhttp',
                load_balancer=alb,
                port=80,
                default_target_groups=[catalogtargetgroup])
            elb.ApplicationListenerRule(self,
                                        'httpredirectionrule',
                                        priority=1,
                                        host_header=vars.zone_name,
                                        listener=alblistenerhttp,
                                        redirect_response=elb.RedirectResponse(
                                            status_code='HTTP_301',
                                            port='443',
                                            protocol='HTTPS'))
            # OPTIONAL - Add https listener to ALB & attach certificate
            alblistenerhttps = elb.ApplicationListener(
                self,
                'alblistenerhttps',
                load_balancer=alb,
                default_target_groups=[catalogtargetgroup],
                port=443,
                certificate_arns=[vars.sslcert_arn])

            # OPTIONAL - Redirect HTTP to HTTPS
            # alblistenerhttp.add_redirect_response(
            #     id = 'redirectionrule',
            #     port = '443',
            #     status_code = 'HTTP_301',
            #     protocol = 'HTTPS'
            # )

        if vars.customdomain:
            # OPTIONAL - Update DNS with ALB
            webshopxyz_zone = r53.HostedZone.from_hosted_zone_attributes(
                self,
                id='customdomain',
                hosted_zone_id=vars.hosted_zone_id,
                zone_name=vars.zone_name)
            webshop_root_record = r53.ARecord(
                self,
                'ALBAliasRecord',
                zone=webshopxyz_zone,
                target=r53.RecordTarget.from_alias(
                    alias.LoadBalancerTarget(alb)))

        # SG for ECS creation
        ECSSG = ec2.SecurityGroup(self,
                                  'ECSSecurityGroup',
                                  vpc=myvpc,
                                  security_group_name='ECS')
        ECSSG.add_ingress_rule(peer=websitefrontendSG,
                               connection=ec2.Port.tcp(80))

        # SG for MySQL creation
        MySQLSG = ec2.SecurityGroup(self,
                                    'DBSecurityGroup',
                                    vpc=myvpc,
                                    security_group_name='DB')
        MySQLSG.add_ingress_rule(peer=ECSSG, connection=ec2.Port.tcp(3306))

        # Create DB subnet group
        subnetlist = []
        for subnet in myvpc.private_subnets:
            subnetlist.append(subnet.subnet_id)
        subnetgr = rds.CfnDBSubnetGroup(
            self,
            'democlustersubnetgroup',
            db_subnet_group_name='democlustersubnetgroup',
            db_subnet_group_description='DemoCluster',
            subnet_ids=subnetlist)

        # Create secret db passwd
        secret = sm.SecretStringGenerator(
            exclude_characters="\"'@/\\",
            secret_string_template='{"username": "******"}',
            generate_string_key='password',
            password_length=40)
        dbpass = sm.Secret(self,
                           'democlusterpass',
                           secret_name='democlusterpass',
                           generate_secret_string=secret)

        # Create Aurora serverless MySQL instance
        dbcluster = rds.CfnDBCluster(
            self,
            'DemoCluster',
            engine='aurora',
            engine_mode='serverless',
            engine_version='5.6',
            db_cluster_identifier='DemoCluster',
            master_username=dbpass.secret_value_from_json(
                'username').to_string(),
            master_user_password=dbpass.secret_value_from_json(
                'password').to_string(),
            storage_encrypted=True,
            port=3306,
            vpc_security_group_ids=[MySQLSG.security_group_id],
            scaling_configuration=rds.CfnDBCluster.
            ScalingConfigurationProperty(auto_pause=True,
                                         max_capacity=4,
                                         min_capacity=1,
                                         seconds_until_auto_pause=300),
            db_subnet_group_name=subnetgr.db_subnet_group_name)
        dbcluster.add_override('DependsOn', 'democlustersubnetgroup')

        # Attach database to secret
        attach = sm.CfnSecretTargetAttachment(
            self,
            'RDSAttachment',
            secret_id=dbpass.secret_arn,
            target_id=dbcluster.ref,
            target_type='AWS::RDS::DBCluster')

        # Upload image into ECR repo
        ecrdemoimage = ecra.DockerImageAsset(self,
                                             'ecrdemoimage',
                                             directory='../',
                                             repository_name='demorepo',
                                             exclude=['cdk.out'])

        # Create ECS fargate cluster
        ecscluster = ecs.Cluster(self, "ecsCluster", vpc=myvpc)

        # Create task role for productsCatalogTask
        getsecretpolicystatement = iam.PolicyStatement(actions=[
            "secretsmanager:GetResourcePolicy",
            "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret",
            "secretsmanager:ListSecretVersionIds"
        ],
                                                       resources=[
                                                           dbpass.secret_arn
                                                       ],
                                                       effect=iam.Effect.ALLOW)
        getsecretpolicydocument = iam.PolicyDocument(
            statements=[getsecretpolicystatement])
        taskrole = iam.Role(
            self,
            'TaskRole',
            assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
            role_name='TaskRoleforproductsCatalogTask',
            inline_policies=[getsecretpolicydocument])

        # Create task definition
        taskdefinition = ecs.FargateTaskDefinition(self,
                                                   'productsCatalogTask',
                                                   cpu=1024,
                                                   memory_limit_mib=2048,
                                                   task_role=taskrole)

        # Add container to task definition
        productscatalogcontainer = taskdefinition.add_container(
            'productscatalogcontainer',
            image=ecs.ContainerImage.from_docker_image_asset(
                asset=ecrdemoimage),
            environment={
                "region": vars.region,
                "secretname": "democlusterpass"
            })
        productscatalogcontainer.add_port_mappings(
            ecs.PortMapping(container_port=80, host_port=80))

        # Create service and associate it with the cluster
        catalogservice = ecs.FargateService(
            self,
            'catalogservice',
            task_definition=taskdefinition,
            assign_public_ip=False,
            security_group=ECSSG,
            vpc_subnets=ec2.SubnetSelection(subnets=myvpc.select_subnets(
                subnet_type=ec2.SubnetType.PRIVATE).subnets),
            cluster=ecscluster,
            desired_count=2)

        # Add autoscaling to the service
        scaling = catalogservice.auto_scale_task_count(max_capacity=20,
                                                       min_capacity=1)
        scaling.scale_on_cpu_utilization(
            'ScaleOnCPU',
            target_utilization_percent=70,
            scale_in_cooldown=core.Duration.seconds(amount=1),
            scale_out_cooldown=core.Duration.seconds(amount=0))

        # Associate the fargate service with load balancer targetgroup
        catalogservice.attach_to_application_target_group(catalogtargetgroup)
예제 #18
0
    def __init__(self, scope: core.Construct, id: str, deploy_env: str,
                 vpc: aws_ec2.Vpc, db_redis_stack: RdsElasticacheEfsStack,
                 config: dict, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self.config = config
        self.deploy_env = deploy_env
        self.db_port = DB_PORT
        # cannot map volumes to Fargate task defs yet - so this is done via Boto3 since CDK does not
        # support it yet: https://github.com/aws/containers-roadmap/issues/825
        #self.efs_file_system_id = db_redis_stack.efs_file_system_id
        cluster_name = get_cluster_name(deploy_env)
        self.cluster = ecs.Cluster(self,
                                   cluster_name,
                                   cluster_name=cluster_name,
                                   vpc=vpc)
        pwd_secret = ecs.Secret.from_ssm_parameter(
            StringParameter.from_secure_string_parameter_attributes(
                self,
                f"dbpwd-{deploy_env}",
                version=1,
                parameter_name="postgres_pwd"))
        self.secrets = {"POSTGRES_PASSWORD": pwd_secret}
        environment = {
            "EXECUTOR":
            "Celery",
            "POSTGRES_HOST":
            db_redis_stack.db_host,
            "POSTGRES_PORT":
            str(self.db_port),
            "POSTGRES_DB":
            "airflow",
            "POSTGRES_USER":
            self.config["dbadmin"],
            "REDIS_HOST":
            db_redis_stack.redis_host,
            "VISIBILITY_TIMEOUT":
            str(self.config["celery_broker_visibility_timeout"])
        }
        image_asset = DockerImageAsset(self,
                                       "AirflowImage",
                                       directory="build",
                                       repository_name=config["ecr_repo_name"])
        self.image = ecs.ContainerImage.from_docker_image_asset(image_asset)
        # web server - this initializes the db so must happen first
        self.web_service = self.airflow_web_service(environment)
        # https://github.com/aws/aws-cdk/issues/1654
        self.web_service_sg().connections.allow_to_default_port(
            db_redis_stack.postgres_db, 'allow PG')
        redis_port_info = Port(protocol=Protocol.TCP,
                               string_representation="allow to redis",
                               from_port=REDIS_PORT,
                               to_port=REDIS_PORT)
        worker_port_info = Port(protocol=Protocol.TCP,
                                string_representation="allow to worker",
                                from_port=AIRFLOW_WORKER_PORT,
                                to_port=AIRFLOW_WORKER_PORT)
        redis_sg = SecurityGroup.from_security_group_id(
            self,
            id=f"Redis-SG-{deploy_env}",
            security_group_id=db_redis_stack.redis.vpc_security_group_ids[0])
        bastion_sg = db_redis_stack.bastion.connections.security_groups[0]
        self.web_service_sg().connections.allow_to(redis_sg, redis_port_info,
                                                   'allow Redis')
        self.web_service_sg().connections.allow_to_default_port(
            db_redis_stack.efs_file_system)
        # scheduler
        self.scheduler_service = self.create_scheduler_ecs_service(environment)
        # worker
        self.worker_service = self.worker_service(environment)
        self.scheduler_sg().connections.allow_to_default_port(
            db_redis_stack.postgres_db, 'allow PG')
        self.scheduler_sg().connections.allow_to(redis_sg, redis_port_info,
                                                 'allow Redis')
        self.scheduler_sg().connections.allow_to_default_port(
            db_redis_stack.efs_file_system)

        self.worker_sg().connections.allow_to_default_port(
            db_redis_stack.postgres_db, 'allow PG')
        self.worker_sg().connections.allow_to(redis_sg, redis_port_info,
                                              'allow Redis')
        self.worker_sg().connections.allow_to_default_port(
            db_redis_stack.efs_file_system)
        # When you start an airflow worker, airflow starts a tiny web server
        # subprocess to serve the workers local log files to the airflow main
        # web server, who then builds pages and sends them to users. This defines
        # the port on which the logs are served. It needs to be unused, and open
        # visible from the main web server to connect into the workers.
        self.web_service_sg().connections.allow_to(self.worker_sg(),
                                                   worker_port_info,
                                                   'web service to worker')
    def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # The code that defines your stack goes here

	#############################################
	#Import resorce and custom setting part start
	#############################################
        #cn-north-1
        impRes={
                 "vpc":"vpc-0883083ff3a10c1ec",
                 "SvcSG":"sg-04d3b60e954c1c1ef",
                 "ALBSG":"sg-0b6d093d52d48bba9",
                 "ALBInternet":True,
                 "taskRole":"arn:aws-cn:iam::627484392488:role/ecsTaskExecutionRole",
                 "AlbSubnet":[
                       {"subnetId":"subnet-0d16fa0c969f234d3",
                        "routeTabId":"rtb-074c6b532f3030ad6"},
                       {"subnetId":"subnet-0f28a97c04d3b11cd",
                        "routeTabId":"rtb-074c6b532f3030ad6"}
                 ],
                 #"SvcSubNet":[{"subnetId":"subnet-0d16fa0c969f234d3","routeTabId":"rtb-074c6b532f3030ad6"}]
                 "SvcSubNet":[{"subnetId":"subnet-0f28a97c04d3b11cd","routeTabId":"rtb-0587cc522717461cd"},
                              {"subnetId":"subnet-0d16fa0c969f234d3","routeTabId":"rtb-0587cc522717461cd"}]
               }
        newRes={
                 "TG":{"HealthPath":"/test.html","Port":80,"containPort":80},
                 "Listener":{"Port":80},
                 "TaskFamily":"tsFargate",
                 "ImageAsset1":{"DockfilePath":"httpd-ssh",
                                "BuildArgs":{"HTTP_PROXY":"http://YOUR_PROXY_SERVER:80"}
                               }
               }

        MyTaskDefinition=[{"Cpu":512,"MemLimitMib":1024}]
        MyContainerDefinition=[
             {"containerName":"MyContainer1",
              "cpu":256,
              "essential":True,
              "portMappings":[ecs.PortMapping(container_port=80,host_port=80)], #"portMappings":[ecs.PortMapping(container_port=80,host_port=80),ecs.PortMapping(container_port=22,host_port=22)],
              "environment":{"SSH_PUBLIC_KEY":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC/alWrS+HH5KkPbso+Tsy+Z0WGTX5wvXvon5OacLMyOU3gj2mbbIifasXf/RadpuywuyW3uFirtRlPmSb5Q0PVLODku503Xettw+u6/Z22VV7F2ACgg4iHaCo2SR4L8saUrLLfcKXKr/WCn3w7uYcqGsXEcSFCCSZgn4BoZJqP4Q=="},
              "LogMountPoint":["/usr/local/apache2/logs"]
             }
        ]
        MySvc={"AssignPubIp":True, "desiredCount":1}
	#############################################
	#Import resorce and custom setting part end
	#############################################
		
        #if you import external resource app you cannot set destory policy
        #import VPC, Private Subnet, SG
        vpc = ec2.Vpc.from_lookup(self, "vpc", vpc_id=impRes["vpc"])	
        
        #import SG
        mysvcsg = ec2.SecurityGroup.from_security_group_id(self, "svcsg", 
                impRes["SvcSG"],
                mutable=False)
        
        #import Role
        taskRole = iam.Role.from_role_arn(self, "TaskRole",impRes["taskRole"])
        
        #create ALB        
        mytargetGrp = elbv2.ApplicationTargetGroup(self, "targetGrp",
                target_type=elbv2.TargetType.IP,
                port=newRes["TG"]["Port"],
                vpc=vpc,
                health_check=elbv2.HealthCheck(path=newRes["TG"]["HealthPath"]))
        #target group cannot use .apply_removal_policy directly
        cfn_mytargetGrp=mytargetGrp.node.find_child("Resource")
        cfn_mytargetGrp.apply_removal_policy(cdk.RemovalPolicy.DESTROY)
		
        #import public subnet for alb
        albsubnets = [
                ec2.Subnet.from_subnet_attributes(self,'albsubnetid1',
                    subnet_id = impRes["AlbSubnet"][0]["subnetId"], 
                    route_table_id=impRes["AlbSubnet"][0]["routeTabId"]
                ),
                ec2.Subnet.from_subnet_attributes(self,'albsubnetid2',
                    subnet_id = impRes["AlbSubnet"][1]["subnetId"], 
                    route_table_id=impRes["AlbSubnet"][1]["routeTabId"]
                )
        ]		
        vpc_subnets_selection = ec2.SubnetSelection(subnets=albsubnets)
        #create new ALB
        myalb = elbv2.ApplicationLoadBalancer(self, "ALBv2",
                vpc=vpc,
                security_group=ec2.SecurityGroup.from_security_group_id(self, "ALBSG", impRes["ALBSG"],mutable=False),
                internet_facing=impRes["ALBInternet"],
                vpc_subnets=vpc_subnets_selection)
        myalb.apply_removal_policy(cdk.RemovalPolicy.DESTROY)

        #create new ALB listener
        myalblistener = elbv2.ApplicationListener(self, "ALBlistenter", 
                load_balancer=myalb, 
                port=newRes["Listener"]["Port"])
        myalblistener.apply_removal_policy(cdk.RemovalPolicy.DESTROY)
        myalblistener.add_target_groups("albaddtg", target_groups=[mytargetGrp])
        
        
        #create new ECS Cluster
        mycluster = ecs.Cluster(self, "cluster", vpc=vpc)
        mycluster.apply_removal_policy(cdk.RemovalPolicy.DESTROY)
        
        fargatetaskDefinition = ecs.FargateTaskDefinition(self, "fargatetaskDefinition",
                cpu=MyTaskDefinition[0]["Cpu"],
                memory_limit_mib=MyTaskDefinition[0]["MemLimitMib"],
                execution_role=taskRole,
                family=newRes["TaskFamily"],
                task_role=taskRole)
                #volumes=myEfsVols)      
        fargatetaskDefinition.apply_removal_policy(cdk.RemovalPolicy.DESTROY)


        #defind docker image asset
        dirname = os.path.dirname(__file__)
        #for container 1 normally httpd
        #create Image assent image will generated locally then push to ecr
        asset1 = DockerImageAsset(self, "ImageAsset1",
                   directory=os.path.join(dirname, "../..", newRes["ImageAsset1"]["DockfilePath"]),
                   build_args=newRes["ImageAsset1"]["BuildArgs"]
                )
         
        #create container definition for task definition
        MyContainer1def = ecs.ContainerDefinition(self, "MyContainer1def",
                task_definition=fargatetaskDefinition,
                linux_parameters=ecs.LinuxParameters(self,"LinuxPara1",init_process_enabled=True),
                image=ecs.ContainerImage.from_ecr_repository(asset1.repository, asset1.image_uri.rpartition(":")[-1]),
                container_name=MyContainerDefinition[0]["containerName"],
                essential=MyContainerDefinition[0]["essential"],
                port_mappings=MyContainerDefinition[0]["portMappings"],
                environment=MyContainerDefinition[0]["environment"]
        )
	
	#import service private subnet
        mysvcprivateSNs = [
                ec2.Subnet.from_subnet_attributes(self,'svcprivateSN1',
                    subnet_id = impRes["SvcSubNet"][0]["subnetId"], 
                    route_table_id=impRes["SvcSubNet"][0]["routeTabId"]),
                ec2.Subnet.from_subnet_attributes(self,'svcprivateSN2',
                    subnet_id = impRes["SvcSubNet"][1]["subnetId"], 
                    route_table_id=impRes["SvcSubNet"][1]["routeTabId"])
        ]

        #create service
        myservice=ecs.FargateService(self,"service",
                task_definition=fargatetaskDefinition,
                assign_public_ip=MySvc["AssignPubIp"],
                platform_version=ecs.FargatePlatformVersion.VERSION1_4,
                vpc_subnets=ec2.SubnetSelection(subnets=mysvcprivateSNs),
                security_group=mysvcsg,
                cluster=mycluster,
                desired_count=MySvc["desiredCount"])
        
        mytargetGrp.add_target(myservice.load_balancer_target(container_name="MyContainer1",container_port=newRes["TG"]["containPort"], protocol=ecs.Protocol.TCP))
예제 #20
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        vpc = ec2.Vpc(
            self, "MyVpc",
            max_azs=2
        )

        cluster = ecs.Cluster(
            self, "EC2Cluster",
            vpc=vpc
        )

        security_group = ec2.SecurityGroup(
            self, "SecurityGroup",
            vpc=vpc,
            allow_all_outbound=True,
        )

        security_group.add_ingress_rule(
            peer=ec2.Peer.any_ipv4(),
            connection=ec2.Port.all_tcp(),
            description="Allow all traffic"
        )

        app_target_group = elbv2.ApplicationTargetGroup(
            self, "AppTargetGroup",
            port=http_port,
            vpc=vpc,
            target_type=elbv2.TargetType.IP,
        )

        elastic_loadbalancer = elbv2.ApplicationLoadBalancer(
            self, "ALB",
            vpc=vpc,
            internet_facing=True,
            security_group=security_group,
        )

        app_listener = elbv2.ApplicationListener(
            self, "AppListener",
            load_balancer=elastic_loadbalancer,
            port=http_port,
            default_target_groups=[app_target_group],
        )

        task_definition = ecs.TaskDefinition(
            self, "TaskDefenition",
            compatibility=ecs.Compatibility.FARGATE,
            cpu=task_def_cpu,
            memory_mib=task_def_memory_mb,
        )

        container_defenition = ecs.ContainerDefinition(
            self, "ContainerDefenition",
            image=ecs.ContainerImage.from_registry("vulnerables/web-dvwa"),
            task_definition=task_definition,
            logging=ecs.AwsLogDriver(
                stream_prefix="DemoContainerLogs",
                log_retention=logs.RetentionDays.ONE_DAY,
            ),
        )

        container_defenition.add_port_mappings(
            ecs.PortMapping(
                container_port=http_port,
            )
        )

        fargate_service = ecs.FargateService(
            self, "FargateService",
            task_definition=task_definition,
            cluster=cluster,
            security_group=security_group,
        )

        fargate_service.attach_to_application_target_group(
            target_group=app_target_group,
        )

        core.CfnOutput(
        self, "LoadBalancerDNS",
        value=elastic_loadbalancer.load_balancer_dns_name
        )
예제 #21
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        ###########################################################################
        # AWS LAMBDA FUNCTIONS
        ###########################################################################
        parse_image_list_file = aws_lambda.Function(
            self,
            'parse_image_list_file',
            handler='parse_image_list_file.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON_3_7,
            code=aws_lambda.Code.asset('parse_image_list_file'),
            memory_size=10240,
            timeout=core.Duration.seconds(300),
            log_retention=aws_logs.RetentionDays.ONE_DAY)

        list_objects = aws_lambda.Function(
            self,
            'list_objects',
            handler='list_objects.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON_3_7,
            code=aws_lambda.Code.asset('list_objects'),
            memory_size=4096,
            timeout=core.Duration.seconds(300),
            log_retention=aws_logs.RetentionDays.ONE_DAY)

        get_size_and_store = aws_lambda.Function(
            self,
            'get_size_and_store',
            handler='get_size_and_store.lambda_handler',
            runtime=aws_lambda.Runtime.PYTHON_3_7,
            code=aws_lambda.Code.asset('get_size_and_store'),
            memory_size=4096,
            timeout=core.Duration.seconds(300),
            log_retention=aws_logs.RetentionDays.ONE_DAY)

        ###########################################################################
        # AMAZON S3 BUCKETS
        ###########################################################################
        images_bucket = aws_s3.Bucket(self, "images_bucket")

        ###########################################################################
        # LAMBDA SUPPLEMENTAL POLICIES
        ###########################################################################
        lambda_supplemental_policy_statement = aws_iam.PolicyStatement(
            effect=aws_iam.Effect.ALLOW,
            actions=["s3:Get*", "s3:Head*", "s3:List*", "sqs:*", "es:*"],
            resources=["*"])

        parse_image_list_file.add_to_role_policy(
            lambda_supplemental_policy_statement)
        list_objects.add_to_role_policy(lambda_supplemental_policy_statement)
        get_size_and_store.add_to_role_policy(
            lambda_supplemental_policy_statement)

        ###########################################################################
        # AWS SNS TOPICS
        ###########################################################################
        # notification_topic = aws_sns.Topic(self, "notification_topic")

        ###########################################################################
        # ADD AMAZON S3 BUCKET NOTIFICATIONS
        ###########################################################################
        images_bucket.add_event_notification(
            aws_s3.EventType.OBJECT_CREATED,
            aws_s3_notifications.LambdaDestination(parse_image_list_file))

        ###########################################################################
        # AWS SQS QUEUES
        ###########################################################################
        comprehend_queue_iqueue = aws_sqs.Queue(self,
                                                "comprehend_queue_iqueue")
        comprehend_queue_iqueue_dlq = aws_sqs.DeadLetterQueue(
            max_receive_count=10, queue=comprehend_queue_iqueue)
        comprehend_queue = aws_sqs.Queue(
            self,
            "comprehend_queue",
            visibility_timeout=core.Duration.seconds(301),
            dead_letter_queue=comprehend_queue_iqueue_dlq)

        rekognition_queue_iqueue = aws_sqs.Queue(self,
                                                 "rekognition_queue_iqueue")
        rekognition_queue_dlq = aws_sqs.DeadLetterQueue(
            max_receive_count=10, queue=rekognition_queue_iqueue)
        rekognition_queue = aws_sqs.Queue(
            self,
            "rekognition_queue",
            visibility_timeout=core.Duration.seconds(301),
            dead_letter_queue=rekognition_queue_dlq)

        object_queue_iqueue = aws_sqs.Queue(self, "object_queue_iqueue")
        object_queue_dlq = aws_sqs.DeadLetterQueue(max_receive_count=10,
                                                   queue=object_queue_iqueue)
        object_queue = aws_sqs.Queue(
            self,
            "object_queue",
            visibility_timeout=core.Duration.seconds(301),
            dead_letter_queue=object_queue_dlq)

        ###########################################################################
        # AWS LAMBDA SQS EVENT SOURCE
        ###########################################################################
        get_size_and_store.add_event_source(
            SqsEventSource(object_queue, batch_size=10))

        ###########################################################################
        # AWS ELASTICSEARCH DOMAIN
        ###########################################################################
        s3workflow_domain = aws_elasticsearch.Domain(
            self,
            "s3workflow_domain",
            version=aws_elasticsearch.ElasticsearchVersion.V7_1,
            capacity={
                "master_nodes": 3,
                "data_nodes": 4
            },
            ebs={"volume_size": 100},
            zone_awareness={"availability_zone_count": 2},
            logging={
                "slow_search_log_enabled": True,
                "app_log_enabled": True,
                "slow_index_log_enabled": True
            })

        ###########################################################################
        # AMAZON COGNITO USER POOL
        ###########################################################################
        s3workflow_pool = aws_cognito.UserPool(
            self,
            "s3workflow-pool",
            account_recovery=None,
            auto_verify=None,
            custom_attributes=None,
            email_settings=None,
            enable_sms_role=None,
            lambda_triggers=None,
            mfa=None,
            mfa_second_factor=None,
            password_policy=None,
            self_sign_up_enabled=None,
            sign_in_aliases=aws_cognito.SignInAliases(email=True,
                                                      phone=None,
                                                      preferred_username=None,
                                                      username=True),
            sign_in_case_sensitive=None,
            sms_role=None,
            sms_role_external_id=None,
            standard_attributes=None,
            user_invitation=None,
            user_pool_name=None,
            user_verification=None)

        ###########################################################################
        # AMAZON VPC
        ###########################################################################
        vpc = aws_ec2.Vpc(self, "s3workflowVPC",
                          max_azs=3)  # default is all AZs in region

        ###########################################################################
        # AMAZON ECS CLUSTER
        ###########################################################################
        cluster = aws_ecs.Cluster(self, "s3", vpc=vpc)

        ###########################################################################
        # AMAZON ECS Repositories
        ###########################################################################
        rekognition_repository = aws_ecr.Repository(
            self,
            "rekognition_repository",
            image_scan_on_push=True,
            removal_policy=core.RemovalPolicy("DESTROY"))
        comprehend_repository = aws_ecr.Repository(
            self,
            "comprehend_repository",
            image_scan_on_push=True,
            removal_policy=core.RemovalPolicy("DESTROY"))

        ###########################################################################
        # AMAZON ECS Roles and Policies
        ###########################################################################
        task_execution_policy_statement = aws_iam.PolicyStatement(
            effect=aws_iam.Effect.ALLOW,
            actions=[
                "logs:*", "ecs:*", "ec2:*", "elasticloadbalancing:*", "ecr:*"
            ],
            resources=["*"])
        task_execution_policy_document = aws_iam.PolicyDocument()
        task_execution_policy_document.add_statements(
            task_execution_policy_statement)
        task_execution_policy = aws_iam.Policy(
            self,
            "task_execution_policy",
            document=task_execution_policy_document)
        task_execution_role = aws_iam.Role(
            self,
            "task_execution_role",
            assumed_by=aws_iam.ServicePrincipal('ecs-tasks.amazonaws.com'))
        task_execution_role.attach_inline_policy(task_execution_policy)

        task_policy_statement = aws_iam.PolicyStatement(
            effect=aws_iam.Effect.ALLOW,
            actions=[
                "logs:*", "xray:*", "sqs:*", "s3:*", "rekognition:*",
                "comprehend:*", "es:*"
            ],
            resources=["*"])
        task_policy_document = aws_iam.PolicyDocument()
        task_policy_document.add_statements(task_policy_statement)
        task_policy = aws_iam.Policy(self,
                                     "task_policy",
                                     document=task_policy_document)
        task_role = aws_iam.Role(
            self,
            "task_role",
            assumed_by=aws_iam.ServicePrincipal('ecs-tasks.amazonaws.com'))
        task_role.attach_inline_policy(task_policy)

        ###########################################################################
        # AMAZON ECS Task definitions
        ###########################################################################
        rekognition_task_definition = aws_ecs.TaskDefinition(
            self,
            "rekognition_task_definition",
            compatibility=aws_ecs.Compatibility("FARGATE"),
            cpu="1024",
            # ipc_mode=None,
            memory_mib="2048",
            network_mode=aws_ecs.NetworkMode("AWS_VPC"),
            # pid_mode=None,                                      #Not supported in Fargate and Windows containers
            # placement_constraints=None,
            execution_role=task_execution_role,
            # family=None,
            # proxy_configuration=None,
            task_role=task_role
            # volumes=None
        )

        comprehend_task_definition = aws_ecs.TaskDefinition(
            self,
            "comprehend_task_definition",
            compatibility=aws_ecs.Compatibility("FARGATE"),
            cpu="1024",
            # ipc_mode=None,
            memory_mib="2048",
            network_mode=aws_ecs.NetworkMode("AWS_VPC"),
            # pid_mode=None,                                      #Not supported in Fargate and Windows containers
            # placement_constraints=None,
            execution_role=task_execution_role,
            # family=None,
            # proxy_configuration=None,
            task_role=task_role
            # volumes=None
        )

        ###########################################################################
        # AMAZON ECS Images
        ###########################################################################
        rekognition_ecr_image = aws_ecs.EcrImage(
            repository=rekognition_repository, tag="latest")
        comprehend_ecr_image = aws_ecs.EcrImage(
            repository=comprehend_repository, tag="latest")

        ###########################################################################
        # ENVIRONMENT VARIABLES
        ###########################################################################
        environment_variables = {}
        environment_variables["COMPREHEND_QUEUE"] = comprehend_queue.queue_url
        environment_variables[
            "REKOGNITION_QUEUE"] = rekognition_queue.queue_url
        environment_variables["IMAGES_BUCKET"] = images_bucket.bucket_name
        environment_variables[
            "ELASTICSEARCH_HOST"] = s3workflow_domain.domain_endpoint

        parse_image_list_file.add_environment(
            "ELASTICSEARCH_HOST", s3workflow_domain.domain_endpoint)
        parse_image_list_file.add_environment("QUEUEURL",
                                              rekognition_queue.queue_url)
        parse_image_list_file.add_environment("DEBUG", "False")
        parse_image_list_file.add_environment("BUCKET", "-")
        parse_image_list_file.add_environment("KEY", "-")

        list_objects.add_environment("QUEUEURL", object_queue.queue_url)
        list_objects.add_environment("ELASTICSEARCH_HOST",
                                     s3workflow_domain.domain_endpoint)
        list_objects.add_environment("S3_BUCKET_NAME",
                                     images_bucket.bucket_name)
        list_objects.add_environment("S3_BUCKET_PREFIX", "images/")
        list_objects.add_environment("S3_BUCKET_SUFFIX", "")
        list_objects.add_environment("LOGGING_LEVEL", "INFO")

        get_size_and_store.add_environment("QUEUEURL", object_queue.queue_url)
        get_size_and_store.add_environment("ELASTICSEARCH_HOST",
                                           s3workflow_domain.domain_endpoint)
        get_size_and_store.add_environment("S3_BUCKET_NAME",
                                           images_bucket.bucket_name)
        get_size_and_store.add_environment("S3_BUCKET_PREFIX", "images/")
        get_size_and_store.add_environment("S3_BUCKET_SUFFIX", "")
        get_size_and_store.add_environment("LOGGING_LEVEL", "INFO")

        ###########################################################################
        # ECS Log Drivers
        ###########################################################################
        rekognition_task_log_driver = aws_ecs.LogDriver.aws_logs(
            stream_prefix="s3workflow",
            log_retention=aws_logs.RetentionDays("ONE_DAY"))
        comprehend_task_log_driver = aws_ecs.LogDriver.aws_logs(
            stream_prefix="s3workflow",
            log_retention=aws_logs.RetentionDays("ONE_DAY"))

        ###########################################################################
        # ECS Task Definitions
        ###########################################################################
        rekognition_task_definition.add_container(
            "rekognition_task_definition",
            image=rekognition_ecr_image,
            memory_reservation_mib=1024,
            environment=environment_variables,
            logging=rekognition_task_log_driver)

        comprehend_task_definition.add_container(
            "comprehend_task_definition",
            image=comprehend_ecr_image,
            memory_reservation_mib=1024,
            environment=environment_variables,
            logging=comprehend_task_log_driver)

        ###########################################################################
        # AWS ROUTE53 HOSTED ZONE
        ###########################################################################
        hosted_zone = aws_route53.HostedZone(
            self,
            "hosted_zone",
            zone_name="s3workflow.com",
            comment="private hosted zone for s3workflow system")
        hosted_zone.add_vpc(vpc)
예제 #22
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        # ==============================
        # ======= CFN PARAMETERS =======
        # ==============================
        project_name_param = core.CfnParameter(scope=self, id='ProjectName', type='String')
        db_name = 'mlflowdb'
        port = 3306
        username = '******'
        bucket_name = f'{project_name_param.value_as_string}-artifacts-{core.Aws.ACCOUNT_ID}'
        container_repo_name = 'mlflow-containers'
        cluster_name = 'mlflow'
        service_name = 'mlflow'

        # ==================================================
        # ================= IAM ROLE =======================
        # ==================================================
        role = iam.Role(scope=self, id='TASKROLE', assumed_by=iam.ServicePrincipal(service='ecs-tasks.amazonaws.com'))
        role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AmazonS3FullAccess'))
        role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AmazonECS_FullAccess'))

        # ==================================================
        # ================== SECRET ========================
        # ==================================================
        db_password_secret = sm.Secret(
            scope=self,
            id='DBSECRET',
            secret_name='dbPassword',
            generate_secret_string=sm.SecretStringGenerator(password_length=20, exclude_punctuation=True)
        )
        

        # ==================================================
        # ==================== VPC =========================
        # ==================================================
        #public_subnet = ec2.SubnetConfiguration(name='Public', subnet_type=ec2.SubnetType.PUBLIC, cidr_mask=28)
        #dev-shared-public-subnet-az1
        #private_subnet = ec2.SubnetConfiguration(name='Private', subnet_type=ec2.SubnetType.PRIVATE, cidr_mask=28)
        #dev-shared-private-subnet-az1
        #isolated_subnet = ec2.SubnetConfiguration(name='DB', subnet_type=ec2.SubnetType.ISOLATED, cidr_mask=28) 
        #dev-shared-private-subnet-az1

        #use existing (is needed later for fargete)
        """ vpc = ec2.Vpc(
            scope=self,
            id='VPC',
            cidr='10.0.0.0/24',
            max_azs=2,
            nat_gateway_provider=ec2.NatProvider.gateway(),
            nat_gateways=1,
            subnet_configuration=[public_subnet, private_subnet, isolated_subnet]
        ) """

        """ stack = MyStack(
            app, "MyStack", env=Environment(account="account_id", region="region")
        ) """

        vpc = ec2.Vpc.from_lookup(self, "VPC",
            vpc_id = "vpc-03076add1b1efca31" #is_default=True
        ) #TODO: fill in correct arguments
        #vpc_id = "vpc-03076add1b1efca31"

        #leave, should be fine, if not check (is nto NAT gateway)

        #original: vpc.add_gateway_endpoint('S3Endpoint', service=ec2.GatewayVpcEndpointAwsService.S3)
        # ==================================================
        # ================= S3 BUCKET ======================
        # ==================================================
        artifact_bucket = s3.Bucket(
            scope=self,
            id='ARTIFACTBUCKET',
            bucket_name=bucket_name,
            public_read_access=False,
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            removal_policy=core.RemovalPolicy.DESTROY
        )
        # # ==================================================
        # # ================== DATABASE  =====================
        # # ==================================================
        # Creates a security group for AWS RDS
        sg_rds = ec2.SecurityGroup(scope=self, id='SGRDS', vpc=vpc, security_group_name='sg_rds')
        # Adds an ingress rule which allows resources in the VPC's CIDR to access the database.
        #original: sg_rds.add_ingress_rule(peer=ec2.Peer.ipv4('10.0.0.0/24'), connection=ec2.Port.tcp(port))
        sg_rds.add_ingress_rule(peer=ec2.Peer.ipv4('10.206.192.0/19'), connection=ec2.Port.tcp(port))
        #10.206.192.0/19

        database = rds.DatabaseInstance(
            scope=self,
            id='MYSQL',
            database_name=db_name,
            port=port,
            credentials=rds.Credentials.from_username(username=username, password=db_password_secret.secret_value),
            engine=rds.DatabaseInstanceEngine.mysql(version=rds.MysqlEngineVersion.VER_8_0_19),
            instance_type=ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),
            vpc=vpc,
            security_groups=[sg_rds],
            #vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.ISOLATED),
            vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE), #TODO: check if you need to select private here and how
            # multi_az=True,
            removal_policy=core.RemovalPolicy.DESTROY,
            deletion_protection=False
        )
        # ==================================================
        # =============== FARGATE SERVICE ==================
        # ==================================================
        
        cluster = ecs.Cluster(scope=self, id='CLUSTER', cluster_name=cluster_name, vpc=vpc)

        task_definition = ecs.FargateTaskDefinition(
            scope=self,
            id='MLflow',
            task_role=role,

        )

        container = task_definition.add_container(
            id='Container',
            image=ecs.ContainerImage.from_asset(
                directory='container',
                repository_name=container_repo_name
            ),
            environment={
                'BUCKET': f's3://{artifact_bucket.bucket_name}',
                'HOST': database.db_instance_endpoint_address,
                'PORT': str(port),
                'DATABASE': db_name,
                'USERNAME': username
            },
            secrets={
                'PASSWORD': ecs.Secret.from_secrets_manager(db_password_secret)
            }
        )
        port_mapping = ecs.PortMapping(container_port=5000, host_port=5000, protocol=ecs.Protocol.TCP)
        container.add_port_mappings(port_mapping)

        fargate_service = ecs_patterns.NetworkLoadBalancedFargateService(
            scope=self,
            id='MLFLOW',
            service_name=service_name,
            cluster=cluster,
            task_definition=task_definition
        )

        # Setup security group
        fargate_service.service.connections.security_groups[0].add_ingress_rule(
            peer=ec2.Peer.ipv4(vpc.vpc_cidr_block),
            connection=ec2.Port.tcp(5000),
            description='Allow inbound from VPC for mlflow'
        )

        # Setup autoscaling policy
        scaling = fargate_service.service.auto_scale_task_count(max_capacity=2)
        scaling.scale_on_cpu_utilization(
            id='AUTOSCALING',
            target_utilization_percent=70,
            scale_in_cooldown=core.Duration.seconds(60),
            scale_out_cooldown=core.Duration.seconds(60)
        )
        # ==================================================
        # =================== OUTPUTS ======================
        # ==================================================
        core.CfnOutput(scope=self, id='LoadBalancerDNS', value=fargate_service.load_balancer.load_balancer_dns_name)
예제 #23
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        branch = kwargs['env']['branch']
        # create s3 bucket for CodeCommit artifacts
        s3_bucket = S3_Bucket(self, 's3-' + branch)

        # Create IAM roles for git merge and CodeBuild
        roles = Roles(self, 'roles-' + branch)

        # Define New Codepipeline
        pipeline = ServicePipeline(self,
                                   'pipeline-' + branch,
                                   bucket=s3_bucket.ArtifactBucket)

        # Create GitHub Account
        github = GitHub(self,
                        'GitHubSource-' + branch,
                        pipeline=pipeline.pipeline)

        # Create ECR Repo
        ecr_repo = ECRRepo(
            self,
            'ECRRepo-' + branch,
        )

        # Create CodeBuild
        GitCodeBuild(
            self,
            'CodeBuild-' + branch,
            source=github.sourceOutput,
            pipeline=pipeline.pipeline,
            bucket=s3_bucket.ArtifactBucket,
            role=roles.CodeBuildServiceRole,
            frontend=ecr_repo.flask.repository_uri,
        )

        # Create VPC for the ecs
        vpc = ec2.Vpc(
            self,
            "MyVPC-" + branch,
            max_azs=2,
        )

        # Create ECS cluster
        cluster = ecs.Cluster(
            self,
            'EC2-Cluster-' + branch,
            vpc=vpc,
        )

        # Add Auto Scaling Group
        for i in range(3):
            cluster.add_capacity(
                "DefaultAutoScalingGroup-" + str(i) + '-' + branch,
                instance_type=ec2.InstanceType("t2.medium"),
                allow_all_outbound=True,
                key_name=os.environ['KEYNAME'],
                # vpc_subnets=vpc.public_subnets
            )

        if branch == 'master':
            # Add HostedZone
            hosted_zone = route53.HostedZone(
                self,
                'hosted-zone-' + branch,
                # hosted_zone_id='Z3HNUDRBTJMWFV',
                zone_name='wiki-trend.com')
            domain_name = 'wiki-trend.com'
        else:
            hosted_zone = None
            domain_name = None

        # Add Load Balancer
        ecs_service = ecs_patterns.LoadBalancedEc2Service(
            self,
            'Ec2Service-' + branch,
            cluster=cluster,
            # service_name='Frontend-1-'+branch,
            memory_limit_mib=2048,
            container_port=80,
            environment={
                "PORT": '80',
                'NEO4J_USER': os.environ['NEO4J_USER'],
                'NEO4J_PASSWORD': os.environ['NEO4J_PASSWORD']
            },
            domain_name=domain_name,
            domain_zone=hosted_zone,
            # image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample"),
            image=ecs.ContainerImage.from_ecr_repository(ecr_repo.flask),
            public_load_balancer=True,
        )

        core.CfnOutput(
            self,
            'ECRRepoURI-' + branch,
            description="The URI of the ECR Repo for flask frontend",
            value=ecr_repo.flask.repository_uri)

        core.CfnOutput(
            self,
            "CodePipelinURL-" + branch,
            description="The URL of the created Pipeline",
            value=
            "https://{}.console.aws.amazon.com/codepipeline/home?region={}#/view/{}"
            .format(os.environ['AWS_REGION'], os.environ['AWS_REGION'],
                    pipeline.pipeline.pipeline_name))

        core.CfnOutput(self,
                       "LoadBalancerDNS-" + branch,
                       value=ecs_service.load_balancer.load_balancer_dns_name)
예제 #24
0
    def create_fagate_NLB_autoscaling_custom(self, vpc, **kwargs):
        ####################
        # Unpack Value for name/ecr_repo
        app_name = kwargs['function'].replace("_", "-")
        task_name = "{}-task-definition".format(app_name)
        log_name = app_name
        image_name = "{}-image".format(app_name)
        container_name = "{}-container".format(app_name)
        service_name = "{}-service".format(app_name)

        app_ecr = kwargs['ecr']
        ecs_role = kwargs['ecs_role']

        ####################
        # Create Cluster
        cluster = ecs.Cluster(self, 'fargate-service-autoscaling', vpc=vpc)

        ####################
        # Config IAM Role
        # add managed policy statement
        # ecs_base_role = iam.Role(
        #     self,
        #     "ecs_service_role",
        #     assumed_by=iam.ServicePrincipal("ecs.amazonaws.com")
        # )
        # ecs_role = ecs_base_role.from_role_arn(self, 'gw-ecr-role-test', role_arn='arn:aws:iam::002224604296:role/ecsTaskExecutionRole')

        ####################
        # Create Fargate Task Definition
        fargate_task = ecs.FargateTaskDefinition(self,
                                                 task_name,
                                                 execution_role=ecs_role,
                                                 task_role=ecs_role,
                                                 cpu=2048,
                                                 memory_limit_mib=8192)
        # 0. config log
        ecs_log = ecs.LogDrivers.aws_logs(stream_prefix=log_name)
        # 1. prepare ecr repository
        ecr_repo = ecr.Repository.from_repository_name(self,
                                                       id=image_name,
                                                       repository_name=app_ecr)
        farget_container = fargate_task.add_container(
            container_name,
            image=ecs.ContainerImage.from_ecr_repository(ecr_repo),
            logging=ecs_log,
            environment={
                'KG_PATH': "s3://autorec-1",
                "REDIS_URL": self.redis_host,
                "REDIS_PORT": self.redis_port
            })
        # 2. config port mapping
        port_mapping = ecs.PortMapping(container_port=9008,
                                       host_port=9008,
                                       protocol=ecs.Protocol.TCP)
        farget_container.add_port_mappings(port_mapping)

        ####################
        # Config NLB service
        # fargate_service = ecs.FargateService(self, 'graph-inference-service',
        #     cluster=cluster, task_definition=fargate_task, assign_public_ip=True
        # )
        fargate_service = ecs_patterns.NetworkLoadBalancedFargateService(
            self,
            service_name,
            cluster=cluster,
            task_definition=fargate_task,
            assign_public_ip=True,
            desired_count=20,
            listener_port=9008)
        # 0. allow inbound in sg
        fargate_service.service.connections.security_groups[
            0].add_ingress_rule(
                # peer = ec2.Peer.ipv4(vpc.vpc_cidr_block),
                peer=ec2.Peer.ipv4('0.0.0.0/0'),
                connection=ec2.Port.tcp(9008),
                description="Allow http inbound from VPC")

        # 1. setup autoscaling policy
        # autoscaling 自动scale
        #         scaling = fargate_service.service.auto_scale_task_count(
        #             max_capacity=50
        #         )
        #         scaling.scale_on_cpu_utilization(
        #             "CpuScaling",
        #             target_utilization_percent=50,
        #             scale_in_cooldown=core.Duration.seconds(60),
        #             scale_out_cooldown=core.Duration.seconds(60),
        #         )

        return fargate_service.load_balancer.load_balancer_dns_name
class MLflowStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        ##
        ##Parametros gerais utilizados para provisioamento de infra
        ##
        project_name_param = core.CfnParameter(scope=self, id='mlflowStack', type='String', default='mlflowStack')
        db_name = 'mlflowdb'
        port = 3306
        username = '******'
        bucket_name = 'mlflowbucket-track-stack'
        container_repo_name = 'mlflow-containers'
        cluster_name = 'mlflow'
        service_name = 'mlflow'

        #Associação das policys gerenciadas a role que sera atribuida a task ECS.        
        role = iam.Role(scope=self, id='TASKROLE', assumed_by=iam.ServicePrincipal(service='ecs-tasks.amazonaws.com'))
        
        role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AmazonS3FullAccess'))
        
        role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name('AmazonECS_FullAccess'))

        #Secrets Manager responsavel pelo armazenamento do password do nosso RDS MySQL
        db_password_secret = sm.Secret(
            scope=self,
            id='dbsecret',
            secret_name='dbPassword',
            generate_secret_string=sm.SecretStringGenerator(password_length=20, exclude_punctuation=True)
        )

         #Criação do Bucket S3
        artifact_bucket = s3.Bucket(
            scope=self,
            id='mlflowstacktrack',
            bucket_name=bucket_name,
            public_read_access=False,
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
            removal_policy=core.RemovalPolicy.DESTROY
        )

      #Obtenção de VPC para atribuição ao RDS
      dev_vpc = ec2.Vpc.from_vpc_attributes(
            self, '<VPC_NAME>',
            vpc_id = "<VPC_ID>",
            availability_zones = core.Fn.get_azs(),
            private_subnet_ids = ["PRIVATE_SUBNET_ID_1","PRIVATE_SUBNET_ID_2","PRIVATE_SUBNET_ID_3"]
       )

        # Adicionamos aqui para efeito de testes 0.0.0.0/0
        sg_rds = ec2.SecurityGroup(scope=self, id='SGRDS', security_group_name='sg_rds', vpc=dev_vpc)
        
        sg_rds.add_ingress_rule(peer=ec2.Peer.ipv4('0.0.0.0/0'), connection=ec2.Port.tcp(port))

        # Criação da instancia RDS
        database = rds.DatabaseInstance(
            scope=self,
            id='MYSQL',
            database_name=db_name,
            port=port,
            credentials=rds.Credentials.from_username(username=username, password=db_password_secret.secret_value),
            engine=rds.DatabaseInstanceEngine.mysql(version=rds.MysqlEngineVersion.VER_8_0_19),
            instance_type=ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL),            
            security_groups=[sg_rds],
            vpc=dev_vpc,            
            # multi_az=True,
            removal_policy=core.RemovalPolicy.DESTROY,
            deletion_protection=False
        )

        #Criação do Cluster ECS
        cluster = ecs.Cluster(scope=self, id='CLUSTER', cluster_name=cluster_name)
        #Task Definition para Fargate
        task_definition = ecs.FargateTaskDefinition(
            scope=self,
            id='MLflow',
            task_role=role,

        )
        #Criando nosso container com base no Dockerfile do MLflow
        container = task_definition.add_container(
            id='Container',
            image=ecs.ContainerImage.from_asset(
                directory='../MLflow/container',
                repository_name=container_repo_name
            ),
             #Atribuição Variaves ambiente
            environment={
                'BUCKET': f's3://{artifact_bucket.bucket_name}',
                'HOST': database.db_instance_endpoint_address,
                'PORT': str(port),
                'DATABASE': db_name,
                'USERNAME': username
            },
            #Secrets contendo o password do RDS MySQL
            secrets={
                'PASSWORD': ecs.Secret.from_secrets_manager(db_password_secret)
            }
        )
        #Port Mapping para exposição do Container MLflow
        port_mapping = ecs.PortMapping(container_port=5000, host_port=5000, protocol=ecs.Protocol.TCP)
        container.add_port_mappings(port_mapping)

        fargate_service = ecs_patterns.NetworkLoadBalancedFargateService(
            scope=self,
            id='MLFLOW',
            service_name=service_name,
            cluster=cluster,
            task_definition=task_definition
        )

        #Security group para ingress
        fargate_service.service.connections.security_groups[0].add_ingress_rule(
            peer=ec2.Peer.ipv4('0.0.0.0/0'),
            connection=ec2.Port.tcp(5000),
            description='Allow inbound for mlflow'
        )

        #Auto Scaling Policy para nosso balanceador
        scaling = fargate_service.service.auto_scale_task_count(max_capacity=2)
        scaling.scale_on_cpu_utilization(
            id='AUTOSCALING',
            target_utilization_percent=70,
            scale_in_cooldown=core.Duration.seconds(60),
            scale_out_cooldown=core.Duration.seconds(60)
        )
     
        core.CfnOutput(scope=self, id='LoadBalancerDNS', value=fargate_service.load_balancer.load_balancer_dns_name)
예제 #26
0
    def __init__(self, scope: core.Stack, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        # This resource alone will create a private/public subnet in each AZ as well as nat/internet gateway(s)
        self.vpc = aws_ec2.Vpc(
            self,
            "BaseVPC",
            cidr='10.0.0.0/24',
        )

        # Creating ECS Cluster in the VPC created above
        self.ecs_cluster = aws_ecs.Cluster(self,
                                           "ECSCluster",
                                           vpc=self.vpc,
                                           cluster_name="container-demo")

        # Adding service discovery namespace to cluster
        self.ecs_cluster.add_default_cloud_map_namespace(name="service", )

        ###### EC2 SPOT CAPACITY PROVIDER SECTION ######

        ## As of today, AWS CDK doesn't support Launch Templates on the AutoScaling construct, hence it
        ## doesn't support Mixed Instances Policy to combine instance types on Auto Scaling and adhere to Spot best practices
        ## In the meantime, CfnLaunchTemplate and CfnAutoScalingGroup resources are used to configure Spot capacity
        ## https://github.com/aws/aws-cdk/issues/6734

        self.ecs_spot_instance_role = aws_iam.Role(
            self,
            "ECSSpotECSInstanceRole",
            assumed_by=aws_iam.ServicePrincipal("ec2.amazonaws.com"),
            managed_policies=[
                aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AmazonEC2ContainerServiceforEC2Role"),
                aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AmazonEC2RoleforSSM")
            ])

        self.ecs_spot_instance_profile = aws_iam.CfnInstanceProfile(
            self,
            "ECSSpotInstanceProfile",
            roles=[self.ecs_spot_instance_role.role_name])

        ## This creates a Launch Template for the Auto Scaling group
        self.lt = aws_ec2.CfnLaunchTemplate(
            self,
            "ECSEC2SpotCapacityLaunchTemplate",
            launch_template_data={
                "instanceType":
                "m5.large",
                "imageId":
                aws_ssm.StringParameter.value_for_string_parameter(
                    self,
                    "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id"
                ),
                "securityGroupIds": [
                    x.security_group_id
                    for x in self.ecs_cluster.connections.security_groups
                ],
                "iamInstanceProfile": {
                    "arn": self.ecs_spot_instance_profile.attr_arn
                },
                #
                ## Here we configure the ECS agent to drain Spot Instances upon catching a Spot Interruption notice from instance metadata
                "userData":
                core.Fn.base64(
                    core.Fn.sub(
                        "#!/usr/bin/bash\n"
                        "echo ECS_CLUSTER=${cluster_name} >> /etc/ecs/ecs.config\n"
                        "sudo iptables --insert FORWARD 1 --in-interface docker+ --destination 169.254.169.254/32 --jump DROP\n"
                        "sudo service iptables save\n"
                        "echo ECS_ENABLE_SPOT_INSTANCE_DRAINING=true >> /etc/ecs/ecs.config\n"
                        "echo ECS_AWSVPC_BLOCK_IMDS=true >> /etc/ecs/ecs.config\n"
                        "cat /etc/ecs/ecs.config",
                        variables={
                            "cluster_name": self.ecs_cluster.cluster_name
                        }))
            },
            launch_template_name="ECSEC2SpotCapacityLaunchTemplate")

        self.ecs_ec2_spot_mig_asg = aws_autoscaling.CfnAutoScalingGroup(
            self,
            "ECSEC2SpotCapacity",
            min_size="0",
            max_size="10",
            vpc_zone_identifier=[
                x.subnet_id for x in self.vpc.private_subnets
            ],
            mixed_instances_policy={
                "instancesDistribution": {
                    "onDemandAllocationStrategy": "prioritized",
                    "onDemandBaseCapacity": 0,
                    "onDemandPercentageAboveBaseCapacity": 0,
                    "spotAllocationStrategy": "capacity-optimized"
                },
                "launchTemplate": {
                    "launchTemplateSpecification": {
                        "launchTemplateId": self.lt.ref,
                        "version": self.lt.attr_default_version_number
                    },
                    "overrides": [{
                        "instanceType": "m5.large"
                    }, {
                        "instanceType": "m5d.large"
                    }, {
                        "instanceType": "m5a.large"
                    }, {
                        "instanceType": "m5ad.large"
                    }, {
                        "instanceType": "m5n.large"
                    }, {
                        "instanceType": "m5dn.large"
                    }, {
                        "instanceType": "m3.large"
                    }, {
                        "instanceType": "m4.large"
                    }, {
                        "instanceType": "t3.large"
                    }, {
                        "instanceType": "t2.large"
                    }]
                }
            })
        #
        core.Tag.add(self.ecs_ec2_spot_mig_asg, "Name",
                     self.ecs_ec2_spot_mig_asg.node.path)
        core.CfnOutput(self,
                       "EC2SpotAutoScalingGroupName",
                       value=self.ecs_ec2_spot_mig_asg.ref,
                       export_name="EC2SpotASGName")
        #
        ##### END EC2 SPOT CAPACITY PROVIDER SECTION #####

        # Namespace details as CFN output
        self.namespace_outputs = {
            'ARN':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_arn,
            'NAME':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_name,
            'ID':
            self.ecs_cluster.default_cloud_map_namespace.
            private_dns_namespace_id,
        }

        # Cluster Attributes
        self.cluster_outputs = {
            'NAME': self.ecs_cluster.cluster_name,
            'SECGRPS': str(self.ecs_cluster.connections.security_groups)
        }

        # When enabling EC2, we need the security groups "registered" to the cluster for imports in other service stacks
        if self.ecs_cluster.connections.security_groups:
            self.cluster_outputs['SECGRPS'] = str([
                x.security_group_id
                for x in self.ecs_cluster.connections.security_groups
            ][0])

        # Frontend service to backend services on 3000
        self.services_3000_sec_group = aws_ec2.SecurityGroup(
            self,
            "FrontendToBackendSecurityGroup",
            allow_all_outbound=True,
            description=
            "Security group for frontend service to talk to backend services",
            vpc=self.vpc)

        # Allow inbound 3000 from ALB to Frontend Service
        self.sec_grp_ingress_self_3000 = aws_ec2.CfnSecurityGroupIngress(
            self,
            "InboundSecGrp3000",
            ip_protocol='TCP',
            source_security_group_id=self.services_3000_sec_group.
            security_group_id,
            from_port=3000,
            to_port=3000,
            group_id=self.services_3000_sec_group.security_group_id)

        # Creating an EC2 bastion host to perform load test on private backend services
        amzn_linux = aws_ec2.MachineImage.latest_amazon_linux(
            generation=aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
            edition=aws_ec2.AmazonLinuxEdition.STANDARD,
            virtualization=aws_ec2.AmazonLinuxVirt.HVM,
            storage=aws_ec2.AmazonLinuxStorage.GENERAL_PURPOSE)

        # Instance Role/profile that will be attached to the ec2 instance
        # Enabling service role so the EC2 service can use ssm
        role = aws_iam.Role(
            self,
            "InstanceSSM",
            assumed_by=aws_iam.ServicePrincipal("ec2.amazonaws.com"))

        # Attaching the SSM policy to the role so we can use SSM to ssh into the ec2 instance
        role.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                "service-role/AmazonEC2RoleforSSM"))

        # Reading user data, to install siege into the ec2 instance.
        with open("stresstool_user_data.sh") as f:
            user_data = f.read()

        # Instance creation
        self.instance = aws_ec2.Instance(
            self,
            "Instance",
            instance_name="{}-stresstool".format(stack_name),
            instance_type=aws_ec2.InstanceType("t3.medium"),
            machine_image=amzn_linux,
            vpc=self.vpc,
            role=role,
            user_data=aws_ec2.UserData.custom(user_data),
            security_group=self.services_3000_sec_group)

        # All Outputs required for other stacks to build
        core.CfnOutput(self,
                       "NSArn",
                       value=self.namespace_outputs['ARN'],
                       export_name="NSARN")
        core.CfnOutput(self,
                       "NSName",
                       value=self.namespace_outputs['NAME'],
                       export_name="NSNAME")
        core.CfnOutput(self,
                       "NSId",
                       value=self.namespace_outputs['ID'],
                       export_name="NSID")
        core.CfnOutput(self,
                       "FE2BESecGrp",
                       value=self.services_3000_sec_group.security_group_id,
                       export_name="SecGrpId")
        core.CfnOutput(self,
                       "ECSClusterName",
                       value=self.cluster_outputs['NAME'],
                       export_name="ECSClusterName")
        core.CfnOutput(self,
                       "ECSClusterSecGrp",
                       value=self.cluster_outputs['SECGRPS'],
                       export_name="ECSSecGrpList")
        core.CfnOutput(self,
                       "ServicesSecGrp",
                       value=self.services_3000_sec_group.security_group_id,
                       export_name="ServicesSecGrp")
        core.CfnOutput(self,
                       "StressToolEc2Id",
                       value=self.instance.instance_id)
        core.CfnOutput(self,
                       "StressToolEc2Ip",
                       value=self.instance.instance_private_ip)
예제 #27
0
 def create_ecs_cluster(self, vpc, asg):
     cluster = ecs.Cluster(self, 'GhostCluster', vpc=vpc)
     cluster.add_auto_scaling_group(asg)
     return cluster
    def __init__(self, scope: core.Construct, construct_id: str,
                 identifier: str, user_arn: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        bucket = aws_s3.Bucket(
            self,
            id=f"flow-storage-bucket-{identifier}",
            auto_delete_objects=True,
            removal_policy=core.RemovalPolicy.DESTROY,
        )
        cache_bucket = aws_s3.Bucket(
            self,
            id=f"flow-cache-bucket-{identifier}",
            auto_delete_objects=True,
            removal_policy=core.RemovalPolicy.DESTROY,
        )
        vpc = aws_ec2.Vpc(
            self,
            id=f"bakery-vpc-{identifier}",
            cidr="10.0.0.0/16",
            enable_dns_hostnames=True,
            enable_dns_support=True,
            nat_gateways=0,
            subnet_configuration=[
                aws_ec2.SubnetConfiguration(
                    name="PublicSubnet1",
                    subnet_type=aws_ec2.SubnetType.PUBLIC)
            ],
            max_azs=3,
        )
        security_group = aws_ec2.SecurityGroup(
            self,
            id=f"security-group-{identifier}",
            vpc=vpc,
        )
        security_group.add_ingress_rule(aws_ec2.Peer.any_ipv4(),
                                        aws_ec2.Port.tcp_range(8786, 8787))
        security_group.add_ingress_rule(aws_ec2.Peer.any_ipv6(),
                                        aws_ec2.Port.tcp_range(8786, 8787))
        security_group.add_ingress_rule(security_group, aws_ec2.Port.all_tcp())
        cluster = aws_ecs.Cluster(
            self,
            id=f"bakery-cluster-{identifier}",
            vpc=vpc,
        )

        ecs_task_role = aws_iam.Role(
            self,
            id=f"prefect-ecs-task-role-{identifier}",
            assumed_by=aws_iam.ServicePrincipal(
                service="ecs-tasks.amazonaws.com"),
        )
        ecs_task_role.add_to_policy(
            aws_iam.PolicyStatement(
                resources=["*"],
                actions=[
                    "iam:ListRoleTags",
                ],
            ))
        ecs_task_role.add_to_policy(
            aws_iam.PolicyStatement(
                resources=[
                    f"arn:aws:logs:{self.region}:{self.account}:log-group:dask-ecs*"
                ],
                actions=[
                    "logs:GetLogEvents",
                ],
            ))
        bucket.grant_read_write(ecs_task_role)
        cache_bucket.grant_read_write(ecs_task_role)

        bucket_user = aws_iam.User.from_user_arn(
            self,
            id=f"prefect-bucket-user-{identifier}",
            user_arn=user_arn,
        )

        cache_bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                effect=aws_iam.Effect.ALLOW,
                actions=["s3:*Object"],
                resources=[f"{cache_bucket.bucket_arn}/*"],
                principals=[bucket_user],
            ))

        cache_bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                effect=aws_iam.Effect.ALLOW,
                actions=["s3:ListBucket"],
                resources=[cache_bucket.bucket_arn],
                principals=[bucket_user],
            ))

        bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                effect=aws_iam.Effect.ALLOW,
                actions=["s3:*Object"],
                resources=[f"{bucket.bucket_arn}/*"],
                principals=[bucket_user],
            ))

        bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                effect=aws_iam.Effect.ALLOW,
                actions=["s3:ListBucket"],
                resources=[bucket.bucket_arn],
                principals=[bucket_user],
            ))

        ecs_task_role.add_managed_policy(
            aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                managed_policy_name="AmazonECS_FullAccess"))

        prefect_ecs_agent_task_definition = aws_ecs.FargateTaskDefinition(
            self,
            id=f"prefect-ecs-agent-task-definition-{identifier}",
            cpu=512,
            memory_limit_mib=2048,
            task_role=ecs_task_role,
        )

        runner_token_secret = aws_ecs.Secret.from_secrets_manager(
            secret=aws_secretsmanager.Secret.from_secret_arn(
                self,
                id=f"prefect-cloud-runner-token-{identifier}",
                secret_arn=os.environ["RUNNER_TOKEN_SECRET_ARN"],
            ),
            field="RUNNER_TOKEN",
        )

        prefect_ecs_agent_task_definition.add_container(
            id=f"prefect-ecs-agent-task-container-{identifier}",
            image=aws_ecs.ContainerImage.from_registry(
                os.environ["BAKERY_IMAGE"]),
            port_mappings=[
                aws_ecs.PortMapping(container_port=8080, host_port=8080)
            ],
            logging=aws_ecs.LogDriver.aws_logs(stream_prefix="ecs-agent"),
            environment={
                "PREFECT__CLOUD__AGENT__LABELS":
                os.environ["PREFECT__CLOUD__AGENT__LABELS"]
            },
            secrets={"PREFECT__CLOUD__AGENT__AUTH_TOKEN": runner_token_secret},
            command=[
                "prefect",
                "agent",
                "ecs",
                "start",
                "--agent-address",
                "http://:8080",
                "--cluster",
                cluster.cluster_arn,
                "--task-role-arn",
                ecs_task_role.role_arn,
            ],
        )

        prefect_ecs_agent_service = aws_ecs_patterns.ApplicationLoadBalancedFargateService(
            self,
            id=f"prefect-ecs-agent-service-{identifier}",
            assign_public_ip=True,
            platform_version=aws_ecs.FargatePlatformVersion.LATEST,
            desired_count=1,
            task_definition=prefect_ecs_agent_task_definition,
            cluster=cluster,
            propagate_tags=aws_ecs.PropagatedTagSource.SERVICE,
        )

        prefect_ecs_agent_service.target_group.configure_health_check(
            path="/api/health", port="8080")

        ecs_task_execution_role = aws_iam.Role(
            self,
            id=f"prefect-ecs-task-execution-role-{identifier}",
            assumed_by=aws_iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
            managed_policies=[
                aws_iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AmazonECSTaskExecutionRolePolicy"),
            ],
        )

        core.CfnOutput(
            self,
            id=f"prefect-task-role-arn-output-{identifier}",
            export_name=f"prefect-task-role-arn-output-{identifier}",
            value=ecs_task_role.role_arn,
        )

        core.CfnOutput(
            self,
            id=f"prefect-cluster-arn-output-{identifier}",
            export_name=f"prefect-cluster-arn-output-{identifier}",
            value=cluster.cluster_arn,
        )

        core.CfnOutput(
            self,
            id=f"prefect-storage-bucket-name-output-{identifier}",
            export_name=f"prefect-storage-bucket-name-output-{identifier}",
            value=bucket.bucket_name,
        )

        core.CfnOutput(
            self,
            id=f"prefect-cache-bucket-name-output-{identifier}",
            export_name=f"prefect-cache-bucket-name-output-{identifier}",
            value=cache_bucket.bucket_name,
        )

        core.CfnOutput(
            self,
            id=f"prefect-task-execution-role-arn-output-{identifier}",
            export_name=f"prefect-task-execution-role-arn-output-{identifier}",
            value=ecs_task_execution_role.role_arn,
        )

        core.CfnOutput(
            self,
            id=f"prefect-security-group-output-{identifier}",
            export_name=f"prefect-security-group-output-{identifier}",
            value=security_group.security_group_id,
        )

        core.CfnOutput(
            self,
            id=f"prefect-vpc-output-{identifier}",
            export_name=f"prefect-vpc-output-{identifier}",
            value=vpc.vpc_id,
        )
예제 #29
0
    def __init__(self, scope: core.Construct, construct_id: str, *,
                 secrets: List[Secret]):
        super().__init__(scope, construct_id)

        vpc = aws_ec2.Vpc(
            self,
            "Vpc",
            enable_dns_support=True,
            enable_dns_hostnames=True,
            max_azs=3,
            nat_gateways=0,
            subnet_configuration=[
                aws_ec2.SubnetConfiguration(
                    name="Public", subnet_type=aws_ec2.SubnetType.PUBLIC)
            ],
        )

        postgres_volume_name = "duckbot_dbdata"
        file_system = aws_efs.FileSystem(
            self,
            "PostgresFileSystem",
            vpc=vpc,
            encrypted=True,
            file_system_name=postgres_volume_name,
            removal_policy=core.RemovalPolicy.DESTROY)
        file_system.node.default_child.override_logical_id(
            "FileSystem"
        )  # rename for compatibility with legacy cloudformation template

        task_definition = aws_ecs.TaskDefinition(
            self,
            "TaskDefinition",
            compatibility=aws_ecs.Compatibility.EC2,
            family="duckbot",
            memory_mib="960",
            network_mode=aws_ecs.NetworkMode.BRIDGE)

        postgres_data_path = "/data/postgres"
        postgres = task_definition.add_container(
            "postgres",
            container_name="postgres",
            image=aws_ecs.ContainerImage.from_registry("postgres:13.2"),
            essential=False,
            environment={
                "POSTGRES_USER": "******",
                "POSTGRES_PASSWORD": "******",
                "PGDATA": postgres_data_path,
            },
            health_check=aws_ecs.HealthCheck(
                command=["CMD", "pg_isready", "-U", "duckbot"],
                interval=core.Duration.seconds(30),
                timeout=core.Duration.seconds(5),
                retries=3,
                start_period=core.Duration.seconds(30),
            ),
            logging=aws_ecs.LogDriver.aws_logs(
                stream_prefix="ecs",
                log_retention=aws_logs.RetentionDays.ONE_MONTH),
            memory_reservation_mib=128,
        )
        task_definition.add_volume(
            name=postgres_volume_name,
            efs_volume_configuration=aws_ecs.EfsVolumeConfiguration(
                file_system_id=file_system.file_system_id, root_directory="/"))
        postgres.add_mount_points(
            aws_ecs.MountPoint(source_volume=postgres_volume_name,
                               container_path=postgres_data_path,
                               read_only=False))

        secrets_as_parameters = {
            # note, parameter version is required by cdk, but does not make it into the template; specify version 1 for simplicity
            x.environment_name:
            aws_ssm.StringParameter.from_secure_string_parameter_attributes(
                self,
                x.environment_name,
                parameter_name=x.parameter_name,
                version=1)
            for x in secrets
        }
        duckbot = task_definition.add_container(
            "duckbot",
            container_name="duckbot",
            essential=True,
            image=aws_ecs.ContainerImage.from_registry(
                self.node.try_get_context("duckbot_image")),
            environment={"STAGE": "prod"},
            secrets={
                k: aws_ecs.Secret.from_ssm_parameter(v)
                for k, v in secrets_as_parameters.items()
            },
            health_check=aws_ecs.HealthCheck(
                command=["CMD", "python", "-m", "duckbot.health"],
                interval=core.Duration.seconds(30),
                timeout=core.Duration.seconds(10),
                retries=3,
                start_period=core.Duration.seconds(30),
            ),
            logging=aws_ecs.LogDriver.aws_logs(
                stream_prefix="ecs",
                log_retention=aws_logs.RetentionDays.ONE_MONTH),
            memory_reservation_mib=128,
        )
        duckbot.add_link(postgres)

        asg = aws_autoscaling.AutoScalingGroup(
            self,
            "AutoScalingGroup",
            min_capacity=0,
            max_capacity=1,
            desired_capacity=1,
            machine_image=aws_ecs.EcsOptimizedImage.amazon_linux2(),
            instance_type=aws_ec2.InstanceType("t2.micro"),
            key_name="duckbot",  # needs to be created manually
            instance_monitoring=aws_autoscaling.Monitoring.BASIC,
            vpc=vpc,
        )

        asg.connections.allow_to_default_port(file_system)
        asg.connections.allow_from(aws_ec2.Peer.any_ipv4(),
                                   aws_ec2.Port.tcp(22))
        asg.connections.allow_from(aws_ec2.Peer.any_ipv4(),
                                   aws_ec2.Port.tcp(80))
        asg.connections.allow_from(aws_ec2.Peer.any_ipv4(),
                                   aws_ec2.Port.tcp(443))

        cluster = aws_ecs.Cluster(self,
                                  "Cluster",
                                  cluster_name="duckbot",
                                  vpc=vpc)
        cluster.add_asg_capacity_provider(
            aws_ecs.AsgCapacityProvider(cluster,
                                        "AsgCapacityProvider",
                                        auto_scaling_group=asg),
            can_containers_access_instance_role=True)

        aws_ecs.Ec2Service(
            self,
            "Service",
            service_name="duckbot",
            cluster=cluster,
            task_definition=task_definition,
            desired_count=1,
            min_healthy_percent=0,
            max_healthy_percent=100,
        )
    def __init__(self, scope: core.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        dockerImageAsset = DockerImageAsset(
            self,
            f"{APPLICATION_NAME}",
            directory="../",
            file="Dockerfile",
            exclude=["cdk/node_modules", ".git", "cdk/cdk.out"],
        )

        vpc = ec2.Vpc(self, f"{APPLICATION_NAME}VPC", max_azs=3)
        cluster = ecs.Cluster(self, f"{APPLICATION_NAME}Cluster", vpc=vpc)

        app_task = ecs.FargateTaskDefinition(
            self,
            f"{APPLICATION_NAME}-task",
            family=f"{APPLICATION_NAME}-family",
            cpu=512,
            memory_limit_mib=2048,
        )

        dd_api_key = ssm.StringParameter.value_for_string_parameter(
            self, "/datadog/snyk_demo/dd_api_key", 1)

        DATADOG_AGENT_VARS["DD_API_KEY"] = dd_api_key

        java_service_container = app_task.add_container(
            f"{APPLICATION_NAME}-java-app",
            image=ecs.ContainerImage.from_docker_image_asset(dockerImageAsset),
            essential=True,
            docker_labels={
                "com.datadoghq.ad.instances":
                '[{"host": "%%host%%", "port": 6379}]',
                "com.datadoghq.ad.check_names": '["tomcat"]',
                "com.datadoghq.ad.init_configs": "[{}]",
            },
            environment=APP_ENV_VARS,
            logging=ecs.LogDrivers.firelens(
                options={
                    "Name": "datadog",
                    "Host": "http-intake.logs.datadoghq.com",
                    "TLS": "on",
                    "apikey": dd_api_key,
                    "dd_service": DD_SERVICE,
                    "dd_source": "tomcat",
                    "dd_tags": DD_TAGS,
                    "provider": "ecs",
                }),
        )

        datadog_agent_container = app_task.add_container(
            f"{APPLICATION_NAME}-datadog-agent",
            image=ecs.ContainerImage.from_registry(
                name="datadog/agent:latest"),
            essential=True,
            environment=DATADOG_AGENT_VARS,
        )

        # Port exposure for the containerized app
        java_service_container.add_port_mappings(
            ecs.PortMapping(container_port=8080, host_port=8080))

        # Mandatory port exposure for the Datadog agent
        datadog_agent_container.add_port_mappings(
            ecs.PortMapping(container_port=8126, host_port=8126))

        app_task_service = ecs_patterns.NetworkLoadBalancedFargateService(
            self,
            id=f"{APPLICATION_NAME}-service",
            service_name=f"{APPLICATION_NAME}",
            cluster=cluster,  # Required
            cpu=512,  # Default is 256
            desired_count=1,  # Default is 1
            task_definition=app_task,
            memory_limit_mib=2048,  # Default is 512
            listener_port=80,
            public_load_balancer=True,
            health_check_grace_period=core.Duration.seconds(120),
        )

        # Security Group to allow load balancer to communicate with ECS Containers.
        app_task_service.service.connections.allow_from_any_ipv4(
            ec2.Port.tcp(8080), f"{APPLICATION_NAME} app inbound")