Hi <@ULVA73B9P> I run prefect in a docker-compose ...
# ask-marvin
m
Hi @Marvin I run prefect in a docker-compose setup. The service (container) for the docker worker is configured like that:
Copy code
worker-docker:
        image: prefecthq/prefect:${PREFECT_TAG:-3-latest}
        restart: unless-stopped
        depends_on:
            server:
                condition: service_started
        networks:
            - internal
        environment:
            EXTRA_PIP_PACKAGES: prefect-docker
            PREFECT_API_URL: <http://server:4200/api>
        command: prefect worker start --pool whale --type docker
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
I have also already created a
block
named
my-cr-secret
that is a dump of
DockerRegistryCredentials
Copy code
credentials = DockerRegistryCredentials(
        username=docker_user, password=SecretStr(docker_password), registry_url=docker_registry_url
    )
    credentials.save(name="my-cr-secret", overwrite=True)
now when I want to deploy some local code to run inside a docker container on my server, I fail at authentication. How do I provide the credentials or better reference the credentials in
my-cr-secret
?
m
thought for 927.8 seconds
Thanks for the details — your setup looks good. In Prefect 3.x, a Docker worker will only pull from a private registry if you pass registry credentials to the job. Since you already created a
DockerRegistryCredentials
block (
my-cr-secret
), reference it in your deployment’s job variables so the worker can log in before pulling the image. Two places you may need credentials: 1) Runtime pull by the worker (always needed for private images) 2) Build/push during deploy steps (only if you build/push an image as part of deployment) Option A — set credentials per deployment (recommended) - Python deploy:
Copy code
from prefect import flow

@flow
def my_flow():
    ...

if __name__ == "__main__":
    my_flow.deploy(
        name="my-deployment",
        work_pool_name="whale",   # your Docker work pool
        image="<http://my-registry.example.com/my-app:latest|my-registry.example.com/my-app:latest>",
        job_variables={
            "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}"
        },
    )
- prefect.yaml:
Copy code
deployments:
  - name: my-deployment
    entrypoint: path/to/flow.py:my_flow
    work_pool:
      name: whale
    job_variables:
      image: <http://my-registry.example.com/my-app:latest|my-registry.example.com/my-app:latest>
      registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}"
Option B — set credentials on the work pool (applies to all deployments) - In the Docker work pool’s base job template, set:
Copy code
registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}"
Then you don’t need to repeat it in each deployment. If you’re also building/pushing an image during deployment (prefect.yaml steps), pass the same block to the push step:
Copy code
build:
  - prefect_docker.deployments.steps.build_docker_image:
      id: build-image
      image_name: <http://my-registry.example.com/my-app|my-registry.example.com/my-app>
      tag: latest
      dockerfile: auto

push:
  - prefect_docker.deployments.steps.push_docker_image:
      image_name: "{{ build-image.image_name }}"
      tag: "{{ build-image.tag }}"
      credentials: "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}"
Notes and gotchas - The block reference format is:
{{ prefect.blocks.docker-registry-credentials.<block-name> }}
— so your value is
{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}
. - Ensure the block is saved to the same Prefect API your worker talks to (you’ve set `PREFECT_API_URL=http://server:4200/api`). -
registry_url
should be the hostname only (no scheme). Examples: - Docker Hub: omit
registry_url
or use
<http://index.docker.io|index.docker.io>
- GHCR:
<http://ghcr.io|ghcr.io>
- ACR:
<http://myregistry.azurecr.io|myregistry.azurecr.io>
- Your worker image already installs
prefect-docker
via
EXTRA_PIP_PACKAGES
, which is required for the Docker worker type. If auth still fails, please share: - The registry you’re using - How you deploy (Python,
prefect.yaml
, or CLI) - The exact error message from the worker logs References - DockerRegistryCredentials block docs - Docker deployments and steps (build/push)
m
@Marvin let's go with option B. Can you provide a more complete idiot-proof example
m
thought for 304.1 seconds
Awesome — let’s make Option B copy/paste friendly. We’ll put the credentials at the work pool level so every deployment that targets the pool “whale” can pull private images without extra config. Prereqs - Your worker is already running with
--type docker
on pool
whale
(as in your compose) - The
DockerRegistryCredentials
block
my-cr-secret
exists in the same Prefect API your worker uses (`PREFECT_API_URL=http://server:4200/api`) - The block type for prefect-docker is registered (one-time) Step 0 — Point your CLI at the same API (important) Run these commands from a shell where
PREFECT_API_URL
points to your server:
Copy code
export PREFECT_API_URL=<http://server:4200/api>
prefect version
prefect server status
Step 1 — Ensure the Docker block type is registered (one-time)
Copy code
prefect block register -m prefect_docker.credentials
Verify your credentials block is there:
Copy code
prefect block inspect docker-registry-credentials/my-cr-secret
Step 2 — Create a base job template file for the pool Create a file named
base_job_template.json
with this content. It sets the registry credentials at the pool level using your block by name and keeps everything else simple.
Copy code
{
  "job_configuration": {
    "name": "{{ name }}",
    "image": "{{ image }}",
    "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}",
    "stream_output": true,
    "auto_remove": true
  },
  "variables": {
    "type": "object",
    "properties": {
      "name": {
        "title": "Container Name",
        "type": "string",
        "default": "prefect-flow-run"
      },
      "image": {
        "title": "Docker Image",
        "description": "The image to run for your flow",
        "type": "string",
        "default": "<http://my-registry.example.com/my-app:latest|my-registry.example.com/my-app:latest>"
      }
    },
    "required": [
      "image"
    ]
  }
}
Notes: - The credentials line must be exactly the placeholder (no extra text):
{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}
-
my-cr-secret
is your existing block name - Set the default image to your private image if you want Step 3 — Update your existing work pool “whale” with this template
Copy code
prefect work-pool update whale --base-job-template base_job_template.json
You can double-check the pool:
Copy code
prefect work-pool inspect whale
No worker restart needed — new runs will use the updated template automatically. Step 4 — Deploy normally without repeating credentials Now you can deploy with just an image and pool; no need to pass
registry_credentials
per deployment. Python:
Copy code
from prefect import flow

@flow
def my_flow():
    print("hello")

if __name__ == "__main__":
    my_flow.deploy(
        name="my-deployment",
        work_pool_name="whale",
        image="<http://my-registry.example.com/my-app:latest|my-registry.example.com/my-app:latest>"
    )
prefect.yaml:
Copy code
deployments:
  - name: my-deployment
    entrypoint: path/to/flow.py:my_flow
    work_pool:
      name: whale
    job_variables:
      image: <http://my-registry.example.com/my-app:latest|my-registry.example.com/my-app:latest>
Step 5 — Run a quick test - Trigger a run (from UI or
prefect deployment run my-deployment
) - Watch the worker logs; you should see it logging into your registry and pulling the image Common gotchas - Make sure the block’s
registry_url
is just the host (no scheme): e.g.
<http://ghcr.io|ghcr.io>
,
<http://index.docker.io|index.docker.io>
,
<http://myregistry.azurecr.io|myregistry.azurecr.io>
- Your CLI and your worker must point to the same Prefect API; otherwise the worker won’t see the block you created - Your worker container already has
prefect-docker
via
EXTRA_PIP_PACKAGES
, which is required for Docker workers If you also build/push images during deployment Putting credentials at the pool level handles runtime pulls. If you’re building/pushing as part of deployment steps, add the same block to your push step: ``` push: - prefect_docker.deployments.steps.push_docker_image: image_name: "{{ build-image.image_name }}" tag: "{{ build-image.tag }}"
credentials: "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}" ``` Docs for reference - DockerRegistryCredentials block - Docker deployments and steps If you hit any error, paste the worker log line around the image pull or auth failure and tell me your registry host — I’ll help debug quickly.
m
@Marvin I hit an error when updating the work pool
Copy code
Response: {'exception_message': 'Invalid request received.', 'exception_detail': [{'type': 'value_error', 'loc': ['body', 'base_job_template'], 'msg': 'Value error, The variables specified in the job configuration template must be present as properties in the variables schema. Your job configuration uses the following undeclared variable(s): prefect.blocks.docker-registry-credentials.my-cr-secret.', 'input': {'job_configuration': {'name': '{{ name }}', 'image': '{{ image }}', 'registry_credentials': '{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}', 'stream_output': True, 'auto_remove': True}, 'variables': {'type': 'object', 'properties': {'name': {'title': 'Container Name', 'type': 'string', 'default': 'prefect-flow-run'}, 'image': {'title': 'Docker Image', 'description': 'The image to run for your flow', 'type': 'string', 'default': 'my-cr.tld/hello-world:latest'}}, 'required': ['image']}}, 'ctx': {'error': {}}}], 'request_body': {'base_job_template': {'job_configuration': {'name': '{{ name }}', 'image': '{{ image }}', 'registry_credentials': '{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}', 'stream_output': True, 'auto_remove': True}, 'variables': {'type': 'object', 'properties': {'name': {'title': 'Container Name', 'type': 'string', 'default': 'prefect-flow-run'}, 'image': {'title': 'Docker Image', 'description': 'The image to run for your flow', 'type': 'string', 'default': 'my-cr.tld/hello-world:latest'}}, 'required': ['image']}}}}
For more information check: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422>
An exception occurred.
m
thought for 40.5 seconds
Thanks for sharing the error — that validation message is actually helpful. Prefect is treating the string in
{{ ... }}
as a variable name, so it expects to find a matching entry in the
variables
schema. Since we put the block reference directly in
job_configuration
, it complained. You have two clean fixes. Pick one. Option 1 (recommended): Declare a variable and set its default to your block reference - Put
registry_credentials
in the variables schema - Reference that variable in the job configuration base_job_template.json
Copy code
{
  "job_configuration": {
    "name": "{{ name }}",
    "image": "{{ image }}",
    "registry_credentials": "{{ registry_credentials }}",
    "stream_output": true,
    "auto_remove": true
  },
  "variables": {
    "type": "object",
    "properties": {
      "name": {
        "title": "Container Name",
        "type": "string",
        "default": "prefect-flow-run"
      },
      "image": {
        "title": "Docker Image",
        "description": "The image to run for your flow",
        "type": "string",
        "default": "my-cr.tld/hello-world:latest"
      },
      "registry_credentials": {
        "title": "Registry Credentials",
        "description": "DockerRegistryCredentials block reference",
        "default": "{{ prefect.blocks.docker-registry-credentials.my-cr-secret }}"
      }
    },
    "required": [
      "image"
    ]
  }
}
Update the pool:
Copy code
export PREFECT_API_URL=<http://server:4200/api>
prefect work-pool update whale --base-job-template base_job_template.json
prefect work-pool inspect whale
Why this works: -
job_configuration
now uses a declared variable
{{ registry_credentials }}
- The variable’s default is your block reference, which Prefect resolves at runtime Option 2: Inline a block reference by ID (no variables entry needed) - Replace the credentials field with a direct
$ref
using the block’s UUID Find the block’s ID:
Copy code
prefect block inspect docker-registry-credentials/my-cr-secret
Copy the block_document_id/ID from the output, then use: base_job_template.json
Copy code
{
  "job_configuration": {
    "name": "{{ name }}",
    "image": "{{ image }}",
    "registry_credentials": {
      "$ref": {
        "block_document_id": "YOUR-BLOCK-UUID-HERE"
      }
    },
    "stream_output": true,
    "auto_remove": true
  },
  "variables": {
    "type": "object",
    "properties": {
      "name": {
        "title": "Container Name",
        "type": "string",
        "default": "prefect-flow-run"
      },
      "image": {
        "title": "Docker Image",
        "type": "string",
        "default": "my-cr.tld/hello-world:latest"
      }
    },
    "required": [
      "image"
    ]
  }
}
Update the pool:
Copy code
export PREFECT_API_URL=<http://server:4200/api>
prefect work-pool update whale --base-job-template base_job_template.json
Quick test - Deploy a flow that uses an image from your private registry and targets
work_pool_name="whale"
- Trigger a run and watch worker logs for successful login/pull Notes - Keep
registry_url
as a host only (e.g.,
<http://ghcr.io|ghcr.io>
,
<http://index.docker.io|index.docker.io>
,
<http://myregistry.azurecr.io|myregistry.azurecr.io>
) - Your CLI and worker must point to the same API (`PREFECT_API_URL=http://server:4200/api`) - If you haven’t already, register the docker blocks once:
Copy code
prefect block register -m prefect_docker.credentials
Reference - DockerRegistryCredentials block docs If you still get a 422 after this change, paste your exact
base_job_template.json
and the failing command and I’ll spot-check it.