Eddie Atkinson
08/25/2021, 10:01 AMECSRun
is doing under the hood to run tasks? I have set a subnet for the service I am running my Prefect tasks in and have disabled public IPs, but when I call ECSRun
my tasks are running with a public IP address in a different subnet.
From reading the documentation for ecs.run_task
it seems as though you are required to specify a subnet ID if you are running a task on Fargate, which I am. Therefore, I’m wondering what subnet ID Prefect is using and whether it can forced to use the default subnet ID of the service. I am aware that you can override the arguments passed to run_task
by ECSRun
, however I don’t want to do this as I want to make my config agnostic to the account that it is being deployed in (I am deploying the same infra to different AWS accounts and don’t want to hard code the subnet ID which is passed to ECSRun
)Kevin Kho
ECSRun
but if you don’t like that approach, this information can also be passed on the agent side. It is not directly exposed as a flag by Prefect so you’d need to include it in the Task Definition.Eddie Atkinson
08/26/2021, 12:24 AMbut if you don’t like that approach, this information can also be passed on the agent sideHi @Kevin Kho, do you have any examples of this? I assume I have to subclass
Agent
and override its deploy_flows
method right?Kevin Kho
Eddie Atkinson
08/26/2021, 12:51 AMtask_definition
? Looking through AWS’ documentation I can’t see a spot where it’s specifiedKevin Kho
awsvpc
by supplying a NetworkConfiguration
Kevin Kho
Eddie Atkinson
08/26/2021, 2:03 AMnetworkMode
section:
If the network mode isTo me this implies that the, the task is allocated an elastic network interface, and you must specify aawsvpc
when you create a service or run a task with the task definition.NetworkConfiguration
networkConfiguration
must be supplied at the level of the service, or in the call to run_task
. I’m just waiting on a Docker image to push to get screenshots, but I have specified the subnets and security groups on the service, but these seem to be overridden when run_task
is called by my prefect ECS agent.Eddie Atkinson
08/26/2021, 2:05 AMrun-task-kwargs
CLI arg to ecs start to override the networkConfiguration
passed to every call to run_task
by the ECS agent starting my flowsKevin Kho
run-task-kwargs
on the agent is a good solution if it works yep. Would like to see screenshots if you get the chance just for my understanding.Eddie Atkinson
08/26/2021, 4:36 AMEddie Atkinson
08/26/2021, 4:38 AMEddie Atkinson
08/26/2021, 4:39 AMECSRun
is doing its own thing hereKevin Kho
Eddie Atkinson
08/26/2021, 4:48 AMtasks:
prefect-task:
name: prefect-task
image: ${env:PREFECT_DOCKER_IMAGE}
desired: 0
cpu: 1024 # 1vcpu
memory: 2048 # 2Gb
override:
role: ${self:custom.ecsBaseTaskRoleName}
container:
Name: flow
# container must be called 'flow' for prefect to run tasks
# when using ECSRun: <https://docs.prefect.io/api/latest/run_configs.html#ecsrun>
# non-obvious, but changing to use the AWS Log driver
# and an awslogs-stream-prefix significantly affects data included
# <https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html>
LogConfiguration:
LogDriver: "awslogs"
Options:
awslogs-group: ${self:custom.ecsClusterLogGroupName}
awslogs-region: ${self:custom.region}
awslogs-stream-prefix: ${self:custom.ecsTaskLogPrefix}
prefect-task-server:
name: ${self:custom.ecsTaskName}-prefect-task-server
image: "prefecthq/prefect:latest"
desired: 1
cpu: 256 # 0.25vcpu
memory: 512 # 512mb
environment:
EXEC_ROLE_ARN: ${self:custom.ecsBaseExecRoleArn}
TASK_ROLE_ARN: ${self:custom.ecsBaseTaskRoleArn}
LOG_LEVEL: INFO
LABEL: feeds-jobs
CLUSTER_ARN: ${self:custom.ecsClusterArn}
AGENT_NAME: feeds-task-server
AGENT_API_KEY: ${self:custom.prefectApiKey.prefect-api-key}
override:
role: ${self:custom.ecsBaseTaskRoleName}
container:
command:
- "sh"
- "-c"
- "prefect agent ecs start --key $AGENT_API_KEY --execution-role-arn $EXEC_ROLE_ARN --task-role-arn $TASK_ROLE_ARN --log-level $LOG_LEVEL --label $LABEL --cluster $CLUSTER_ARN --name $AGENT_NAME"
# non-obvious, but changing to use the AWS Log driver
# and an awslogs-stream-prefix significantly affects data included
# <https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_awslogs.html>
LogConfiguration:
LogDriver: "awslogs"
Options:
awslogs-group: ${self:custom.ecsClusterLogGroupName}
awslogs-region: ${self:custom.region}
awslogs-stream-prefix: ${self:custom.ecsTaskLogPrefix}
What you see in the screenshot is the service for the prefect-task
definition above. My agent runs in the prefect-task-server
serviceKevin Kho
Eddie Atkinson
08/26/2021, 4:53 AMKevin Kho
Eddie Atkinson
08/26/2021, 4:57 AMKevin Kho
Eddie Atkinson
08/26/2021, 4:58 AMKevin Kho
Kevin Kho
ECS Service
that you provisioned is indeed a Prefect agent
. The Service is responsible for picking up the Prefect flow
and then starting the ECS Task
.
There are two ways to set the task definition stuff. The first is through ECSRun
(which we don’t want to do). The second is through the Prefect agent
, which is the ECS Service
you provisioned.
In order to provision this on the Prefect agent
, you need to do something like
prefect agent ecs start --task-definition /path/to/my_definition.yaml
or
prefect agent ecs start --run-task-kwargs /path/to/options.yaml
the point is that these are loaded in upon agent start. You can find that code snippet here. It loads in these configurations, and then when the flow starts, the RunConfig
items override what was in these `yaml`files, and then it kicks of the Prefect flow
as an ECS task
.
So when that ECS Service
is created for the Prefect agent
, it already has a fixed configuration that can only be overriden by the ECSRun
.
Now, you mentioned that you attached some network information to the ECS Service (Prefect agent)
, but looking at the command in your yaml,
- "prefect agent ecs start --key $AGENT_API_KEY --execution-role-arn $EXEC_ROLE_ARN --task-role-arn $TASK_ROLE_ARN --log-level $LOG_LEVEL --label $LABEL --cluster $CLUSTER_ARN --name $AGENT_NAME"
I am not seeing anything beyond the cluster arn. This needs either a task definition
or run_task_kwargs
that will hold the networkConfiguration
. One it’s attached here, it would apply to all of the Flows that it picks up unless overridden by the ECSRun
So what is happening is that your ECS Service
is starting in some subnet, but that’s not necessarily the same subnet your ECS Task/Prefect Flow
will be unless explicitly specified. I believe there are just some default subnets (maybe 3), and unless specified, it would use one of the defaults. There is nothing tying the ECS Service
subnet to the ECS Task
because the Prefect Agent
is simply a process that is starting the Prefect Flow/ECS Task
without knowing anything about where it is running. For example, if you started an ecs agent
on your local machine and deployed a Prefect Flow
, it would just grab a default subnet. The same thing is going on here.
So if the networkConfiguration
is not specified for the agent, Prefect can infer it. Unfortunately, the inferring of networkConfiguration
happens during agent startup here , which means that it infers something and then will pass that to all flows that it starts. In short, the agent is already locked to one networkConfiguration
by the time the flows come in.
That might be fine for you. It just means that you need to spin up different agents, each with their own configuration, so that you don’t need to specify this in the ECSRun
. I think this is what you were going for, so yes it can be one with multiple Prefect agents
, but they would have to be separate ECS Services
because the ECS Service
only holds one task definition
at a time I think. Each one of these would be configured with different networkConfiguration
, and then that would dictate where the Flows run.
In order to send the right Flow to the right agent, you would need to specify labels to pair them together.Eddie Atkinson
08/27/2021, 1:15 AMrun_task_kwargs
yaml override file at runtime when the container starts.
import os
import yaml
ENV_VAR_NAMES = [
"SECURITY_GROUP_ID",
"SUBNET_ID",
]
OVERRIDE_FILE_NAME = "run_task_overrides.yml"
env_var_values = {k: os.environ[k] for k in ENV_VAR_NAMES}
run_task_overrides = {
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "DISABLED",
"securityGroups": [env_var_values["SECURITY_GROUP_ID"]],
"subnets": [env_var_values["SUBNET_ID"]],
}
}
}
with open(OVERRIDE_FILE_NAME, "w") as outfile:
outfile.write(yaml.dump(run_task_overrides))
os.system(
f"prefect agent ecs start --key $AGENT_API_KEY --execution-role-arn $EXEC_ROLE_ARN --task-role-arn $TASK_ROLE_ARN --log-level $LOG_LEVEL --label $LABEL --cluster $CLUSTER_ARN --name $AGENT_NAME --run-task-kwargs {OVERRIDE_FILE_NAME}"
)
Kevin Kho
start
method. Maybe a bit nicer to work with.Eddie Atkinson
08/27/2021, 1:26 AMauth.toml
instead?Kevin Kho
PREFECT__CLOUD__API_KEY
using the env_vars
. None of the agents seem to accept the key in the constructionKevin Kho
Eddie Atkinson
08/27/2021, 1:37 AM