AWSTemplateFormatVersion: '2010-09-09' Description: Deploy Gradio and FastAPI services on AWS ECS Fargate Parameters: Environment: Type: String Default: dev AllowedValues: [dev, prod] # VPC Configuration VpcCIDR: Type: String Default: 10.0.0.0/16 PublicSubnet1CIDR: Type: String Default: 10.0.1.0/24 PublicSubnet2CIDR: Type: String Default: 10.0.2.0/24 # ECS Configuration ECSClusterName: Type: String Default: rag-ecs-cluster GradioTaskDefinitionCPU: Type: Number Default: 512 GradioTaskDefinitionMemory: Type: Number Default: 1024 FastAPITaskDefinitionCPU: Type: Number Default: 256 FastAPITaskDefinitionMemory: Type: Number Default: 512 # Container Images ContainerImageGradio: Type: String Description: URI of the Gradio container image in ECR ContainerImageFastAPI: Type: String Description: URI of the FastAPI container image in ECR # CertificateArn: # Type: String Resources: # VPC and Networking VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub ${Environment}-acres-vpc InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${Environment}-acres-igw AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Ref PublicSubnet1CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${Environment}-acres-public-subnet-1 PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Ref PublicSubnet2CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub ${Environment}-acres-public-subnet-2 PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${Environment}-acres-public-rt PublicRoute: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable # Security Groups GradioSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for Gradio service VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 7860 ToPort: 7860 CidrIp: 0.0.0.0/0 Description: INTERNET HTTPS - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: INTERNET HTTP SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 FastAPISecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for FastAPI service VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 8000 ToPort: 8000 CidrIp: 0.0.0.0/0 Description: INTERNET HTTPS - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: INTERNET HTTP SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 # IAM Roles and Policies # Gradio Execution Role - for pulling images and logging GradioTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy Policies: - PolicyName: GradioExecutionPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ecr:GetAuthorizationToken - ecr:BatchCheckLayerAvailability - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage Resource: '*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-gradio:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-gradio:log-stream:* # Gradio Task Role - for runtime permissions GradioTaskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: GradioTaskPolicy PolicyDocument: Version: '2012-10-17' Statement: # Add specific permissions needed by your Gradio application at runtime - Effect: Allow Action: - s3:GetObject - s3:PutObject Resource: !Sub arn:aws:s3:::${Environment}-acres-gradio-bucket/* # FastAPI Execution Role - for pulling images and logging FastAPITaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy Policies: - PolicyName: FastAPIExecutionPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ecr:GetAuthorizationToken - ecr:BatchCheckLayerAvailability - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage Resource: '*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-fastapi:* - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/ecs/${Environment}-acres-fastapi:log-stream:* # FastAPI Task Role - for runtime permissions FastAPITaskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: FastAPITaskPolicy PolicyDocument: Version: '2012-10-17' Statement: # Add specific permissions needed by your FastAPI application at runtime - Effect: Allow Action: - dynamodb:GetItem - dynamodb:PutItem - dynamodb:Query Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Environment}-acres-fastapi-table # Allow FastAPI to make HTTP calls to Gradio service - Effect: Allow Action: - execute-api:Invoke Resource: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:* # ECS Cluster ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ECSClusterName Tags: - Key: Environment Value: !Ref Environment # Load Balancer for Gradio GradioALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${Environment}-acres-gradio-alb Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '60' Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref GradioSecurityGroup GradioTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckPort: 7860 HealthCheckTimeoutSeconds: 20 HealthyThresholdCount: 2 Name: !Sub ${Environment}-acres-gradio-tg Port: 7860 Protocol: HTTP TargetType: ip UnhealthyThresholdCount: 5 VpcId: !Ref VPC TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '30' GradioHTTPSListener: # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref GradioTargetGroup LoadBalancerArn: !Ref GradioALB # Certificates: # - CertificateArn: !Ref CertificateArn Port: 7860 Protocol: HTTP # GradioHTTPListener: # # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html # Type: AWS::ElasticLoadBalancingV2::Listener # Properties: # Protocol: HTTP # Port: 80 # LoadBalancerArn: !Ref GradioALB # DefaultActions: # - Type: redirect # RedirectConfig: # Protocol: "HTTPS" # Port: 7860 # Host: "#{host}" # Path: "/#{path}" # Query: "#{query}" # StatusCode: "HTTP_301" # Load Balancer for FastAPI FastAPIALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${Environment}-acres-fastapi-alb Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '60' Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref FastAPISecurityGroup FastAPITargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckEnabled: true HealthCheckIntervalSeconds: 30 HealthCheckPath: /docs # FastAPI's Swagger UI path HealthCheckPort: 8000 HealthCheckTimeoutSeconds: 20 HealthyThresholdCount: 2 Name: !Sub ${Environment}-acres-fastapi-tg Port: 8000 Protocol: HTTP TargetType: ip UnhealthyThresholdCount: 5 VpcId: !Ref VPC TargetGroupAttributes: - Key: deregistration_delay.timeout_seconds Value: '30' FastAPIHTTPSListener: # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref FastAPITargetGroup LoadBalancerArn: !Ref FastAPIALB # Certificates: # - CertificateArn: !Ref CertificateArn Port: 8000 Protocol: HTTP # FastAPIHTTPListener: # # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-listener.html # Type: AWS::ElasticLoadBalancingV2::Listener # Properties: # Protocol: HTTP # Port: 80 # LoadBalancerArn: !Ref FastAPIALB # DefaultActions: # - Type: redirect # RedirectConfig: # Protocol: "HTTPS" # Port: 8000 # Host: "#{host}" # Path: "/#{path}" # Query: "#{query}" # StatusCode: "HTTP_301" # ECS Task Definitions GradioTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Sub ${Environment}-acres-gradio RequiresCompatibilities: - FARGATE Cpu: !Ref GradioTaskDefinitionCPU Memory: !Ref GradioTaskDefinitionMemory NetworkMode: awsvpc ExecutionRoleArn: !GetAtt GradioTaskExecutionRole.Arn TaskRoleArn: !GetAtt GradioTaskRole.Arn ContainerDefinitions: - Name: gradio Image: !Ref ContainerImageGradio PortMappings: - ContainerPort: 7860 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref GradioLogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: gradio FastAPITaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Sub ${Environment}-acres-fastapi RequiresCompatibilities: - FARGATE Cpu: !Ref FastAPITaskDefinitionCPU Memory: !Ref FastAPITaskDefinitionMemory NetworkMode: awsvpc ExecutionRoleArn: !GetAtt FastAPITaskExecutionRole.Arn TaskRoleArn: !GetAtt FastAPITaskRole.Arn ContainerDefinitions: - Name: fastapi Image: !Ref ContainerImageFastAPI PortMappings: - ContainerPort: 8000 Environment: - Name: GRADIO_URL Value: !Sub http://${GradioALB.DNSName}:7860/ LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref FastAPILogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: fastapi # CloudWatch Log Groups GradioLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /ecs/${Environment}-acres-gradio RetentionInDays: 30 FastAPILogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /ecs/${Environment}-acres-fastapi RetentionInDays: 30 # ECS Services GradioService: Type: AWS::ECS::Service DependsOn: - GradioHTTPSListener # - GradioHTTPListener Properties: ServiceName: !Sub ${Environment}-acres-gradio Cluster: !Ref ECSCluster TaskDefinition: !Ref GradioTaskDefinition DesiredCount: 1 LaunchType: FARGATE HealthCheckGracePeriodSeconds: 180 LoadBalancers: - ContainerName: gradio ContainerPort: 7860 TargetGroupArn: !Ref GradioTargetGroup NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref GradioSecurityGroup Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 DeploymentConfiguration: DeploymentCircuitBreaker: Enable: true Rollback: true MaximumPercent: 200 MinimumHealthyPercent: 100 FastAPIService: Type: AWS::ECS::Service DependsOn: - GradioService - FastAPIHTTPSListener # - FastAPIHTTPListener Properties: ServiceName: !Sub ${Environment}-acres-fastapi Cluster: !Ref ECSCluster TaskDefinition: !Ref FastAPITaskDefinition DesiredCount: 1 LaunchType: FARGATE HealthCheckGracePeriodSeconds: 180 LoadBalancers: - ContainerName: fastapi ContainerPort: 8000 TargetGroupArn: !Ref FastAPITargetGroup NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref FastAPISecurityGroup Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 DeploymentConfiguration: DeploymentCircuitBreaker: Enable: true Rollback: true MaximumPercent: 200 MinimumHealthyPercent: 100 # Add deployment controller for better rollout control DeploymentController: Type: ECS Outputs: VpcId: Description: VPC ID Value: !Ref VPC PublicSubnet1: Description: Public Subnet 1 Value: !Ref PublicSubnet1 PublicSubnet2: Description: Public Subnet 2 Value: !Ref PublicSubnet2 GradioServiceUrl: Description: URL for the Gradio service Value: !Sub http://${GradioALB.DNSName}:7860/ ECSClusterName: Description: Name of the ECS cluster Value: !Ref ECSCluster GradioServiceName: Description: Name of the Gradio service Value: !GetAtt GradioService.Name FastAPIServiceName: Description: Name of the FastAPI service Value: !GetAtt FastAPIService.Name FastAPIServiceUrl: Description: URL for the FastAPI service Value: !Sub http://${FastAPIALB.DNSName}:8000/