<@ULVA73B9P> I work with Prefect 3 on Prefect Clou...
# ask-marvin
f
@Marvin I work with Prefect 3 on Prefect Cloud, with GCP and Github. My project needs a specific environment defined in poetry.lock file with Poetry. What's the best way to deploy my flow and to ensure that my run have the corrects dependencies?
m
thought for 364.3 seconds
Great question — and nice stack. Since you’re on Prefect 3.x with code in GitHub and running on GCP, here’s a practical hierarchy for ensuring your runs use the exact Poetry-locked environment. Recommended approaches (from most reproducible/fast to simplest) 1) Bake dependencies into a container image (Poetry → requirements.txt) - Best for: production, large deps (numpy/pandas), Cloud Run/GKE, faster runs, reproducibility. - Flow: - Export your Poetry lock to a pinned requirements.txt in CI. - Build a Docker image with those deps. - Push to Artifact Registry and point your deployment at that image. Example CI step (runs on every change to poetry.lock):
Copy code
poetry export -f requirements.txt --output requirements.txt --without-hashes
prefect.yaml using Prefect’s docker build/push steps (targets Artifact Registry):
Copy code
name: my-project

build:
  - prefect_docker.deployments.steps.build_docker_image:
      id: build-image
      requires: "prefect-docker>=0.4.0"
      image_name: "us-docker.pkg.dev/<gcp-project>/<repo>/<image>"
      tag: "{{ get-commit-hash.stdout }}"
      dockerfile: auto  # Prefect autogenerates a Dockerfile that installs requirements.txt if present

push:
  - prefect_docker.deployments.steps.push_docker_image:
      requires: "prefect-docker>=0.4.0"
      image_name: "{{ build-image.image_name }}"
      tag: "{{ build-image.tag }}"

deployments:
  - name: my-flow
    entrypoint: flows/my_flow.py:my_flow
    work_pool:
      # For Cloud Run push pool, set this to your cloud-run pool name
      # For GKE, set this to your kubernetes pool name
      name: cloud-run-or-k8s-pool
      job_variables:
        image: "{{ build-image.image }}"
        # for Cloud Run, set region/service account in the work pool config (UI) or job variables
- On Cloud Run: use a Cloud Run work pool (push). No worker needed; Prefect starts jobs for you. Set region/service account on the pool. - On GKE: use a Kubernetes work pool and run a worker (Helm chart). Jobs will run with your baked image. Docs: - Deployments overview - Docker deployments - Kubernetes deployments - Serverless (Cloud Run/ECS/ACI) 2) Deploy from GitHub and install deps at runtime (Poetry → requirements.txt) - Best for: quick start or small deps. No image build. - Flow: - Keep your code in GitHub. - Export Poetry to requirements.txt in CI as above and commit it. - Deploy with from_source(). The worker/serverless runtime will clone your repo and install requirements.txt before the run. Example:
Copy code
from prefect import flow

if __name__ == "__main__":
    flow.from_source(
        source="<https://github.com/<org>/<repo>.git>",
        entrypoint="flows/my_flow.py:my_flow",
    ).deploy(
        name="my-flow",
        work_pool_name="my-cloud-run-or-k8s-pool",
    )
Useful built-in steps: -
prefect.deployments.steps.pull.git_clone
-
prefect.deployments.steps.utility.pip_install_requirements
You can also wire these into prefect.yaml if you prefer the CLI path. 3) Small runtime tweaks with EXTRA_PIP_PACKAGES - Best for: a couple of light packages or hotfixes without rebuilding an image. - How it works: If you use a Prefect base image (and don’t override the entrypoint), containers install whatever you set in
EXTRA_PIP_PACKAGES
before the flow executes (uses uv pip install). - Set it per-deployment via job variables:
Copy code
my_flow.deploy(
    name="my-flow",
    work_pool_name="my-k8s-or-docker-pool",
    job_variables={
        "env": {
            "EXTRA_PIP_PACKAGES": "pandas==2.2.2 requests==2.32.3"
        }
    }
)
Notes: - This runs on every task container start — great for small additions, not heavy stacks.
- Documented in the Docker/Kubernetes how-tos: Docker and Kubernetes. Poetry-specific guidance - Most reliable: export Poetry to requirements.txt and install with uv/pip (either at image build time or runtime). - If you truly want Poetry inside the image, use a custom Dockerfile and disable Poetry’s venv:
Copy code
FROM prefecthq/prefect:3-latest
  RUN uv pip install poetry
  WORKDIR /app
  COPY pyproject.toml poetry.lock ./
  RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi --no-root
  COPY . /opt/prefect/flows/
  WORKDIR /opt/prefect/flows
This is slower to build than the export-to-requirements approach but works if you need Poetry semantics. What I recommend for your setup (GCP + GitHub + Poetry) - Production: Build and push a container per commit with dependencies baked from poetry.lock (via requirements.txt export). Use: - Cloud Run work pool (push) for serverless, or - Kubernetes work pool + worker on GKE. - Development/prototyping: Deploy from GitHub with requirements.txt and let the runtime install. - Use EXTRA_PIP_PACKAGES only for small, temporary adds. A couple of best practices - Align Python versions: choose a Prefect image like
prefecthq/prefect:3-python3.11
to match your project. - Keep
pyproject.toml
,
poetry.lock
, and
requirements.txt
in sync (CI regenerates requirements.txt on lock updates). - For private indexes, set pip/uv env vars or use a ~/.pip/pip.conf in the image. If you can share: - Are you targeting Cloud Run or GKE? - Do you prefer no-worker (Cloud Run push) or running a worker on GKE? - Any large/compiled deps (numpy/pandas/arrow) or GPUs? I can tailor an exact example (prefect.yaml + GitHub Actions + work pool config) for your path.