<@ULVA73B9P> what command can i use in job_variabl...
# ask-marvin
e
@Marvin what command can i use in job_variable of a .deploy() for a k8s self hosted setup?
m
thought for 199.5 seconds
Assuming Prefect 3.x: you generally don’t need to set a command at all—the Kubernetes worker injects the right args to run your flow. The default is: - prefect flow-run execute If you do want to set it explicitly in your deployment’s
job_variables
, use the
command
key (it maps to the container args):
Copy code
flow.deploy(
  name="my-deployment",
  work_pool_name="my-k8s-pool",
  job_variables={
    "command": "prefect flow-run execute"
  }
)
Notes: - Leave it unset unless you have a special wrapper/entrypoint; the default is correct for standard runs. - Make sure your image has Prefect installed so the
prefect
CLI is available. References: - Default command in worker base: base.py - Kubernetes worker variables (what
job_variables
you can set): prefect_kubernetes.worker.KubernetesWorkerVariables - How to run flows on Kubernetes: Docs: Kubernetes
e
@Marvin will the logs of the pods be visible on the UI ?
m
thought for 102.0 seconds
Short answer: Yes—your flow’s logs will appear in the Prefect UI, but raw pod stdout/stderr won’t unless you route it through Prefect’s logger. Details: - Logs emitted via Prefect’s logging (e.g.,
get_run_logger().info(...)
) are sent from the pod to the Prefect API and show up in the UI automatically. - The
stream_output
job variable in the Kubernetes worker only mirrors pod stdout/stderr to the worker’s local terminal; it does not affect what the UI shows. - Anything printed directly to stdout/stderr or produced by unrelated subprocesses isn’t automatically captured in the UI. To surface it, capture that output and send it via Prefect’s logger. Good refs: - Kubernetes worker variables (incl.
stream_output
): KubernetesWorkerVariables - Prefect API log handler (how logs reach the UI): APILogHandler If you want help adapting non-Prefect output to appear in the UI, share a snippet of how you’re running those commands and I’ll show you a pattern to capture and log them.
e
ok
@Marvin i'm using a <flow>.from_source(source=GitRepository(...)...).deploy(...) but i'm not sure my code is run, nothing is display in the logs
m
thought for 281.6 seconds
Got it — let’s troubleshoot why nothing shows up in the logs when deploying with
flow.from_source(...).deploy(...)
on Kubernetes. A few quick questions to pinpoint the issue: - What state do your flow runs show in the UI (Scheduled, Late, Pending, Running)? - Do you have a Kubernetes worker running and polling the same work pool you deployed to? - Which container image are you using in
job_variables["image"]
? - Is your repo private? If so, how are you passing credentials to
GitRepository(...)
? - Did you override
job_variables["command"]
? If yes, please remove it. Most common causes and fixes: 1) No worker is picking up runs - Ensure a worker is running and attached to the correct work pool. - Check:
prefect work-pool inspect "<your-pool>"
- Start a worker (ensure kubernetes integration is installed):
Copy code
uv run --with 'prefect[kubernetes]' prefect worker start -p "<your-pool>"
Docs: Run flows on Kubernetes 2) Image doesn’t have Prefect (or git) - The pod needs to run
prefect flow-run execute
and clone your repo at runtime. Your image must include: - Prefect 3.x - git CLI (required for GitRepository) - Your Python dependencies - If unsure, build a custom image, e.g.:
Copy code
FROM prefecthq/prefect:3-python3.11
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
  # pip install your deps here
- Then set it in
job_variables["image"]
. 3) Incorrectly overriding the container command - Don’t set
job_variables["command"]
unless you have a very specific reason. The default is correct. - If you set it to something else (like
python my_script.py
), Prefect won’t run the flow engine and you’ll see no Prefect logs. - Remove the override to let the worker use the default command:
prefect flow-run execute
. 4) Private repo credentials not available at runtime - If your repo is private, the runtime pod must be able to clone it. Prefer a
Secret
block for tokens:
Copy code
from prefect.runner.storage import GitRepository
  from prefect.blocks.system import Secret

  repo = GitRepository(
    url="<https://github.com/org/repo.git>",
    credentials={"access_token": Secret.load("my-github-token")},
    branch="main",
  )
- Make sure you used a block (or a supported credentials dict) so the worker can resolve it at runtime. - Guide: Store flow code from Git 5) Network/API connectivity from the pod - The pod needs to reach both your Git host and your Prefect API (
PREFECT_API_URL
). - If you’re self-hosting, confirm the cluster can reach your API URL and that
PREFECT_API_KEY
is set by the worker. Quick verification checklist: - In UI → Work Pools, confirm your pool shows an active worker. - In UI → Flow Runs, check the state. If it’s stuck in Scheduled/Late, the worker isn’t submitting a job. - Check worker logs for submission errors (image pull, RBAC, etc.). - If a pod is created, check its logs/events:
Copy code
kubectl -n <ns> get pods
  kubectl -n <ns> describe pod <pod-name>
  kubectl -n <ns> logs <pod-name>
If you can share: - The deployment snippet (source/entrypoint, job_variables, image) - The flow run state - Whether the worker is running and any worker logs …I can pinpoint the exact fix fast. Helpful refs: - Kubernetes how-to: Run flows on Kubernetes - Deploy via Python: Deploy via Python - Store flow code (GitRepository): Store flow code from Git
e
@Marvin state: crashed a jobs appear but are terminated with Error Reason image: prefecthq/prefect:3.6.5-python3.11 git private repo, credentials where provided as well as entrypoint (gitrepository function) no command set
m
thought for 46.3 seconds
Thanks — that context helps. Given: - Flow run state: crashed - Pod shows Reason: Error - Image:
prefecthq/prefect:3.6.5-python3.11
- Using
flow.from_source(GitRepository(...), entrypoint=...)
- Private repo, credentials provided - No custom
command
Most common root cause here: the container does not have git installed, so the runtime clone of your repo fails immediately and the pod exits before Prefect can emit logs to the API. The official Prefect images do not include git by default. What to do: 1) Build an image with git (and your flow’s dependencies) - Example Dockerfile:
Copy code
FROM prefecthq/prefect:3.6.5-python3.11
  RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
  # Optional: pip install your Python deps here
  # RUN pip install -r requirements.txt
- Push this image to your registry and update your deployment to use it:
Copy code
flow.from_source(
    source=GitRepository(...),
    entrypoint="path/to/flow.py:my_flow",
  ).deploy(
    name="my-deployment",
    work_pool_name="my-k8s-pool",
    job_variables={
      "image": "your-registry/prefect-with-git:latest",
      "namespace": "<your-ns>",
      # optional: service_account_name, etc.
    },
  )
- Quick local check:
Copy code
docker run --rm your-registry/prefect-with-git:latest git --version
2) Verify the pod’s failure reason - This will confirm the diagnosis quickly:
Copy code
kubectl -n <ns> describe pod <pod-name>
  kubectl -n <ns> logs <pod-name>
If you see messages like “git: not found” or a clone/auth error, that’s the issue. 3) Double-check repo access at runtime - For private repos, your credentials need to be resolvable in the pod:
Copy code
from prefect.runner.storage import GitRepository
  from prefect.blocks.system import Secret

  repo = GitRepository(
    url="<https://github.com/org/repo.git>",
    credentials={"access_token": Secret.load("my-github-token")},
    branch="main",
  )
- Using a
Secret
block ensures credentials are injected safely at runtime. 4) Ensure the entrypoint path is correct - Must be relative to the repo root:
Copy code
"some/dir/flows.py:my_flow"
A wrong path/function name will crash after clone; pod logs will show a Python error. 5) Sanity checks - Worker is running and attached to the same work pool - Cluster can reach your Prefect API URL (if API is not reachable, logs won’t show in UI even if the engine starts; but you’ll still see the pod error in kubectl) If you can paste: -
kubectl -n <ns> logs <pod-name>
(first few lines) - The
entrypoint
you’re using - The
job_variables
snippet …I can confirm if it’s purely the missing git package or something else. Helpful refs: - Run flows on Kubernetes: Docs: Kubernetes - Store flow code from Git (requirements and behavior): Docs: Store flow code from Git - Kubernetes worker variables: KubernetesWorkerVariables
e
local run show that the image does have git
Copy code
$ docker  run -ti prefecthq/prefect:3.6.5-python3.11 git                                                                                                                                                                                                                                                                                  usage: git ...
entrypoint ="flows/b2r.py:b2r"
Copy code
job_variables={
     "namespace": "prefect",
       "env": {
           "PREFECT_LOGGING_LEVEL": "DEBUG",
           "EXTRA_PIP_PACKAGES": "-r requirements.txt",
           "ACCESS_KEY": "{{ prefect.blocks.secret.etl-bucket-access-key}}",
           "SECRET_KEY": "{{ prefect.blocks.secret.etl-bucket-secret-key}}",
        },
 },
logs
Copy code
$ kubectl logs -n prefect opal-mastiff-mdbts-88tzr
+uv pip install -r flows/requirements.txt
error: File not found: `flows/requirements.txt`
the requirements.ttxt is in the <repo>/flows/ @Marvin any idea ?
m
thought for 220.1 seconds
Yep — the error is from
EXTRA_PIP_PACKAGES
running before your repo is cloned. In Prefect’s images, the container entrypoint runs
uv pip install $EXTRA_PIP_PACKAGES
immediately on startup, then later the worker/runner pulls your Git repo and runs the flow. Since your requirements file lives inside the repo (
flows/requirements.txt
), it doesn’t exist yet when the entrypoint tries to install it — hence “File not found.” Refs: - Entry script (shows the install happens first): entrypoint.sh - Using Git as storage: Store flow code from Git Ways to fix it: - Best for prod: bake deps into the image - Dockerfile
Copy code
FROM prefecthq/prefect:3.6.5-python3.11
    # If you want to use a file in the repo, copy it into the image at build time:
    COPY flows/requirements.txt /opt/prefect/requirements.txt
    RUN uv pip install --system -r /opt/prefect/requirements.txt
- Then set
job_variables["image"]
to your custom image and remove
EXTRA_PIP_PACKAGES
. - If you want to keep `EXTRA_PIP_PACKAGES`: pass package names, not a file path
Copy code
job_variables={
    "env": {
      "EXTRA_PIP_PACKAGES": "boto3 pandas s3fs",  # examples
    }
  }
This works because it doesn’t rely on repo files. - Or, still use a requirements file with
EXTRA_PIP_PACKAGES
, but copy it into the image and reference the absolute path you copied to:
Copy code
# Dockerfile
  COPY flows/requirements.txt /opt/prefect/requirements.txt
  # job_variables env
  EXTRA_PIP_PACKAGES="-r /opt/prefect/requirements.txt"
Once you make one of those changes, the container will install deps successfully, then the runner will clone your repo and load `entrypoint="flows/b2r.py:b2r"`; at that point Prefect logs should start appearing as the flow runs. If you share which approach you prefer (custom image vs. package names vs. copying the file into the image), I can provide a minimal working example tailored to your setup.
e
@Marvin can i run pip install after using "steps.pip_install_requirements" but in python not yaml ?
m
thought for 182.9 seconds
Short answer: There isn’t a first-class Python flag to “run `steps.pip_install_requirements`” inside `.deploy()`; the pip-install step is a deployment “pull step” that’s typically defined in
prefect.yaml
and executed in the runtime environment. Your options without YAML: - Bake deps into your image (recommended for K8s). Build a custom image that installs your repo’s requirements and set it in
job_variables["image"]
. - Use
EXTRA_PIP_PACKAGES
for simple cases to install by name (not from a file inside the repo) at container startup. - Manually invoke the step function in Python, but note it runs in your build environment, not in the worker’s runtime:
Copy code
import asyncio
  from prefect.deployments.steps.utility import pip_install_requirements

  asyncio.run(
      pip_install_requirements(
          directory="/path/to/checked-out/repo",
          requirements_file="requirements.txt",
          stream_output=True
      )
  )
Or the generic runner:
Copy code
from prefect.deployments.steps.core import run_step
  asyncio.run(run_step({
      "prefect.deployments.steps.pip_install_requirements": {
          "directory": "/path/to/repo",
          "requirements_file": "requirements.txt"
      }
  }))
This is useful in CI to pre-bake an image or prepare an artifact, but it won’t execute on the Kubernetes pod at flow-run time unless you put it in
prefect.yaml
pull steps. If your goal is “install requirements from the repo at runtime in K8s”: - Use
prefect.yaml
pull steps with
pip_install_requirements
so the pod installs after the repo is cloned, or - Avoid runtime installs and bake deps into the image. References: - Pull steps API: run_step / run_steps - pip_install_requirements: pip_install_requirements - Deploy via Python: Deploy via Python - Store flow code (from_source): Store flow code from Git
e
@Marvin can i use EXTRA_PIP_PACKAGES with private pip repo ?
m
thought for 42.0 seconds
Yes.
EXTRA_PIP_PACKAGES
is just passed to the container entrypoint, which runs: - uv pip install --system $EXTRA_PIP_PACKAGES So you can use it with a private index the same ways you would with pip. Recommended approaches: - Preferred: configure the index via env vars and keep
EXTRA_PIP_PACKAGES
to package names only
Copy code
job_variables={
    "env": {
      "PIP_INDEX_URL": "<https://__token_>_:{{ prefect.blocks.secret.my-pip-token }}@pypi.mycorp.com/simple",
      # or add an additional index:
      # "PIP_EXTRA_INDEX_URL": "<https://pypi.org/simple>",
      # if needed by your index cert:
      # "PIP_TRUSTED_HOST": "<http://pypi.mycorp.com|pypi.mycorp.com>",
      "EXTRA_PIP_PACKAGES": "myprivpkg==1.2.3 anotherpkg>=0.5"
    }
  }
- Store the token in a Secret block and reference it so it isn’t exposed. - These env vars are not echoed by the entrypoint; only the
EXTRA_PIP_PACKAGES
string is printed. - Alternative (works but beware secrets in logs): pass pip flags directly in
EXTRA_PIP_PACKAGES
Copy code
"EXTRA_PIP_PACKAGES": "--index-url <https://__token_>_:TOKEN@pypi.mycorp.com/simple myprivpkg anotherpkg"
The entrypoint echoes the full command, so the token may appear in logs. Not recommended. - Image-based options: - Bake credentials into
/etc/pip.conf
(or mount one via your work pool’s base job template):
Copy code
[global]
    index-url = <https://__token_>_:TOKEN@pypi.mycorp.com/simple
    trusted-host = <http://pypi.mycorp.com|pypi.mycorp.com>
Then
EXTRA_PIP_PACKAGES: "myprivpkg anotherpkg"
works with no secrets in env. - Or pre-install deps in a custom image and skip
EXTRA_PIP_PACKAGES
. Important note from earlier: since
EXTRA_PIP_PACKAGES
runs before your Git repo is cloned, don’t point it at a requirements file inside the repo. If you need a requirements file, copy it into the image and reference an absolute path (e.g.,
-r /opt/prefect/requirements.txt
). Reference: - Entrypoint that runs `uv pip install`: entrypoint.sh If you tell me which private index you’re using (PyPI token, Artifactory, Nexus, GitLab, etc.), I can give you an exact env snippet.