### ECS Service
ECSService:
Type: AWS::ECS::Service
DependsOn: AttachGateway
Properties:
ServiceName: document-portal-service
Cluster: !Ref ECSCluster
LaunchType: FARGATE
DesiredCount: 1
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref Subnet1
- !Ref Subnet2
SecurityGroups:
- !Ref ECSSecurityGroup
TaskDefinition: !Ref ECSTaskDefinition
Outputs:
ECSClusterName:
Value: !Ref ECSCluster
TaskDefinitionArn:
Value: !Ref ECSTaskDefinition
ECSService:
Type: AWS::ECS::Service
DependsOn: AttachGateway
Type: AWS::ECS::Service — creates a running service which ensures your task(s) stay up and (optionally) register with a load balancer.
DependsOn: AttachGateway — CloudFormation will wait for the Internet Gateway attachment to complete before creating the service. This matters because your tasks are configured to get public IPs, and the IGW/route needs to exist for internet connectivity.
Properties:
ServiceName: document-portal-service
Friendly name in the console for the service.
Cluster: !Ref ECSCluster
Tells ECS which cluster the service should run in (the cluster you created earlier).
LaunchType: FARGATE
Uses Fargate (serverless containers). You don't manage EC2 instances — AWS provisions the ENIs and infra for you.
DesiredCount: 1
The service will try to keep 1 task running. If it crashes, ECS will launch another to maintain this count.
For HA, you’ll likely want DesiredCount >= 2 across AZs or set up an autoscaling policy.
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref Subnet1
- !Ref Subnet2
SecurityGroups:
- !Ref ECSSecurityGroup
NetworkMode = awsvpc (from task definition) + this section means:
Each task gets its own ENI (Elastic Network Interface) and private IP within the specified subnets.
AssignPublicIp: ENABLED means each task’s ENI also gets a public IP assigned. That makes the task directly reachable from the internet (subject to security group rules and routing).
Subnets: the task ENIs will be created in the listed subnets (you gave two — AZ spread). ECS will place tasks across the subnets for availability.
SecurityGroups: the ENIs will use this security group (you earlier opened port 8080 to 0.0.0.0/0).
Implications & cautions:
Assigning public IPs to tasks exposes them directly to the internet. This is simpler but less secure than placing tasks in private subnets and fronting them with an Application Load Balancer (ALB).
Common, more secure pattern:
Put tasks in private subnets (no public IP).
Create an ALB in public subnets that receives internet traffic and forwards to tasks in private subnets (ALB has public IPs; tasks do not).
Security groups: ALB SG allows 80/443 from internet; task SG allows traffic only from ALB SG.
If you keep AssignPublicIp: ENABLED, lock down the security group to only required sources (avoid 0.0.0.0/0 unless absolutely needed).
TaskDefinition: !Ref ECSTaskDefinition
Points the service to the task definition revision to run (the blueprint you defined earlier).
This service will run tasks and restart them if they fail to maintain DesiredCount.
It will not:
Create or register a Load Balancer (unless you add LoadBalancers + Role properties).
Configure automatic scaling (you must add ECS Service Auto Scaling).
Perform application-level health checks unless you integrate a load balancer or configure healthCheckGracePeriodSeconds and proper task health checks.
Use an ALB + private tasks
Add an Application Load Balancer in public subnets, target group pointing to tasks (port 8080), and set AssignPublicIp: DISABLED.
Secure traffic with security groups: ALB SG (internet → ALB), Task SG (ALB SG → tasks). This is standard production pattern.
Enable high availability
DesiredCount: 2 (or use an autoscaling policy) so tasks run across both subnets/AZs.
Add health checks
If using ALB, configure health checks (path, interval, healthy/unhealthy thresholds).
Optionally set healthCheckGracePeriodSeconds for startup time.
Service Auto Scaling
Add AWS::ApplicationAutoScaling::ScalingPolicy and ScalableTarget to scale tasks based on CPU/RAM or custom CloudWatch metrics.
Use Deployment Configuration
Control deployment strategy (minimum healthy percent, maximum percent) to avoid downtime during updates.
Consider a Service Role
If you register with load balancer, ECS may need an Role (service-linked role or Role property depending on deployment). CloudFormation often creates an AutomaticIAMRole but check docs and permissions.
Logging and Monitoring
Ensure CloudWatch Logs, Container Insights, and ALB access logs are enabled for observability.
Outputs:
ECSClusterName:
Value: !Ref ECSCluster
TaskDefinitionArn:
Value: !Ref ECSTaskDefinition
ECSClusterName — exports the cluster name (the logical id you created). Handy to show in stack outputs or reference in other stacks (you can add Export: Name: if you want cross-stack usage).
TaskDefinitionArn — returns the task definition revision ARN or family:revision (the CloudFormation Ref for a task definition returns the task definition ARN). Useful for CI/CD pipelines to know which task definition is deployed.
You’ve defined a service that runs your container on Fargate, keeps 1 copy running, places the task ENIs in two subnets, and gives them public IPs so they are reachable from the internet.
That works for quick testing, but for production:
prefer private tasks + ALB,
increase redundancy (DesiredCount or autoscaling),
add health checks and tighter security group rules,
and integrate autoscaling and deployment configuration for smooth updates.