Tinh
09/26/2025, 7:28 AMflows
, few of them run as python script, few are containers (docker)
. The docker I run with local image.
But this causes issue when I deploy the flow flow.serve()
is there any way to deploy the flow with local images? or better to pull them from dockerhub. My docker images are model specific and few are 2-3Gb, thus I don't push them to remote docker hub.
What would be best-practice now for the deploymentMarvin
09/26/2025, 7:28 AMMarvin
09/26/2025, 7:43 AMflow.serve()
by itself won’t magically run your flow in a container — you need to bind the flow to Docker infra or use flow.deploy(...)
with a Docker pool.
- For local images, the image must exist on the machine(s) where your Docker worker(s) run. If the worker is remote, either preload the image there or use a private/nearby registry.
- Use the Docker worker’s job variables to set image
and image_pull_policy
to control pulling behavior.
Recommended setup
1) Create a Docker work pool and start a worker on the host that has your large images:
prefect work-pool create my-docker-pool --type docker
prefect worker start --pool my-docker-pool
- Install extras if needed: pip install "prefect[docker]"
2) Build/load your large image(s) on that host and give them a specific tag (e.g. my-local/model-a:2025-09
).
3) Deploy your flow to the Docker pool, pointing at the local image and disabling build/push:
python
from prefect import flow
@flow
def my_flow():
...
my_flow.deploy(
name="model-a",
work_pool_name="my-docker-pool",
# We’re not asking Prefect to build/push anything
build=False,
push=False,
# Tell the Docker worker to use the preloaded image and not re-pull it
job_variables={
"image": "my-local/model-a:2025-09",
"image_pull_policy": "IfNotPresent", # or "Never" to never attempt a pull
# optional: volumes/env/memory/etc
# "volumes": ["/models/model-a:/models:ro"],
# "mem_limit": "12g",
},
)
If you prefer to keep using serve()
You can bind your flow to the Docker work pool first, then call `serve()`:
python
from prefect import flow
from prefect.flows import bind_flow_to_infrastructure
from prefect_docker.worker import DockerWorker
@flow
def my_flow():
...
bound = bind_flow_to_infrastructure(
my_flow,
work_pool="my-docker-pool",
worker_cls=DockerWorker,
job_variables={
"image": "my-local/model-a:2025-09",
"image_pull_policy": "Never",
},
)
bound.serve(name="model-a")
This creates a deployment that targets your Docker pool, while still using serve()
to register and watch it.
When local images won’t work
- If your Docker worker runs on a different machine from where you built the image, it won’t see your local image. Options:
- Preload the image on each worker host (e.g., distribute tarballs and docker load
), and set image_pull_policy: Never/IfNotPresent
.
- Run a private/nearby registry and configure credentials via a DockerRegistryCredentials block in job variables (registry_credentials
) for fast pulls.
- You can retrieve the default Docker job template to see all supported fields:
prefect work-pool get-default-base-job-template --type docker
Best practices for large (2–3GB) model images
- Prefer preloading or a private registry close to workers over Docker Hub to avoid slow/expensive pulls.
- Keep the image slim: put large model artifacts on a shared volume and mount them at runtime instead of baking into the image:
- job_variables["volumes"] = ["/mnt/models/model-a:/models:ro"]
- Pin image tags per model/version and use image_pull_policy: IfNotPresent
to use host cache.
- Use one “family” base image for multiple flows to benefit from shared layers.
Docs
- Docker work pool and deployment configuration: Docker work pools with PrefectMarvin
09/26/2025, 7:43 AMflow.serve()
with your local images? If you paste it here, I can pinpoint the fix.