Florent VanDeMoortele
12/23/2025, 5:32 PMMarvin
12/23/2025, 5:33 PMMarvin
12/23/2025, 5:39 PMprefect worker start as a system service on an always-on instance.
- Docker worker on a GCE VM: 2–10s when the image is already pulled.
- Kubernetes worker (GKE): 10–30s to schedule a pod and start the container.
References
- Prefect GCP Cloud Run worker (v1): CloudRunWorker code
- Prefect GCP Cloud Run worker (v2): CloudRunWorkerV2 code
- GCP docs: Cloud Run Jobs overview: Cloud Run Jobs
If you share:
- How often your flows run (e.g., every minute vs hourly)
- Your acceptable startup latency target
- Whether you prefer fully serverless vs managing a tiny VM
…I can recommend the best worker type and outline the setup.Florent VanDeMoortele
12/23/2025, 5:41 PMMarvin
12/23/2025, 5:41 PMMarvin
12/23/2025, 5:48 PMgcloud auth configure-docker <region>-docker.pkg.dev)
- Pre-pull your flow image and keep it cached locally
- Use a Docker work pool; start a worker on the VM; deploy your flow to that pool with image_pull_policy set to if_not_present or never
Step-by-step
1) Create a Docker work pool (once)
prefect work-pool create "gce-docker" --type docker
2) Optionally set the pool’s base job template to avoid pulls on every run
- Fetch the template:
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
- Edit docker-pool.json and set:
- "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG"
- "image_pull_policy": "if_not_present" (or "never" if you’ll always pre-pull)
- Apply:
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
3) On the VM, install requirements and pre-pull the image
pip install "prefect[docker]"
gcloud auth configure-docker REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
4) Start a Prefect worker on the VM (as a service)
- Minimal start:
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
export PREFECT_API_KEY="<YOUR_API_KEY>"
prefect worker start -p "gce-docker" -n "gce-docker-1"
- Optional systemd unit:
[Unit]
Description=Prefect Docker Worker
After=docker.service
Requires=docker.service
[Service]
Environment=PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>
Environment=PREFECT_API_KEY=<YOUR_API_KEY>
ExecStart=/usr/local/bin/prefect worker start -p gce-docker -n gce-docker-1
Restart=always
[Install]
WantedBy=multi-user.target
5) Deploy your flow to this pool using your existing image
- If your image already contains the flow code at the right path:
from prefect import Flow
flow = Flow.from_source(
source=".", # entrypoint path must exist inside the image
entrypoint="app/flow.py:main_flow",
)
flow.deploy(
name="prod",
work_pool_name="gce-docker",
image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
build=False, # image already built
push=False, # image already pushed
)
Tips to reliably hit <10s
- Keep the image small and pre-pulled on the VM
- Set image_pull_policy to if_not_present (or never if you manage pulls yourself)
- Avoid runtime git clone or pip install in the container’s entrypoint
- Keep VM and Artifact Registry in the same region
- Use a fixed tag or digest to avoid unexpected pulls
Alternative if you don’t need containers
- Process worker on a GCE VM is the fastest (<1s), but only if you can install your code and deps on the VM directly (no Docker). For your current containerized setup, Docker worker is the best fit.
If you want, I can tailor a systemd unit + Terraform snippet for the VM (with a MIG) and a minimal Dockerfile to keep launch times in the 2–5s range.Florent VanDeMoortele
12/24/2025, 9:00 AM- Keep everything regional:
- Store the image in Artifact Registry in the same region as the job
- Ensure the job’s service account has Artifact Registry Reader to avoid auth retries
- Avoid optional features that add provisioning time unless needed (VPC connectors, large memory, etc.)
Marvin
12/24/2025, 9:00 AMMarvin
12/24/2025, 9:02 AMgcloud artifacts repositories list --location=REGION
- Create a regional repo (if needed):
gcloud artifacts repositories create REPO \
--repository-format=docker \
--location=REGION \
--description="Prefect images"
- Tag and push your image to the regional registry:
docker tag IMAGE:TAG REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
docker push REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
Docs: Artifact Registry: Store Docker images
b) Configure your Prefect Cloud Run v2 work pool to use that same region and image
- Create or update a Cloud Run v2 work pool:
prefect work-pool create "cr-v2" --type cloud-run-v2
# or update existing
prefect work-pool get-default-base-job-template --type cloud-run-v2 --file cr.json
- Edit cr.json “variables” to set region and image (and keep other settings minimal):
{
"variables": {
"region": "REGION",
"image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
"service_account_name": "<mailto:my-sa@PROJECT.iam.gserviceaccount.com|my-sa@PROJECT.iam.gserviceaccount.com>",
"cpu": "1000m",
"memory": "512Mi",
"vpc_connector_name": null, // leave null/omit unless you need it
"max_retries": 0,
"timeout": 600,
"env": {}
}
}
- Apply the template:
prefect work-pool update "cr-v2" --base-job-template cr.json
Reference: CloudRunWorkerV2 variables and job template
2) Ensure the job’s service account has Artifact Registry Reader
- Create a service account (or pick an existing one) to run the job:
gcloud iam service-accounts create prefect-cr-sa \
--display-name="Prefect Cloud Run Jobs"
- Grant Artifact Registry Reader at the repository level (preferred) or project level:
Repository-level:
gcloud artifacts repositories add-iam-policy-binding REPO \
--location=REGION \
--member="serviceAccount:prefect-cr-sa@PROJECT.iam.gserviceaccount.com" \
--role="roles/artifactregistry.reader"
Project-level (broader):
gcloud projects add-iam-policy-binding PROJECT \
--member="serviceAccount:prefect-cr-sa@PROJECT.iam.gserviceaccount.com" \
--role="roles/artifactregistry.reader"
- Set that service account on the work pool template (as shown above: service_account_name).
Docs:
- Artifact Registry IAM roles
- Cloud Run Jobs overview
- Cloud Run service identity
3) Avoid optional features that add provisioning time
- VPC connector: only set vpc_connector_name if you must reach private resources. Leaving it null removes the block and speeds up provisioning.
Docs: Cloud Run VPC connectors
- Memory/CPU: keep to the minimum your flow needs (e.g., memory “512Mi”, cpu “1000m”). Larger resources can slow scheduling/startup.
- Extras: don’t set Cloud SQL integrations or other add-ons unless required. In the default Cloud Run v2 template, keep cloudsql_instances empty.
Important note on startup time
These changes reduce cold-start overhead, but Cloud Run Jobs can still take >10s depending on GCP scheduling and image pull. If <10s is a hard requirement, the fastest reliable path is a Docker worker on an always-on GCE VM with your image pre-pulled. I’m happy to share a ready-to-use systemd unit and minimal VM setup for that if you want.
If you share your target region and repo/image names, I can draft a complete cr.json template for your work pool.Florent VanDeMoortele
12/24/2025, 9:44 AMMarvin
12/24/2025, 9:44 AMMarvin
12/24/2025, 9:46 AMprefect work-pool create "gce-docker" --type docker
2) Configure the pool’s base job template (so we don’t pull on every run)
- Dump the default template:
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
- Edit docker-pool.json:
- Set "image" to your Artifact Registry image (with a pinned tag or digest)
- Set "image_pull_policy" to "IfNotPresent" (or "Never" if you’ll always pre-pull)
Example snippet:
{
"variables": {
"image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3",
"image_pull_policy": "IfNotPresent",
"env": {}
}
}
- Apply:
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
3) Provision a small GCE VM in the same region as your Artifact Registry
- e2-small/e2-medium is usually enough. Install Docker and Prefect.
- Authenticate Docker to AR and pre-pull your image:
gcloud auth configure-docker REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3
4) Start the Prefect worker on the VM
- Set Cloud API auth:
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
export PREFECT_API_KEY="<YOUR_API_KEY>"
- Start worker:
prefect worker start -p "gce-docker" -n "gce-docker-1"
- Optional: run it under systemd so it auto-restarts.
5) Deploy your flow using your prebuilt image (no builds)
- In code:
from prefect import flow
@flow
def my_flow():
...
if __name__ == "__main__":
my_flow.deploy(
name="prod",
work_pool_name="gce-docker",
image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:1.2.3",
build=False,
push=False,
job_variables={
"image_pull_policy": "IfNotPresent"
}
)
Notes:
- Using a pinned tag or digest avoids unexpected pulls.
- If you set "image_pull_policy": "Never", ensure the image is always pre-pulled during VM boot/update.
Option B (fastest absolute, no containers): Process worker on GCE VM
- Expected startup: ~1s.
- Tradeoff: you install your code and dependencies directly on the VM; no Docker isolation.
- Steps are similar: create a process work pool, install your app on the VM, start a process worker, and deploy without specifying an image.
Optional hardening and ops tips
- Put the worker on a Managed Instance Group and use a startup script that:
- Installs Docker + Prefect
- Runs gcloud auth configure-docker
- Pulls the image
- Starts the worker (systemd)
- Roll out image updates by pushing a new tag/digest and pre-pulling on the VMs before switching deployments.
- Keep the VM and Artifact Registry in the same region to minimize pull time (even if you rarely pull).
If you share:
- Your region
- The exact AR image path
- Preference for Docker vs Process worker
…I can give you a copy-paste systemd unit, a GCE startup script, and a minimal Terraform example to stand this up with image pre-pull and automatic worker start.Florent VanDeMoortele
12/24/2025, 9:48 AMMarvin
12/24/2025, 9:48 AMMarvin
12/24/2025, 9:48 AMprefect work-pool create "gce-docker" --type docker
- Configure the pool’s template to use your image and avoid pulls:
prefect work-pool get-default-base-job-template --type docker --file docker-pool.json
Edit:
- "image": "REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG"
- "image_pull_policy": "IfNotPresent" (or "Never" if you always pre-pull)
Apply:
prefect work-pool update "gce-docker" --base-job-template docker-pool.json
- On a small GCE VM in the same region as AR:
- gcloud auth configure-docker REGION-docker.pkg.dev
- docker pull REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG
- Start the worker:
export PREFECT_API_URL="<https://api.prefect.cloud/api/accounts/<ACCOUNT_ID>/workspaces/<WORKSPACE_ID>>"
export PREFECT_API_KEY="<YOUR_API_KEY>"
prefect worker start -p "gce-docker" -n "gce-docker-1"
- Deploy with your prebuilt image and no build:
flow.deploy(
name="prod",
work_pool_name="gce-docker",
image="REGION-docker.pkg.dev/PROJECT/REPO/IMAGE:TAG",
build=False,
push=False,
job_variables={"image_pull_policy": "IfNotPresent"}
)
Cheapest (if you can drop containers)
- Why: No Docker overhead; run on a tiny preemptible VM (60–70% cheaper). Startup ~1s.
- How:
- Package your code as a normal Python app on the VM (venv/uv/pip).
- Create a Process work pool:
prefect work-pool create "gce-process" --type process
- Start a worker:
export PREFECT_API_URL=...
export PREFECT_API_KEY=...
prefect worker start -p "gce-process" -n "gce-process-1"
- Deploy without an image:
flow.deploy(name="prod", work_pool_name="gce-process", build=False)
- Cost tips: use e2-micro/e2-small or t2a-standard-1 (ARM) if your stack supports ARM; consider preemptible (spot) to cut cost further. Keep VM and data in the same region.
If containers are required and you want “cheapest”
- Use the Docker worker on a preemptible e2-micro/e2-small (or ARM t2a) VM.
- Pre-pull the image; set image_pull_policy to IfNotPresent/Never.
Want me to drop in a ready-to-use systemd unit and a GCE startup script for either option? If you share your region and image path, I’ll tailor them.Bring your towel and join one of the fastest growing data communities. Welcome to our second-generation open source orchestration platform, a completely rethought approach to dataflow automation.
Powered by