Madushan Pathirana
09/10/2025, 5:30 AMMarvin
09/10/2025, 5:30 AMMarvin
09/10/2025, 5:33 AM{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECSControl",
"Effect": "Allow",
"Action": [
"ecs:RunTask",
"ecs:StopTask",
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition",
"ecs:RegisterTaskDefinition",
"ecs:DeregisterTaskDefinition",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "PassRolesToTasks",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<account-id>:role/<ecs-task-execution-role-name>",
"arn:aws:iam::<account-id>:role/<ecs-task-role-name>"
]
},
{
"Sid": "OptionalCreateLogsGroup",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup"
],
"Resource": "*"
}
]
}
3) Prefect Server connectivity from Fargate tasks
- Ensure every Fargate task can reach PREFECT_API_URL:
- If your Prefect Server API is private on the EC2 host, put it behind an internal ALB/NLB and provide a private URL (recommended). Open the target SG/port to the ECS tasks’ SG.
- If public, provide a public URL and open the EC2 SG/port appropriately.
- Share with you the final URL you should set as PREFECT_API_URL (e.g., http(s)//internal alb.your.domain4200 or 443 if behind TLS).
4) Optional VPC endpoints (to avoid NAT costs and public egress)
- Consider interface/gateway endpoints for: ECR (api+dkr), CloudWatch Logs, Secrets Manager/SSM, STS. Otherwise ensure a NAT gateway for internet egress.
How many ECS services do you need?
- For Prefect flow runs on ECS Fargate: zero services. Prefect uses ecs:RunTask to launch tasks on demand.Marvin
09/10/2025, 5:33 AMMadushan Pathirana
09/10/2025, 5:38 AMMarvin
09/10/2025, 5:38 AMMarvin
09/10/2025, 5:41 AMhttp://<host-or-lb>:4200/api
or https if terminated at your LB.
Optional to reduce NAT costs
- Add VPC endpoints for: ECR (api + dkr), CloudWatch Logs, STS, Secrets Manager/SSM.
How many ECS services do you need?
- One ECS Service to run the Prefect ECS worker (desiredCount=1 is fine to start).
- You do NOT create services for flow runs — the worker uses ecs:RunTask to launch them on demand.
- For multiple environments:
- Best practice: one work pool + one ECS Service (worker) per environment (dev/stage/prod) for clear isolation and blast-radius control.
- You can scale desiredCount>1 for HA, or run multiple worker services if you want separate queues or capacity.
Do you need access keys for the ECS task execution role?
- No. Do not create or use access keys for execution roles.
- The ECS service assumes the worker’s execution and task roles automatically.
- Whoever deploys the ECS service (your CI/CD or engineer) needs permissions like ecs:CreateService/UpdateService and iam:PassRole to pass the worker roles — but not the worker/flow execution role’s access keys.
What to put in the worker service/task definition
- Container image: prefecthq/prefect:3-latest (or your bespoke image)
- Command:
prefect worker start --pool <your-ecs-pool-name>
- Environment variables:
- PREFECT_API_URL: http(s)//<your server>4200/api
- Any other Prefect settings you need (e.g., PREFECT_LOGGING_LEVEL)
- CPU/memory: start small (e.g., 0.25 vCPU/512–1024MB) and adjust
- Networking: awsvpc in your private subnets, SG as above
- IAM roles: attach the worker task execution role and worker task roleMarvin
09/10/2025, 5:41 AMprefect work-pool create "my-ecs-pool" --type ecs
- Inspect default ECS job template to see what variables you’ll configure (cluster, subnets/SGs, image, roles, logs):
prefect work-pool get-default-base-job-template --type ecs
- Configure the pool’s base job variables for:
- cluster, launch_type=FARGATE (or capacityProviderStrategy)
- network_configuration (subnets, security groups, assignPublicIp=false if using private subnets)
- image (your flow image), execution_role_arn, task_role_arn
- cloudwatch_logs options (log group name)
- Deploy the worker ECS Service using the task definition above.
Docs
- Prefect AWS ECS guide: Prefect AWS ECS guide
- Workers and Work Pools overview: Workers and Work Pools
- AWS: ECS task execution role: ECS task execution role
Quick confirmations to tailor this:
- Will you split dev/stage/prod into separate work pools and worker services?
- Are your flow images in private ECR?
- Is your Prefect Server API going to be internal (ALB/NLB) or public? I can help finalize the exact pool variables and security groups once you confirm.Madushan Pathirana
09/10/2025, 10:27 AMMarvin
09/10/2025, 10:27 AMMarvin
09/10/2025, 10:28 AMMadushan Pathirana
09/10/2025, 10:32 AMMarvin
09/10/2025, 10:32 AMMarvin
09/10/2025, 10:33 AMMadushan Pathirana
09/10/2025, 10:35 AMMarvin
09/10/2025, 10:35 AMMarvin
09/10/2025, 10:40 AMprefect work-pool create "ecs-pool" --type ecs
Step 2) Export the default ECS base job template
prefect work-pool get-default-base-job-template --type ecs --file ecs-template.json
Step 3) Edit ecs-template.json variables
- Open ecs-template.json and fill the “variables” section to match your AWS environment. Example (fill in <>):
{
"job_configuration": { ... },
"variables": {
"cluster": "arn:aws:ecs:ap-southeast-1:<account-id>:cluster/<your-ecs-cluster>",
"launch_type": "FARGATE",
"container_name": "prefect-task",
"image": "<your-flow-image-uri-or-public-image>",
"cpu": 512,
"memory": 1024,
"execution_role_arn": "arn:aws:iam::<account-id>:role/<flow-task-execution-role>",
"task_role_arn": "arn:aws:iam::<account-id>:role/<flow-task-role>",
"vpc_id": "<your-vpc-id>",
"network_configuration": {
"awsvpcConfiguration": {
"subnets": ["subnet-aaaa", "subnet-bbbb"],
"securityGroups": ["sg-xxxxxx"],
"assignPublicIp": "DISABLED"
}
},
"configure_cloudwatch_logs": true,
"cloudwatch_logs_prefix": "prefect",
"cloudwatch_logs_options": {
"awslogs-group": "/prefect/flows",
"awslogs-region": "ap-southeast-1",
"awslogs-create-group": "true",
"awslogs-stream-prefix": "flows"
},
"stream_output": true,
"task_start_timeout_seconds": 600,
"task_watch_poll_interval": 5,
"auto_deregister_task_definition": true
}
}
Notes:
- Use your private subnets and an SG that allows outbound internet or VPC endpoints for ECR/Logs/STS.
- If your flow image is in private ECR, make sure the execution role has ECR read and the network has NAT or ECR VPC endpoints.
Step 4) Apply the base job template to the pool
prefect work-pool update "ecs-pool" --base-job-template ecs-template.json
Step 5) Start the worker on your EC2 host
- Ensure the EC2 instance has the instance profile role with ECS permissions and iam:PassRole.
- Set your Prefect API URL (include /api):
export PREFECT_API_URL="http://<your-server-or-internal-lb>:4200/api"
prefect worker start --pool ecs-pool --name ec2-ecs-worker
Step 6) Deploy your flows to this pool
Option A: In Python
from prefect import flow
@flow
def my_flow():
print("hello from ECS")
if __name__ == "__main__":
from prefect.flows import Flow
# If your code is in a repo:
Flow.from_source(
"<https://github.com/<owner>/<repo>>",
"path/to/flow.py:my_flow",
).deploy(
name="my-flow-ecs",
work_pool_name="ecs-pool",
# Optionally set an image for this deployment; otherwise use the pool default
image="<your-flow-image-uri>",
)
Option B: CLI from your project root (if you prefer CLI)Marvin
09/10/2025, 10:40 AMMadushan Pathirana
09/10/2025, 10:56 AMMarvin
09/10/2025, 10:56 AMMarvin
09/10/2025, 10:56 AMexport PREFECT_API_URL="http://<your-server-or-internal-lb>:4200/api"
prefect worker start --pool ecs-pool --name ec2-ecs-worker
Deploy your flows
- You can create deployments via code or CLI; after that, you can manage schedules/parameters in the UI.
- Example (from code):
from prefect import flow
@flow
def my_flow():
print("hello from ECS")
if __name__ == "__main__":
from prefect.flows import Flow
Flow.from_source(
"<https://github.com/<owner>/<repo>>",
"path/to/flow.py:my_flow",
).deploy(
name="my-flow-ecs",
work_pool_name="ecs-pool",
image="<your-ecr-image-uri>", # or rely on pool default
)
Networking reminder
- No inbound rules needed on ECS tasks.
- Prefect Server SG must allow inbound 4200 from the ECS tasks (or an internal ALB SG).
- Tasks need outbound to Prefect Server and AWS services (ECR/CloudWatch/STS) via NAT or VPC endpoints.
Docs
- Prefect AWS ECS guide
- Workers and Work Pools
- ECS task execution role
If you share your cluster name/ARN, subnets, SG, and the two role ARNs, I can fill in the exact Base Job Variables you’ll paste into the UI.Madushan Pathirana
09/10/2025, 10:57 AMMarvin
09/10/2025, 10:57 AMMarvin
09/10/2025, 10:58 AM{
"cluster": "arn:aws:ecs:ap-southeast-1:<account-id>:cluster/<your-cluster>",
"launch_type": "FARGATE",
"container_name": "prefect-task",
"image": "<your-ecr-image-or-public-image>",
"cpu": 512,
"memory": 1024,
"execution_role_arn": "arn:aws:iam::<account-id>:role/<flow-task-exec-role>",
"task_role_arn": "arn:aws:iam::<account-id>:role/<flow-task-role>",
"network_configuration": {
"awsvpcConfiguration": {
"subnets": [
"subnet-aaaa",
"subnet-bbbb"
],
"securityGroups": [
"sg-xxxxxx"
],
"assignPublicIp": "DISABLED"
}
},
"configure_cloudwatch_logs": true,
"cloudwatch_logs_options": {
"awslogs-group": "/prefect/flows",
"awslogs-region": "ap-southeast-1",
"awslogs-create-group": "true",
"awslogs-stream-prefix": "flows"
},
"stream_output": true,
"auto_deregister_task_definition": true
}
EC2 worker startup (what I’ll do)
- Ensure the EC2 instance profile has the ECS + iam:PassRole permissions
- Start the worker pointing at the pool:
export PREFECT_API_URL="http://<your-server-or-internal-lb>:4200/api"
prefect worker start --pool ecs-pool --name ec2-ecs-worker
Cost reminder
- No ECS Service baseline cost. You pay Fargate only when flow-run tasks are running (plus NAT/VPC endpoints, CloudWatch Logs, ECR).
References
- Prefect ECS guide: Prefect AWS ECS guide
- Workers and Work Pools: Workers and Work Pools
- ECS task execution role: AWS docs: task execution role
If you want, I can turn this into a ready-to-send ticket with placeholders for your account ID/ARNs—just share your cluster name and whether you’re using an internal ALB for the Server.Madushan Pathirana
09/11/2025, 11:53 AMMarvin
09/11/2025, 11:53 AMMarvin
09/11/2025, 12:06 PMMadushan Pathirana
09/11/2025, 12:58 PMMarvin
09/11/2025, 12:58 PMMarvin
09/11/2025, 1:02 PMfrom prefect.blocks.system import Secret
dsn = Secret.load("rds-postgres-dsn").get()
# Use dsn in your DB client
- Confirm the ECS tasks’ SG is allowed to connect to the RDS SG on port 5432.
Docs
- ECS guide: Run Prefect on AWS ECS (3.x)
- Deployments: Create deployments in Prefect 3.x
Open questions to confirm
- What hostname or private IP should we use for PREFECT_API_URL so that ECS tasks can reach the Prefect Server?
- Do you already have a base ECR image for the POC, or would you like a minimal Dockerfile to start?Madushan Pathirana
09/11/2025, 1:40 PMMarvin
09/11/2025, 1:40 PMMarvin
09/11/2025, 1:41 PMMadushan Pathirana
09/11/2025, 1:46 PMMarvin
09/11/2025, 1:46 PMMarvin
09/11/2025, 1:48 PM{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECSControlPlane",
"Effect": "Allow",
"Action": [
"ecs:RunTask",
"ecs:RegisterTaskDefinition",
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition",
"ecs:DescribeClusters",
"ecs:ListClusters",
"ecs:ListTaskDefinitions"
],
"Resource": "*"
},
{
"Sid": "AllowPassingEcsTaskRoles",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<ACCOUNT_ID>:role/prefect-ecs-task-role",
"arn:aws:iam::<ACCOUNT_ID>:role/ecsTaskExecutionRole"
],
"Condition": {
"StringEquals": {
"iam:PassedToService": "<http://ecs-tasks.amazonaws.com|ecs-tasks.amazonaws.com>"
}
}
}
]
}
Notes
- Replace the two role ARNs with the actual Task Role and Task Execution Role you’ll use for your flow tasks.
- The iam:PassRole permission is critical because the worker:
- Registers task definitions that reference those roles
- Runs tasks that must assume those roles
- You can pare back the List* permissions if desired; they’re convenient for validation but not strictly required at runtime.
- You do not need ECR or CloudWatch Logs permissions on the worker role; those are handled by the ECS Task Execution Role attached to each flow task.
Trust policy for the EC2 instance role (so the instance can assume it)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "<http://ec2.amazonaws.com|ec2.amazonaws.com>"
},
"Action": "sts:AssumeRole"
}
]
}
Where to put these in Prefect
- In the Prefect UI, create an ECS work pool and reference:
- The cluster name
- Subnet IDs and Security Group for tasks
- The Task Role ARN and Task Execution Role ARN (these are the roles your flow tasks will use)
- Do not put AWS keys in the work pool.
- Start the Prefect worker on your EC2 instance. The worker will use the EC2 instance role automatically.
If you ever run the worker on ECS/Fargate instead of EC2
- Use the same permissions as above, but attach them to the worker task’s role (trust policy principal becomes ecs-tasks.amazonaws.com).
Docs
- Run Prefect on AWS ECS (3.x)
If you share the exact ARNs for your task role and execution role, I can tailor the iam:PassRole statement precisely and suggest optional resource-level restrictions.Madushan Pathirana
09/11/2025, 2:17 PMMarvin
09/11/2025, 2:17 PMMarvin
09/11/2025, 2:19 PM{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECSControl",
"Effect": "Allow",
"Action": [
"ecs:RunTask",
"ecs:RegisterTaskDefinition",
"ecs:DescribeTasks",
"ecs:StopTask",
"ecs:DescribeTaskDefinition",
"ecs:ListTaskDefinitions",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "PassRolesToECS",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<account-id>:role/<ecs-task-execution-role>",
"arn:aws:iam::<account-id>:role/<ecs-task-role>"
],
"Condition": {
"StringLike": {
"iam:PassedToService": "<http://ecs-tasks.amazonaws.com|ecs-tasks.amazonaws.com>"
}
}
}
]
}
2) ECS task execution role (used by ECS to pull images, write logs)
- Attach AWS managed policy: AmazonECSTaskExecutionRolePolicy
- This gives ECR and CloudWatch Logs access needed to pull your image and stream logs.
- Docs: AWS: Task execution role
3) ECS task role (your flow’s application role)
- What your flow actually uses inside the container.
- Grant only what your code needs (e.g., S3 access). For RDS with username/password, you may not need any AWS perms here.
- Note: Prefect-stored DB credentials are fine; just ensure the task is in the right subnets/SGs to reach RDS.
4) ECS container instance role (only for EC2 launch type capacity hosts)
- If you’re running your own ECS cluster with EC2 container instances, those instances need the ecsInstanceRole with the AWS managed policy AmazonEC2ContainerServiceforEC2Role so the ECS agent can register with the cluster.
- Docs: AWS: Container instance IAM role
Notes and common gotchas
- The worker host needs iam:PassRole for both the execution role and the task role ARNs — this is the most common missing permission.
- The worker host does NOT need ECR or CloudWatch Logs permissions; the execution role handles those.
- Ensure you actually have EC2 capacity registered in your ECS cluster (EC2 launch type) with the correct instance role (#4). The worker just submits tasks — ECS must have instances to place them on.
- For RDS access: place tasks in subnets/SGs that can reach your RDS SG; IAM isn’t required if you’re using password auth.
- Prefect 3 ECS guide: Prefect 3: ECS worker guide
Questions to confirm so I can tailor this exactly:
- Do you already have an ECS cluster with EC2 container instances registered, or are you planning to register your Prefect EC2 host as a container instance too?
- Are your images in ECR (same account/region as ap-southeast-1)?
- Beyond RDS, will flows need access to S3/Secrets Manager/etc. from inside the task?Madushan Pathirana
09/11/2025, 2:28 PMMadushan Pathirana
09/11/2025, 2:28 PMMarvin
09/11/2025, 2:28 PMMarvin
09/11/2025, 2:32 PMecs:RunTask against that task definition on that cluster, plus read-only describes and iam:PassRole for the two ECS roles (execution role and task role).
- Run the Prefect ECS worker (as a long‑running service or on your EC2) using that locked‑down role.
- You provide:
- The ECR image URI and the ECS task definition you want (CPU/mem, container name, env/logging, subnets/SGs).
- The Prefect work pool name and server URL (and API key if using Prefect Cloud).
- Configure the Prefect ECS work pool to use the existing task definition (no re-registering). The worker will only supply container overrides (command/env) at run time.
- Prefect will then just queue work; the worker (running under their restricted role) will call RunTask.
Minimal worker IAM policy (tight scope, no task definition registration):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RunOnlyThisTaskOnThisCluster",
"Effect": "Allow",
"Action": "ecs:RunTask",
"Resource": "arn:aws:ecs:<region>:<account-id>:task-definition/<family-or-arn>",
"Condition": {
"ArnEquals": {
"ecs:cluster": "arn:aws:ecs:<region>:<account-id>:cluster/<cluster-name>"
}
}
},
{
"Sid": "DescribeForStatus",
"Effect": "Allow",
"Action": [
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "OptionalStopForCancellations",
"Effect": "Allow",
"Action": "ecs:StopTask",
"Resource": "*",
"Condition": {
"ArnEquals": {
"ecs:cluster": "arn:aws:ecs:<region>:<account-id>:cluster/<cluster-name>"
}
}
},
{
"Sid": "PassOnlyTheseRolesToECS",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<account-id>:role/<ecs-task-execution-role>",
"arn:aws:iam::<account-id>:role/<ecs-task-role>"
],
"Condition": {
"StringLike": {
"iam:PassedToService": "<http://ecs-tasks.amazonaws.com|ecs-tasks.amazonaws.com>"
}
}
}
]
}
- No ecs:RegisterTaskDefinition needed if you pre-create the task definition.
- You can even omit ecs:StopTask if they don’t want Prefect to cancel tasks; just know flow cancellations won’t stop running containers.
- The ECR pull and CloudWatch Logs access are handled by the ECS task execution role (attach AWS managed AmazonECSTaskExecutionRolePolicy to that role).
Option B: If they will not grant ecs:RunTask to any worker at all
- Then Prefect cannot dispatch ECS tasks. In that case, either:
- Run flows with a non‑ECS work pool (Process or Docker) on your EC2 host, or
- Let them schedule ECS tasks outside Prefect (EventBridge/Cron), but Prefect won’t be orchestrating those runs.
Relevant docs
- Prefect 3 ECS worker guide: Prefect 3: ECS worker guide
- AWS: Task execution role: AWS: Task execution role
- AWS: ECS IAM actions/resources: AWS: ECS IAM actions, resources, and condition keys
Clarifying question to proceed:Marvin
09/11/2025, 2:32 PMecs:RunTask (restricted to your cluster + task definition) and iam:PassRole for the specific execution/task roles? If yes, I’ll help you fill out the exact work pool base job template to use the pre-created task definition so no registrations happen.Madushan Pathirana
09/11/2025, 2:46 PMMarvin
09/11/2025, 2:46 PMMarvin
09/11/2025, 2:47 PMecs:RunTask, here are workable patterns:
1) EventBridge “indirection” (no ECS perms for Prefect)
- Flow: Prefect worker → events:PutEvents → EventBridge rule → ECS RunTask (using a target role owned by your engineer).
- Prefect only needs:
{
"Effect": "Allow",
"Action": "events:PutEvents",
"Resource": "arn:aws:events:ap-southeast-1:<account-id>:event-bus/<bus-name>"
}
- Your engineer configures:
- EventBridge rule that targets ECS RunTask for your cluster + task definition.
- A target role that has ecs:RunTask + iam:PassRole for the task execution + task roles.
- Result: Prefect triggers tasks indirectly; scaling is handled by ECS EC2 capacity.
2) SNS/Lambda “run-task proxy”
- Flow: Prefect worker → sns:Publish → Lambda → ecs:RunTask.
- Prefect only needs:
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-southeast-1:<account-id>:<topic>"
}
- Lambda’s role (owned by your engineer) has ecs:RunTask + iam:PassRole scoped to your cluster/task def.
- Result: No ECS perms on Prefect side; autoscaling via ECS remains possible.
3) Engineer-owned ECS worker
- They run the Prefect ECS worker under a tightly-scoped role that can RunTask. You provide pool config; they control IAM and scale by running more workers or increasing service count. Prefect can still schedule many runs; ECS provides elasticity.
4) Non‑ECS workers with EC2 Auto Scaling
- If you must avoid ECS entirely, run Process or Docker workers on an EC2 Auto Scaling Group.
- Use a launch template that starts:
prefect worker start -p <your-work-pool>
- Scale the ASG via CPU or a small scaler that publishes a “queue backlog” custom metric.
- You still get some elasticity, but it’s bounded by your ASG capacity, not ECS tasks.
If none of the indirection patterns (1 or 2) are acceptable, then yes, you’re restricted to the capacity where your workers run.
Want me to draft the exact IAM, EventBridge target role, and the Prefect work pool config for Option 1 (EventBridge) or Option 2 (SNS/Lambda)?Madushan Pathirana
09/11/2025, 7:00 PMMarvin
09/11/2025, 7:00 PMMarvin
09/11/2025, 7:02 PM{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RunOnlyThisTaskOnThisCluster",
"Effect": "Allow",
"Action": "ecs:RunTask",
"Resource": "arn:aws:ecs:<region>:<account-id>:task-definition/<family-or-arn>",
"Condition": {
"ArnEquals": {
"ecs:cluster": "arn:aws:ecs:<region>:<account-id>:cluster/<cluster-name>"
}
}
},
{
"Sid": "DescribeForStatus",
"Effect": "Allow",
"Action": [
"ecs:DescribeTasks",
"ecs:DescribeTaskDefinition",
"ecs:DescribeClusters"
],
"Resource": "*"
},
{
"Sid": "OptionalStopForCancellations",
"Effect": "Allow",
"Action": "ecs:StopTask",
"Resource": "*",
"Condition": {
"ArnEquals": {
"ecs:cluster": "arn:aws:ecs:<region>:<account-id>:cluster/<cluster-name>"
}
}
},
{
"Sid": "PassOnlyTheseRolesToECS",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::<account-id>:role/<ecs-task-execution-role>",
"arn:aws:iam::<account-id>:role/<ecs-task-role>"
],
"Condition": {
"StringLike": {
"iam:PassedToService": "<http://ecs-tasks.amazonaws.com|ecs-tasks.amazonaws.com>"
}
}
}
]
}
- Note: No ecs:RegisterTaskDefinition permission is needed if they pre-create the task definition.
What you configure in Prefect
- Create an ECS work pool and set the base job template to use:
- The existing ECS cluster name/ARN
- The pre-created task definition ARN (so the worker does not register new task defs)
- Network settings (subnets/security groups) that can reach your RDS
- Container name to override, plus optional command/env overrides as needed
- Run the worker on that EC2 instance (with the instance profile attached). It will use IMDS credentials automatically.
Control boundaries
- Your engineer controls:
- Which cluster and task definition can be used (via resource-scoped IAM and PassRole)
- The task execution and task roles
- ECS capacity and scaling
- You do not need any static credentials and cannot run arbitrary ECS tasks outside the allowed scope.
Docs for reference
- Prefect 3 ECS worker guide: Prefect 3: ECS worker guide
- AWS: Task execution role: AWS: Task execution role
- AWS: Container instance role (EC2 launch type): AWS: Container instance IAM role
If you want, I can draft the exact IAM policy with your real ARNs (cluster, task definition, execution/task roles) and a quick checklist for your engineer, plus the work pool base job template fields to fill in.Madushan Pathirana
09/11/2025, 7:15 PMMarvin
09/11/2025, 7:15 PMMarvin
09/11/2025, 7:16 PMprefect worker start -p <your-ecs-work-pool>
Autoscaling note
- Prefect “autoscaling” here means it will submit more ECS tasks as more flow runs queue up. Actual compute scaling comes from ECS capacity providers/ASGs. If you only have a single ECS container instance, there’s nothing for ECS to scale — make sure your engineer configures a capacity provider.
- AWS docs: ECS capacity providers and managed scaling
Helpful references
- Prefect 3 ECS worker guide: Prefect 3: ECS worker guide
- AWS: Task execution role (ECR/Logs): Task execution role
If you share your cluster ARN, task definition ARN, and the two role ARNs, I can draft the exact IAM policy for the EC2 instance profile and the base job template values to paste into the work pool.Madushan Pathirana
09/11/2025, 7:22 PMMarvin
09/11/2025, 7:22 PMMarvin
09/11/2025, 7:23 PMMadushan Pathirana
09/12/2025, 5:46 AMMarvin
09/12/2025, 5:47 AMMarvin
09/12/2025, 5:59 AMprefecthq/prefect:3.x.y-python3.11
- Your flows should run in a runtime image that includes your dependencies (build into ECR and reference in the ECS work pool template).
1) Bring up Prefect Server as an ECS Service
- Task definition:
- Container image: prefecthq/prefect:<your-3.x.y-tag>
- Command:
prefect server start --host 0.0.0.0 --port 4200 --ui
- Port mapping: container 4200
- Env vars:
- This one is required for RDS:
PREFECT_API_DATABASE_CONNECTION_URL=postgresql+asyncpg://<user>:<password>@<rds-endpoint>:5432/<db_name>
- Optional (only if you need to override defaults):
PREFECT_SERVER_API_HOST=0.0.0.0
PREFECT_SERVER_API_PORT=4200
- Execution role: ECS task execution role
- Task role: to allow CloudWatch logging if needed
- Logs: send to CloudWatch
- ALB/NLB:
- Target port 4200 to the Server service
- Optional TLS on the ALB
- Quick health check:
- After deploy, verify:
curl http://<load-balancer-dns>:4200/api/health
- It should return OK.
Docs:
- Server on Docker/ECS
- Settings reference
2) Create an ECS work pool (EC2 launch type)
Run these locally (or from any machine that can reach your server API). If you’re self-hosting server, set PREFECT_API_URL on your shell first so the CLI talks to your server:
export PREFECT_API_URL=http://<load-balancer-dns>:4200/api
prefect work-pool create ecs-ec2-pool --type ecs
prefect work-pool get-default-base-job-template --type ecs > ecs-job-template.json
Edit ecs-job-template.json so most defaults are set in the pool (so deployments don’t need to repeat them). Key fields to fill:
- job_configuration.task_definition
- family: your task definition family name for flow runs (or leave blank and use task_definition_arn)
- executionRoleArn: arnawsiam:<acct>role/<ecs-execution-role>
- containerDefinitions[0].name: a container name (e.g., flow-run)
- job_configuration.task_run_request
- launchType: EC2
- cluster: your ECS cluster name or ARN
- overrides.taskRoleArn: arnawsiam:<acct>role/<flow-run-task-role>
- taskDefinition: either blank (and use family + match_latest_revision_in_family=true) or a specific ARN
- job_configuration.network_configuration
- subnets: ["subnet-...","subnet-..."]
- securityGroups: ["sg-..."]
- assignPublicIp: false (if using private subnets)
- Optional CloudWatch logs:
- configure_cloudwatch_logs: true
- cloudwatch_logs_options: e.g., region, logGroup, streamPrefix
- Optional:
- vpc_id: "vpc-..."
- match_latest_revision_in_family: true
Save and update:
prefect work-pool update ecs-ec2-pool --base-job-template ecs-job-template.json
Docs:
- ECS worker guide
3) Run the Prefect worker as an ECS ServiceMarvin
09/12/2025, 5:59 AMprefecthq/prefect:<your-3.x.y-tag>
- Command:
prefect worker start --pool ecs-ec2-pool --name ecs-ec2-worker
- Env vars:
PREFECT_API_URL=http://<server-internal-lb-or-service-dns>:4200/api
- Task Role: the “worker task role” described above with ecs:RunTask, iam:PassRole, etc.
- Execution Role: standard ECS execution role
- Logs: send to CloudWatch
4) Deploy flows to the ECS work pool
- Prefer the Prefect 3 pattern where the flow is pulled from source. For example:
from prefect import flow
@flow
def my_flow():
print("hello from ECS")
if __name__ == "__main__":
my_flow.from_source(
source="<https://github.com/<owner>/<repo>>",
entrypoint="flows/my_flow.py:my_flow",
).deploy(
name="my-flow",
work_pool_name="ecs-ec2-pool",
# Only include job vars that change per-deployment;
# everything else should be set in the pool template
job_variables={
"image": "<http://123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-runtime:latest|123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/my-runtime:latest>"
},
)
- Make sure your runtime image includes your flow’s Python dependencies and access to any private repos/registries you need.
Important notes specific to your setup
- Database credentials
- The Prefect Server’s DB credentials cannot be stored in Prefect itself — the server needs them at startup. Provide them via ECS task definition environment variables or inject from AWS Secrets Manager.
- Your flows’ DB credentials can be stored in Prefect (Variables/Secrets) and injected into flow-run tasks via the ECS pool template’s env settings.
- Networking
- Ensure flow-run tasks can reach RDS (open SG/Route).
- Ensure the worker service can reach the Prefect Server API endpoint and ECS control plane.
- Environments on one host/cluster
- Use separate work pools per environment (e.g., ecs-ec2-dev, ecs-ec2-stage, ecs-ec2-prod) and separate RDS DBs or schemas.
- Optionally, create separate ECS services for workers per environment. You can also scope different subnets/SGs if needed.
Questions to confirm before I draft exact JSON/task definitions:
1) Will the Prefect Server UI/API be public behind an ALB (TLS), or private only inside the VPC?
2) Do you already have an ECR runtime image for your flows, or should I help you create one?
3) Do you want one ECS worker service per environment (recommended) or a single worker that polls multiple pools?
Happy to turn this into concrete ECS task/service definitions once you confirm the above.