<@ULVA73B9P> how to provide DockerImage with crede...
# ask-marvin
p
@Marvin how to provide DockerImage with credentials to push the image to docker registry while deploying a flow
m
thought for 753.7 seconds
Great question. Assuming Prefect 3.x: the
DockerImage
packager itself does not accept registry credentials. Pushing to a private registry relies on the Docker daemon’s auth (i.e., you must be logged in) or you can use the
prefect_docker
deployment steps with explicit credentials. Two supported approaches: 1) Prefect YAML with explicit credentials (best for CI and private registries) - Install extras and register blocks:
Copy code
uv run --with 'prefect[docker]' prefect block register -m prefect_docker
- Option A: Use a DockerRegistryCredentials block
Copy code
# Create the block (run once)
from pydantic import SecretStr
from prefect_docker.credentials import DockerRegistryCredentials

DockerRegistryCredentials(
    username="myuser",
    password=SecretStr("my-token-or-password"),
    registry_url="<http://ghcr.io|ghcr.io>"  # or your registry
).save("ghcr-creds", overwrite=True)
- Reference it in prefect.yaml
Copy code
# prefect.yaml
deployments:
- name: my-deploy
  entrypoint: flows/flow.py:flow
  build:
    - prefect_docker.deployments.steps.build_docker_image:
        image_name: <http://ghcr.io/myorg/myimage|ghcr.io/myorg/myimage>
        tag: "{{ flow_run.id }}"
  push:
    - prefect_docker.deployments.steps.push_docker_image:
        image_name: <http://ghcr.io/myorg/myimage|ghcr.io/myorg/myimage>
        tag: "{{ flow_run.id }}"
        # Provide credentials via a block reference or env vars (see Option B)
        credentials: "{{ blocks.docker_registry_credentials/ghcr-creds }}"
- Option B: Use environment variables (no block needed)
Copy code
push:
  - prefect_docker.deployments.steps.push_docker_image:
      image_name: <http://ghcr.io/myorg/myimage|ghcr.io/myorg/myimage>
      tag: "{{ flow_run.id }}"
      credentials:
        registry_url: "<http://ghcr.io|ghcr.io>"
        username: "{{ env.DOCKER_USERNAME }}"
        password: "{{ env.DOCKER_PASSWORD }}"
Helpful docs: - prefect.yaml deployments - Docker packaging with Prefect 2) Python deploy() with DockerImage (use docker login on the runner) When using
flow.from_source(...).deploy(image=DockerImage(...), build=True, push=True)
, Prefect uses your local Docker daemon. Make sure the environment running deploy is logged into the registry first. Example:
Copy code
from prefect import flow
from prefect.packaging.docker import DockerImage

@flow
def my_flow():
    ...

my_flow.from_source("<https://github.com/myorg/myrepo>", entrypoint="flows/flow.py:my_flow").deploy(
    name="prod",
    work_pool_name="docker-pool",
    image=DockerImage(name="<http://ghcr.io/myorg/myimage|ghcr.io/myorg/myimage>", tag="latest"),
    build=True,
    push=True,
)
- In CI (GitHub Actions):
Copy code
- uses: docker/login-action@v3
  with:
    registry: <http://ghcr.io|ghcr.io>
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}
- run: uv run --with 'prefect[docker]' python deploy.py
- For AWS ECR:
Copy code
aws ecr get-login-password --region $AWS_REGION \
  | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$<http://AWS_REGION.amazonaws.com|AWS_REGION.amazonaws.com>
Key points: -
DockerImage
does not take credentials directly; pushing uses Docker’s auth. - For YAML-based deployments, you can explicitly pass credentials to
prefect_docker.deployments.steps.push_docker_image
. - For Python
.deploy()
, make sure the machine running deploy has already performed
docker login
(or equivalent action) to your registry. If you can share which registry you’re using (Docker Hub, GHCR, ECR, GCR, etc.) and whether you prefer YAML or Python-based deployments, I can tailor the exact snippet for you.
p
@Marvin I would prefer python and i am using docker hub registry
m
thought for 33.6 seconds
Perfect — with Python-based deployments to Docker Hub, Prefect uses your local Docker daemon for build/push. You don’t pass creds into `DockerImage`; instead, authenticate Docker before calling
.deploy()
. Here’s a complete example you can run locally or in CI: - Install extras
Copy code
pip install "prefect[docker]"
- Set env vars (use a Docker Hub access token, not your password)
Copy code
export DOCKERHUB_USERNAME=your-username
export DOCKERHUB_TOKEN=your-token
- deploy.py
Copy code
import os
import subprocess
from prefect import flow
from prefect.packaging.docker import DockerImage

def dockerhub_login():
    username = os.environ["DOCKERHUB_USERNAME"]
    token = os.environ["DOCKERHUB_TOKEN"]
    # Login to the default registry (Docker Hub)
    subprocess.run(
        ["docker", "login", "-u", username, "--password-stdin"],
        input=token.encode(),
        check=True,
    )

@flow
def my_flow():
    print("Hello from Prefect + Docker!")

if __name__ == "__main__":
    dockerhub_login()

    my_flow.from_source(
        "<https://github.com/your-org/your-repo>",
        entrypoint="flows/flow.py:my_flow",
    ).deploy(
        name="prod",
        work_pool_name="docker-pool",  # adjust to your pool
        image=DockerImage(
            name="<http://docker.io/your-username/your-image|docker.io/your-username/your-image>",  # or "your-username/your-image"
            tag="latest",
            # Optional: build arguments, labels, platforms, etc.
            # build-arg=... (pass as keyword args if needed)
        ),
        build=True,
        push=True,
    )
In CI (GitHub Actions) you can rely on the Docker login action instead of the Python login step:
Copy code
- uses: docker/login-action@v3
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}
- run: pip install "prefect[docker]"
- run: python deploy.py
Key points: -
DockerImage
does not accept registry credentials; pushing uses Docker’s auth. - For Docker Hub, logging in with
docker login
(or the login action in CI) before calling
.deploy(build=True, push=True)
is the correct approach. - Use a Docker Hub access token for security. Docs for reference: - Docker image packaging with Prefect - Deploy flows from source If you want, share your repo/image names and I’ll tailor the snippet exactly to your setup.
p
@Marvin i want to add the version of the script in the deplyment tag in the yaml file in python it looks like this from soc import version as soc_version
m
thought for 274.1 seconds
Got it — quick clarifier: do you want this version to appear in your Docker image tag, or in the Prefect deployment’s metadata tags? I’ll show the Docker image tag (most common), and you can also reuse the same value elsewhere. You can’t import Python directly in prefect.yaml, but you can capture it via a step and template the result. Use a run_shell_script step to print the module version, then reference its stdout as the tag for your Docker image. Example prefect.yaml:
Copy code
deployments:
- name: my-deploy
  entrypoint: flows/flow.py:flow
  build:
    - prefect.deployments.steps.run_shell_script:
        id: get_version
        # Print the version without a trailing newline
        script: |
          python - <<'PY'
          import sys
          import soc
          sys.stdout.write(getattr(soc, "__version__", "0.0.0"))
          PY
    - prefect_docker.deployments.steps.build_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ get_version.stdout }}"
  push:
    - prefect_docker.deployments.steps.push_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ get_version.stdout }}"
  # Optional: reuse in job variables (e.g., worker image) or deployment tags
  # tags:
  #   - "soc-{{ get_version.stdout }}"
Notes: - The script uses sys.stdout.write to avoid a trailing newline, which makes for a clean Docker tag. - You can reference the same
{{ get_version.stdout }}
anywhere templating is supported (e.g., additional_tags, job_variables.image, etc.). If you prefer to set the tag in Python (since you mentioned you use
from soc import __version__
):
Copy code
from prefect import flow
from prefect.packaging.docker import DockerImage
import soc

@flow
def my_flow():
    ...

my_flow.from_source(
    "<https://github.com/your-org/your-repo>",
    entrypoint="flows/flow.py:my_flow",
).deploy(
    name="prod",
    work_pool_name="docker-pool",
    image=DockerImage(
        name="<http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>",
        tag=soc.__version__,
    ),
    build=True,
    push=True,
)
Docs for reference: - prefect.yaml templating and steps - Docker image packaging with Prefect If you meant Prefect deployment metadata tags (not Docker tags), say the word and I’ll show that pattern too.
p
@Marvin is there a way to directly load the file and get the value bypassing python
m
thought for 58.3 seconds
Yes. You can read the version directly from a file with a shell step and template its output in prefect.yaml—no Python needed. Here are common patterns: - If version lives in soc/__init__.py as version = "1.2.3" - If version lives in pyproject.toml as version = "1.2.3" - If you maintain a plain version.txt file Example prefect.yaml:
Copy code
deployments:
- name: my-deploy
  entrypoint: flows/flow.py:flow

  build:
    - prefect.deployments.steps.run_shell_script:
        id: get_version
        script: |
          # Option A: parse soc/__init__.py
          if [ -f soc/__init__.py ]; then
            v=$(sed -nE "s/^__version__ *= *<[^'\"]+|'\">['\"].*$/\1/p" soc/__init__.py | head -n1)
            printf "%s" "$v"
            exit 0
          fi

          # Option B: parse pyproject.toml
          if [ -f pyproject.toml ]; then
            v=$(sed -nE 's/^version *= *"([^"]+)".*$/\1/p' pyproject.toml | head -n1)
            printf "%s" "$v"
            exit 0
          fi

          # Option C: read version.txt
          if [ -f version.txt ]; then
            tr -d '\n' < version.txt
            exit 0
          fi

          echo "0.0.0"  # fallback

    - prefect_docker.deployments.steps.build_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ get_version.stdout }}"
        # optionally:
        # additional_tags:
        #   - "soc-{{ get_version.stdout }}"

  push:
    - prefect_docker.deployments.steps.push_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ get_version.stdout }}"
Notes: - The sed expressions are portable (-E works on macOS and Linux). They extract the first version match and print it without a trailing newline. - You can reuse the same value anywhere templating is supported, e.g., additional_tags, job_variables.image, etc. If you tell me exactly where your version lives (init file path, pyproject, or a version file), I’ll tailor the script down to a single, minimal line. Docs: - prefect.yaml templating and steps - Docker image packaging with Prefect
p
@Marvin how to load prefect variable in yaml file
m
thought for 216.1 seconds
Yes—use Prefect Variables in prefect.yaml via templating. In Prefect 3.x the syntax is: - Reference a variable:
{{ prefect.variables.VARIABLE_NAME }}
How to set and use: 1) Create/set a variable
Copy code
prefect variable set DOCKER_TAG v1.2.3
# optional: overwrite if it already exists
prefect variable set DOCKER_TAG v1.2.4 --overwrite
2) Use it in prefect.yaml - For Docker image tags in build/push steps:
Copy code
deployments:
- name: my-deploy
  entrypoint: flows/flow.py:flow
  build:
    - prefect_docker.deployments.steps.build_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ prefect.variables.DOCKER_TAG }}"
  push:
    - prefect_docker.deployments.steps.push_docker_image:
        image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
        tag: "{{ prefect.variables.DOCKER_TAG }}"
- For job variables (e.g., environment passed to the worker/container):
Copy code
job_variables:
    env:
      DOCKER_TAG: "{{ prefect.variables.DOCKER_TAG }}"
      APP_ENV: "{{ prefect.variables.APP_ENV }}"
Where templating works: - build, push, and pull sections (pull resolves at runtime) - job_variables (e.g., image, env) - within step parameters (and cross-step references via
{{ step_id.field }}
) Notes: - Variables are strings; set them to the exact value you want used. - If a variable is missing, deployment may fail at template resolution time. - For sensitive values, consider blocks (e.g., Secrets) instead of variables. Docs: - Prefect Variables - prefect.yaml templating
p
@Marvin the deployment is getting stuck at the run_shell_script step
m
thought for 102.1 seconds
Let’s get you unstuck. A run_shell_script step will “hang” if the script waits for input or never exits (e.g., an unterminated heredoc, an interactive command, a path that causes a command to wait). A few quick things to try: - Share your run_shell_script snippet and any deploy output if you can — that will let me pinpoint it. - Ensure the script exits. Avoid interactive commands (e.g., docker login without --password-stdin), and make sure heredocs are properly closed. - Add safety and debug flags: - Use a short timeout so it can’t hang indefinitely - Set -euxo pipefail to see each command and fail fast - Verify file paths (use directory: "." or a specific subdir so relative paths resolve) Example: robust, non-interactive version extraction (no Python), plus timeout and debug
Copy code
- prefect.deployments.steps.run_shell_script:
    id: get_version
    directory: "."
    script: |
      set -euxo pipefail
      # bail out after 30s if something goes wrong
      timeout 30s bash -c '
        v=""
        if [ -f soc/__init__.py ]; then
          v=$(awk -F"[\x22\x27]" '"'"'/__version__/{print $2; exit}'"'"' soc/__init__.py)
        elif [ -f pyproject.toml ]; then
          v=$(awk -F\" '"'"'/^version *=/{print $2; exit}'"'"' pyproject.toml)
        elif [ -f version.txt ]; then
          v=$(tr -d "\n" < version.txt)
        fi
        if [ -z "$v" ]; then
          echo "Could not determine version" >&2
          exit 1
        fi
        printf "%s" "$v"
      '
Then reference it:
Copy code
- prefect_docker.deployments.steps.build_docker_image:
    image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
    tag: "{{ get_version.stdout }}"
- prefect_docker.deployments.steps.push_docker_image:
    image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
    tag: "{{ get_version.stdout }}"
If you were using a Python heredoc like python - <<'PY', the most common cause of “stuck” is the heredoc terminator not matching exactly (PY) or getting mis-indented so the shell keeps waiting for the end marker. Prefer to avoid the shell step entirely? - Set a Prefect Variable in CI or locally, then use it in YAML. This removes the run_shell_script step:
Copy code
prefect variable set APP_VERSION 1.2.3
Copy code
- prefect_docker.deployments.steps.build_docker_image:
    image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
    tag: "{{ prefect.variables.APP_VERSION }}"
Extra diagnostics: - Run the script locally (outside Prefect) to ensure it returns quickly. - Enable more logs when deploying: set
PREFECT_LOGGING_LEVEL=DEBUG
in your environment. - If your script references files, confirm the working directory is what you expect (use the
directory:
parameter or insert
pwd && ls -la
at the top for troubleshooting). If you paste your current run_shell_script step and the last few log lines from prefect deploy, I can identify the exact cause and give a targeted fix.
p
@Marvin this is my yaml config - prefect.deployments.steps.run_shell_script: id: get_soc_version # Print the version without a trailing newline script: | python - <<'PY' import sys import soc sys.stdout.write(getattr(soc, "__version__", "0.0.0")) PY stream_output: false
m
thought for 50.4 seconds
Thanks for sharing the snippet — two common causes of “hangs” with run_shell_script here: - Heredoc pitfalls: if the closing marker (PY) isn’t matched exactly at the start of a line, the shell keeps waiting for input. YAML indentation can sometimes cause this. Also make sure the file actually contains
<<
(not the HTML
<<
you pasted here). - No logs: you’ve set
stream_output: false
, so you won’t see what’s happening even if it’s stuck. Easiest fix: avoid heredocs entirely and use python -c. Also turn on output and add a timeout. Try this:
Copy code
- prefect.deployments.steps.run_shell_script:
    id: get_soc_version
    directory: "."
    stream_output: true
    script: |
      set -euxo pipefail
      # Use python3 if that's your default; otherwise change to `python`
      timeout 30s python3 -c 'import sys, soc; sys.stdout.write(getattr(soc, "__version__", "0.0.0"))'
Then reference it as before:
Copy code
- prefect_docker.deployments.steps.build_docker_image:
    image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
    tag: "{{ get_soc_version.stdout }}"
- prefect_docker.deployments.steps.push_docker_image:
    image_name: <http://docker.io/youruser/yourimage|docker.io/youruser/yourimage>
    tag: "{{ get_soc_version.stdout }}"
If you prefer to keep the heredoc, make sure the terminator is exact and not indented. For example:
Copy code
script: |
  set -euxo pipefail
  timeout 30s python3 - <<'PY'
  import sys
  import soc
  sys.stdout.write(getattr(soc, "__version__", "0.0.0"))
  PY
If this still hangs, it usually means the shell didn’t see the terminating PY exactly. The python -c approach avoids this entirely. Extra tips: - Ensure the
soc
package is importable at deploy time (run from repo root or set PYTHONPATH). - Use
stream_output: true
while debugging. - You can eliminate the shell step entirely by setting a Prefect Variable (e.g.,
prefect variable set APP_VERSION 1.2.3
) and referencing
{{ prefect.variables.APP_VERSION }}
. Docs: - prefect.yaml templating and steps If it still hangs after this change, paste the new logs (with
stream_output: true
) and I’ll pinpoint the exact cause.