<@ULVA73B9P> my ci can reach the prefect api with ...
# ask-marvin
o
@Marvin my ci can reach the prefect api with "somehost:4200/api" but in the later deployment the woker container is inside a docker network "prefect-server:4200/api" so i need to injecte different PREFECT_API URLS one at deploy.py and one inside the code?
m
thought for 197.4 seconds
Short answer: yes—set different PREFECT_API_URL values per environment, but don’t hardcode them in your code. - In CI (where you run deploy), set
PREFECT_API_URL
to the endpoint your CI can reach (e.g., `http://somehost:4200/api`). This is only needed to create/update the deployment. - In your worker container (runtime), set
PREFECT_API_URL
to the address resolvable inside the Docker network (e.g., `http://prefect-server:4200/api`). Workers automatically pass their Prefect settings to flow run containers, so your flows will connect using the worker’s URL. No need to inject it in your flow code. Example: Docker Compose worker
Copy code
services:
  prefect-worker:
    image: prefecthq/prefect:3-latest
    environment:
      PREFECT_API_URL: "<http://prefect-server:4200/api>"
      # For Prefect Cloud use PREFECT_API_KEY; for self-hosted with auth use PREFECT_API_AUTH_STRING if applicable
      # PREFECT_API_KEY: "pnu_..."
      # PREFECT_API_AUTH_STRING: "admin:password"
    command: >
      prefect worker start -p my-work-pool
    depends_on:
      - prefect-server
    networks:
      - prefect
CI (deploy) example
Copy code
# environment for your CI job
PREFECT_API_URL=<http://somehost:4200/api>
# plus auth if needed:
# PREFECT_API_KEY=...
# or PREFECT_API_AUTH_STRING=...

# then run either:
prefect deploy
# or in Python: flow.from_source(...).deploy(...)
If you ever need to override the API URL for a specific deployment (rare with a single server), you can set it per-deployment via `job_variables.env`:
Copy code
flow.deploy(
  name="my-deployment",
  work_pool_name="my-pool",
  job_variables={
    "env": {
      "PREFECT_API_URL": "<http://some-other-endpoint:4200/api>"
    }
  }
)
Key points: - Use environment variables, not code, for
PREFECT_API_URL
. - The deployment process and the worker runtime can (and often should) use different URLs depending on their network vantage point. - Flow run containers inherit the worker’s
PREFECT_*
settings automatically. Does that match your setup (self-hosted Prefect Server + Docker worker)? If so, I can help tailor a minimal docker-compose and CI snippet for your exact stack.
o
@Marvin when i run the deployment if fails to pull the docker container, because it needs authentication at the registry /testci/prefect/manifests/0.0.1-dev ": unknown: Authentication is required
m
thought for 329.9 seconds
Authentication errors when a worker pulls your flow image usually mean the worker isn’t authenticated to your registry. Quick questions to get you unblocked fast: - Which worker type are you using (Docker, Kubernetes, ECS, Azure)? - What registry are you pulling from (Docker Hub, GHCR, ECR, ACR, etc.)? - What’s the full image name you’re using? In the meantime, here’s how to fix it per worker type (Prefect 3.x): Docker worker - Option A (quick): Ensure the host running the worker is logged in to the registry as the same user running the worker process. - Test interactively on the worker host:
Copy code
docker login <your-registry>
    docker pull <your-registry>/<repo>:<tag>
- If this pull succeeds, your worker should be able to pull too. - Option B (recommended): Provide explicit registry credentials via a DockerRegistryCredentials block and reference it in your work pool job variables. 1) Install the docker integration and register block types:
Copy code
pip install "prefect[docker]"
     prefect block register -m prefect_docker
2) Create the credentials block (you can run this once locally or anywhere with Prefect API access):
Copy code
from prefect_docker import DockerRegistryCredentials
     from pydantic import SecretStr

     creds = DockerRegistryCredentials(
         username="YOUR_USERNAME",
         password=SecretStr("YOUR_PASSWORD_OR_PAT"),
         registry_url="<http://your-registry.example.com|your-registry.example.com>"
     )
     import asyncio; asyncio.run(creds.save("my-registry", overwrite=True))
3) In your Docker work pool’s job variables (UI or
prefect.yaml
), set:
Copy code
work_pool:
       name: your-docker-pool
       job_variables:
         image: <http://your-registry.example.com/your-repo:your-tag|your-registry.example.com/your-repo:your-tag>
         registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-registry }}"
Kubernetes worker - Create a docker-registry secret in the namespace where jobs run and add it to the pool’s base job template as imagePullSecrets:
Copy code
kubectl create secret docker-registry my-registry-secret \
    --docker-server=<http://your-registry.example.com|your-registry.example.com> \
    --docker-username=YOUR_USERNAME \
    --docker-password=YOUR_PASSWORD_OR_PAT \
    --docker-email=you@example.com \
    -n <namespace>
Then in the Kubernetes work pool’s base job template:
Copy code
spec:
    template:
      spec:
        imagePullSecrets:
          - name: my-registry-secret
ECS worker (AWS) - Put your registry credentials in AWS Secrets Manager and reference them in the task definition via repositoryCredentials in the base job template:
Copy code
containerDefinitions:
    - name: prefect
      image: "{{ image }}"
      repositoryCredentials:
        credentialsParameter: "arn:aws:secretsmanager:region:acct:secret:your-secret"
Azure Container Instances worker - Provide an image registry block in job variables:
Copy code
work_pool:
    name: your-aci-pool
    job_variables:
      image: <http://yourregistry.azurecr.io/your-repo:tag|yourregistry.azurecr.io/your-repo:tag>
      image_registry: "{{ prefect.blocks.docker-registry-credentials.my-registry }}"
Or use a managed identity block for ACR. Helpful checks - On the worker host, run:
Copy code
docker pull <your-image>
If this fails, the worker will fail too—fix auth first. - Make sure your token has the right scopes (e.g., GHCR: read:packages; ACR: pull; ECR: IAM permissions for GetAuthorizationToken/BatchGetImage). If you can share your worker type and the registry you’re using, I’ll give you the exact snippet to drop into your work pool/deployment.
o
@Marvin what is the most secret and preferred way of prefect users to register the secrets of a container registry?
m
thought for 71.6 seconds
Great question. Short answer: prefer identity-based auth; if you must use a password/token, store it in a credentials block and reference it—don’t hardcode it in YAML or env vars. Preferred patterns (most secure → least) 1) Use cloud/workload identity (no static secrets) - AWS ECS/EKS: ECR with IAM roles (task/IRSA). No username/password at all. - Azure: ACR with managed identity (ACI worker supports an ACRManagedIdentity block). - GKE/Kubernetes: Artifact Registry/GCR with Workload Identity; if needed, mint imagePullSecrets via your cloud auth controller. 2) Use your cloud secret manager integrated with the worker runtime - ECS: Put creds in AWS Secrets Manager and reference via
repositoryCredentials
in the task definition template. - Kubernetes: Use
imagePullSecrets
sourced from a K8s Secret that’s synced from your secret manager (e.g., External Secrets Operator or a CSI secrets driver). Don’t embed secrets in Prefect config. 3) Use Prefect Blocks for registry auth (most common, secure within Prefect) - Store a DockerRegistryCredentials block and reference it from your work pool/deployment. Secret values are encrypted at rest in Prefect Cloud and redacted in logs. - This keeps credentials out of code, CI logs, and your
prefect.yaml
. Creating a DockerRegistryCredentials block (for Docker worker, ACI, and build/push steps)
Copy code
pip install "prefect[docker]"
prefect block register -m prefect_docker
Then in Python (run once, anywhere with API access):
Copy code
from prefect_docker import DockerRegistryCredentials
from pydantic import SecretStr
import asyncio

creds = DockerRegistryCredentials(
    username="YOUR_USERNAME",
    password=SecretStr("YOUR_PASSWORD_OR_PAT"),
    registry_url="<http://your-registry.example.com|your-registry.example.com>"
)
asyncio.run(creds.save("my-registry", overwrite=True))
Reference it in your Docker work pool job variables (UI or prefect.yaml):
Copy code
work_pool:
  name: your-docker-pool
  job_variables:
    image: <http://your-registry.example.com/your-repo:tag|your-registry.example.com/your-repo:tag>
    registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-registry }}"
For build/push steps in prefect.yaml:
Copy code
push:
  - prefect_docker.deployments.steps.push_docker_image:
      requires: prefect-docker>=0.3.0
      image_name: "{{ build-image.image_name }}"
      tag: "{{ build-image.tag }}"
      credentials: "{{ prefect.blocks.docker-registry-credentials.my-registry }}"
Kubernetes worker best practice - Prefer cloud identity; otherwise use an
imagePullSecrets
K8s Secret (ideally synced from your secret manager):
Copy code
kubectl create secret docker-registry my-registry-secret \
  --docker-server=<http://your-registry.example.com|your-registry.example.com> \
  --docker-username=YOUR_USERNAME \
  --docker-password=YOUR_PASSWORD_OR_PAT \
  -n <namespace>
Add to the Kubernetes work pool’s base job template:
Copy code
spec:
  template:
    spec:
      imagePullSecrets:
        - name: my-registry-secret
Azure ACI worker best practice - Prefer managed identity:
Copy code
# In job variables
image_registry: "{{ prefect.blocks.acr-managed-identity.YOUR_IDENTITY_BLOCK }}"
- Or use DockerRegistryCredentials as above. ECS worker best practice - Prefer ECR with IAM (no secrets). - For other registries, use AWS Secrets Manager +
repositoryCredentials
in the task definition template. What to avoid - Hardcoding credentials in
prefect.yaml
or env vars. - Relying on
docker login
on the host (works but is less auditable/portable and easy to misconfigure in CI). If you share your worker type and registry (e.g., GHCR/ECR/ACR), I’ll give you the exact, minimal configuration following the most secure option for that stack.
o
@Marvin and how do use the block ? in .deploy? or where ? from my understanding its the cleanest way to point in the deploy py to the block? what is the best way?
m
thought for 250.9 seconds
Great question — in Prefect 3.x you don’t pass blocks directly to
.deploy()
. Instead: - Code storage (Git, S3, etc.): Set via
Flow.from_source(source=..., entrypoint=...)
before calling
.deploy(...)
- Infrastructure settings: Set on your work pool and optionally override via
.deploy(job_variables=...)
- Result storage: Set on the flow via the
@flow
decorator (
result_storage=...
) - Credentials blocks: Load them in your
deploy.py
(or inside the flow) and pass them to whatever needs them (e.g., a
GitRepository
, S3 client, etc.) Signatures (verified):
Copy code
Flow.from_source(source, entrypoint) -> Flow
Flow.deploy(name, work_pool_name=None, image=None, build=True, push=True, work_queue_name=None, job_variables=None, ...)
Clean, recommended patterns 1) Point your deployment at a repo using a credentials block (deploy.py)
Copy code
from prefect.flows import Flow
from prefect.runner.storage import GitRepository
from prefect_github import GitHubCredentials

if __name__ == "__main__":
    gh = GitHubCredentials.load("my-gh-token-block")  # a Block
    repo = GitRepository(
        url="<https://github.com/org/repo.git>",
        credentials=gh,  # use the loaded block instance here
    )

    Flow.from_source(
        source=repo,
        entrypoint="flows/my_flow.py:my_flow",  # path:callable_name in the repo
    ).deploy(
        name="prod",
        work_pool_name="docker-pool",
        job_variables={
            "env": {"ENV": "prod"},
            # any pool template overrides like image/memory/cpu/etc.
            # "image": "my-registry/my-image:latest",
        },
    )
2) Set result storage with a block on the flow (flow code)
Copy code
from prefect import flow
from prefect_aws.s3 import S3Bucket

s3 = S3Bucket.load("my-s3-bucket-block")

@flow(result_storage=s3, persist_result=True)
def my_flow(name: str = "world"):
    return f"Hello, {name}!"
Tip: If you want to avoid API calls at import time, you can defer block loading with a string slug:
Copy code
@flow(result_storage="s3-bucket/my-s3-bucket-block", persist_result=True)
def my_flow(...):
    ...
Key takeaways - Don’t pass blocks to
.deploy()
— it doesn’t accept them. - Use
Flow.from_source(...)
to define code storage; you can pass a storage object that uses a credentials block. - Use
job_variables
in
.deploy(...)
to tweak infra at deploy time. - Use the flow decorator for result storage. - Removed in 3.x:
Deployment.build_from_flow()
and
prefect deployment build
. If you can share which block you’re trying to point to (e.g., GitHubCredentials, S3Bucket, Secret), I can tailor the exact snippet to your setup.
o
@Marvin i think you misunderstood, how to tell which credentials block to use for multiple deployments to pull images?
m
thought for 269.3 seconds
Got it — you want to pick a different registry credentials block per deployment so the worker can pull the right image. Short answer: - For Docker work pools, set
registry_credentials
per deployment via
job_variables
- You can either pass a loaded block object in Python, or reference a saved block via a template string - Kubernetes/ECS don’t use this field; use their native mechanisms (imagePullSecrets / repositoryCredentials) Examples for Docker worker 1) Pass a loaded block per deployment (cleanest in deploy.py)
Copy code
from prefect import flow
from prefect_docker.credentials import DockerRegistryCredentials

@flow
def my_flow():
    ...

if __name__ == "__main__":
    prod_creds = DockerRegistryCredentials.load("docker-registry-prod")
    stg_creds = DockerRegistryCredentials.load("docker-registry-staging")

    my_flow.deploy(
        name="prod",
        work_pool_name="docker-pool",
        image="<http://my-registry.example.com/app:prod|my-registry.example.com/app:prod>",
        job_variables={"registry_credentials": prod_creds},
    )

    my_flow.deploy(
        name="staging",
        work_pool_name="docker-pool",
        image="<http://staging-registry.example.com/app:stg|staging-registry.example.com/app:stg>",
        job_variables={"registry_credentials": stg_creds},
    )
2) Use a block reference string (if you prefer templating)
Copy code
my_flow.deploy(
    name="prod",
    work_pool_name="docker-pool",
    image="<http://my-registry.example.com/app:prod|my-registry.example.com/app:prod>",
    job_variables={
        "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.docker-registry-prod }}"
    },
)
Notes - Field name is
registry_credentials
on the Docker worker job config; it expects a
DockerRegistryCredentials
block. - You can put a default in the work pool’s base job template and override per deployment with
job_variables
when needed. - If you’re not on the Docker worker: - Kubernetes: set
imagePullSecrets
in
job_variables.job_manifest
(K8s secret must exist in the cluster). - ECS: set
task_definition.containerDefinitions[].repositoryCredentials.credentialsParameter
to an AWS Secrets Manager ARN. Helpful links - Prefect Docker integration reference - Docker worker job config (source) - DockerRegistryCredentials block (source) - Worker templating/deserialization (source) If you can confirm which worker you’re using (Docker, Kubernetes, ECS), I’ll tailor the exact snippet to that runtime.
o
@Marvin what is benefit job_variables={"registry_credentials": stg_creds} over job_variables={ "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.docker-registry-prod }}" },
m
thought for 165.4 seconds
Great follow-up. The main difference is about security, portability, and how values are stored: Using a loaded block object (Python):
Copy code
job_variables={"registry_credentials": stg_creds}
- Pros: - Convenient when scripting in Python; you already have the object. - Type-safe locally (Pydantic validation happens right there). - Cons: - The object is serialized into the deployment payload. Sensitive fields (e.g., password) become plain JSON in the deployment record. - Ties your deploy script to having API access to load the block at deploy time. - Harder to see/edit from the UI because the deployment stores a blob of values instead of a neat reference. Using a block reference (templated string):
Copy code
job_variables={
  "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.docker-registry-prod }}"
}
- Pros: - Only a reference is stored on the deployment; the actual secret stays in the block store and is resolved at runtime. - Safer for credentials; no secret material in the deployment JSON. - Easy to swap per environment by changing the block name, and easy to inspect/edit in the UI or prefect.yaml. - Works even when your deploy script shouldn’t load blocks at import/deploy time. - Cons: - Slightly more ceremony (need the block pre-created with the correct name). - You don’t get local type-checking on that field at deploy time. Recommendation - For credentials (registry, cloud auth, etc.), prefer the templated block reference approach to avoid leaking secrets into deployment config and to keep deployments portable and editable. - Reserve passing objects directly for non-sensitive config or for quick local experiments. If you share the worker type and how you manage environments (prod/stg/dev), I can sketch a pattern for naming and referencing the right block per deployment.
o
prefect.deployments.runner.DeploymentApplyError: Error creating deployment: Validation failed for field 'registry_credentials'. Failure reason: '{{ prefect.blocks.docker-registry-credentials.my-credentials }}'
@Marvin prefect.deployments.runner.DeploymentApplyError: Error creating deployment: Validation failed for field 'registry_credentials'. Failure reason: '{{ prefect.blocks.docker-registry-credentials.my-credentials }}'
m
thought for 139.1 seconds
Thanks for the error message — that helps pinpoint what’s happening. What it means -
registry_credentials
is a structured field (expects a DockerRegistryCredentials object). - You passed a template string:
{{ prefect.blocks.docker-registry-credentials.my-credentials }}
. - Prefect validates deployment payloads before saving; for some fields it checks type/shape. A raw string can be rejected when the server expects an object. Why this can fail at deploy time - Although block references are resolved later by the worker, the deployment creation still validates job_variables against the work pool’s base job template schema. If the schema for
registry_credentials
says “object”, providing a plain string (the template) can cause a validation error: Validation failed for field 'registry_credentials'. Failure reason: '{{ ... }}'. Two reliable fixes Option A: Pass the loaded block object in Python (works immediately at deploy time)
Copy code
from prefect import flow
from prefect_docker.credentials import DockerRegistryCredentials

@flow
def my_flow():
    ...

if __name__ == "__main__":
    creds = DockerRegistryCredentials.load("my-credentials")
    my_flow.deploy(
        name="staging",
        work_pool_name="docker-pool",
        image="my.private.registry/app:stg",
        job_variables={"registry_credentials": creds},
    )
Option B: Put the templated reference into the pool’s base job template or prefect.yaml so the deploy client doesn’t validate it as a typed field - In prefect.yaml:
Copy code
deployments:
  - name: staging
    entrypoint: flows/my_flow.py:my_flow
    work_pool:
      name: docker-pool
    job_variables:
      image: "my.private.registry/app:stg"
      registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-credentials }}"
- Or set this default in the work pool’s base job template in the UI, then omit
registry_credentials
from
job_variables
at deploy time. The worker will resolve the block reference at run time. Checklist to avoid this error - Ensure the block type slug is correct:
docker-registry-credentials
(hyphenated, lowercase). - Use the block document name exactly as saved in Prefect. - If you must pass the reference via
.deploy(job_variables=...)
, prefer Option A (pass the loaded object) to satisfy deploy-time validation. - If you want purely declarative (no Python block loading), place the
{{ ... }}
in prefect.yaml or the pool template. If you share how you’re deploying (Python script vs prefect.yaml) and whether you can edit the work pool template, I can suggest the cleanest path for your setup.
o
@Marvin still i have an issue Flow run could not be submitted to infrastructure: APIError(HTTPError('500 Server Error: Internal Server Error for url: http+docker://localhost/v1.52/auth'))
m
thought for 69.6 seconds
That 500 is coming from the Docker Engine when the Docker worker tries to log in to your registry. It means the worker reached the daemon, but the login failed at the /auth step. Most common causes: - Wrong registry URL for your provider - Bad username/password or expired token (ECR tokens expire) - Daemon cannot reach the registry (network/proxy/firewall) - Insecure/self‑signed registry not allowed by the daemon Quick checks 1) On the same host where the Docker worker runs, try the exact login manually:
Copy code
docker login <registry> -u <username>
# paste the same password/token as in your block
If this fails, fix creds/URL first. 2) Verify the registry_url in your credentials block matches your registry: - Docker Hub: leave blank or use https://index.docker.io/v1/ - GHCR: ghcr.io - GitLab: registry.gitlab.com - ACR: <name>.azurecr.io - ECR: <account>.dkr.ecr.<region>.amazonaws.com (password must be an AWS ECR login password from
aws ecr get-login-password
, expires after 12h) 3) If your registry is HTTP or uses a self‑signed cert, add it to Docker’s daemon config as an insecure registry and restart Docker: - /etc/docker/daemon.json:
Copy code
{
  "insecure-registries": [
    "my-registry:5000"
  ]
}
4) Confirm the worker can reach the registry (proxy/firewall). If behind a proxy, set env vars in job_variables:
Copy code
job_variables={"env": {"HTTP_PROXY": "...", "HTTPS_PROXY": "...", "NO_PROXY": "..." }}
5) Double‑check you’re not passing a raw string where an object is expected. For Docker workers, registry credentials must resolve to a DockerRegistryCredentials object at runtime. Either: - Pass the loaded block object in Python:
Copy code
creds = DockerRegistryCredentials.load("my-credentials")
my_flow.deploy(..., job_variables={"registry_credentials": creds})
- Or reference a saved block in prefect.yaml or pool template:
Copy code
registry_credentials: "{{ prefect.blocks.docker-registry-credentials.my-credentials }}"
Provider-specific notes - Docker Hub: if you use a PAT, set username to your Docker ID and registry_url to https://index.docker.io/v1/ (or leave empty). - GHCR: use a classic PAT with the right scopes, registry_url="ghcr.io". - ECR: don’t store a static password in the block; it will expire. Either: - Refresh the block regularly with a new
aws ecr get-login-password
, or - Use a public image, or - Switch to ECS worker and use repositoryCredentials via AWS Secrets Manager for better ergonomics. If it still fails, please share: - Which registry you’re using - The relevant part of your deployment’s
job_variables
(redact secrets) - The values of
username
and
registry_url
from your DockerRegistryCredentials block (redact username if needed) - A snippet of the Docker worker logs around “Logging into Docker registry...” Helpful links: - Prefect Docker integration reference - Docker worker login code (source)
o
@Marvin is it possible to use a token? without username? docker.errors.APIError: 500 Server Error for http+docker://localhost/v1.52/auth: Internal Server Error
m
thought for 45.3 seconds
Short answer: No — the Docker login API requires a username and password. In Prefect 3.x, the Docker worker’s
DockerRegistryCredentials
block also requires
username
and
password
. If you have a “token-only” auth model, most registries still expect you to supply a specific username value and put the token in the password field. Use these provider-specific conventions: - Docker Hub: username = your Docker ID; password = your PAT; registry_url = https://index.docker.io/v1/ (or leave blank) - GHCR (ghcr.io): username = your GitHub username; password = your PAT; registry_url = ghcr.io - GitLab Registry: username = oauth2; password = your token (PAT/CI_JOB_TOKEN); registry_url = registry.gitlab.com - GCR/Artifact Registry: username = oauth2accesstoken; password = access token; registry_url = gcr.io or REGION-docker.pkg.dev (tokens expire, so you must refresh) - ECR: username = AWS; password = output of
aws ecr get-login-password
(expires ~12h); registry_url = <account>.dkr.ecr.<region>.amazonaws.com - ACR: username = registry admin user or service principal appId; password = admin key or SP secret; registry_url = <name>.azurecr.io Example block for GHCR:
Copy code
from prefect_docker.credentials import DockerRegistryCredentials

creds = DockerRegistryCredentials(
    username="my-gh-username",
    password="ghp_xxx",  # your PAT
    registry_url="<http://ghcr.io|ghcr.io>",
)
await creds.save("ghcr-prod")
Then in your deployment:
Copy code
job_variables={
  "image": "<http://ghcr.io/org/app:tag|ghcr.io/org/app:tag>",
  "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.ghcr-prod }}"
}
Your 500 on /auth is consistent with missing/incorrect username or an invalid registry_url. Please try on the same host as the Docker worker:
Copy code
docker login <http://ghcr.io|ghcr.io> -u <username> -p <token>
and use the exact same values in your
DockerRegistryCredentials
block. Helpful references: - Prefect Docker integration reference - DockerRegistryCredentials block (source) - Docker worker login code (source) If you tell me which registry you’re using, I can provide the exact username/token/registry_url values you need.
o
@Marvin i can login with docker login private_artifactory without issues. but prefect seems to have issues with that
m
thought for 45.8 seconds
Thanks for the details. Since
docker login <artifactory>
works but the Prefect Docker worker gets a 500 from /auth, this is usually a mismatch in the registry value or credentials format that Docker SDK is using versus what your CLI used. Key things to check/fix for Artifactory - Use the exact registry server address your CLI stores. After a successful CLI login, check your Docker config and copy the key used under auths:
Copy code
cat ~/.docker/config.json
# Look under "auths": the key might be "<http://artifactory.myco.com|artifactory.myco.com>" or "<https://artifactory.myco.com>"
# Use that exact string for registry_url in your block
- No path segments in registry_url. For Artifactory, do NOT use /artifactory or a repo path in the registry_url. It should be just the host (and optional port), e.g.: - OK: artifactory.myco.com - OK: https://artifactory.myco.com - Not OK: artifactory.myco.com/artifactory - Image name must match the registry host you log into:
Copy code
image: "<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>"
- Username is required. For Artifactory: - username = your Artifactory username (or the token’s associated username) - password = API key or access token - If you’re using a custom cert/self-signed, make sure the Docker daemon trusts it. CLI success suggests this is already fine on that host. How to set the block for Artifactory
Copy code
from prefect_docker.credentials import DockerRegistryCredentials

creds = DockerRegistryCredentials(
    username="my-artifactory-user",
    password="<<access-token-or-api-key>>",
    registry_url="<http://artifactory.myco.com|artifactory.myco.com>",  # EXACTLY as in ~/.docker/config.json
    reauth=True,
)
await creds.save("artifactory-prod", overwrite=True)
Then in your deployment
Copy code
job_variables={
  "image": "<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>",
  "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.artifactory-prod }}"
}
or pass the loaded block object in Python:
Copy code
creds = DockerRegistryCredentials.load("artifactory-prod")
my_flow.deploy(..., job_variables={"registry_credentials": creds})
Quick isolation test on the worker host Run this on the same machine where your Docker worker runs:
Copy code
python - <<'PY'
import docker
c = docker.from_env()
print("Logging in...")
c.login(username="my-artifactory-user",
        password="<<access-token-or-api-key>>",
        registry="<http://artifactory.myco.com|artifactory.myco.com>")
print("Pulling image...")
c.images.pull("<http://artifactory.myco.com/docker-virtual/hello-world:latest|artifactory.myco.com/docker-virtual/hello-world:latest>")
print("OK")
PY
If this fails, the issue is between Docker SDK and your registry settings (e.g., wrong serveraddress string). Use whatever key appears in ~/.docker/config.json under "auths" for the registry parameter until the script succeeds; then mirror that in your Prefect block. If it still fails, please share: - The exact
registry_url
in your block - The image value in your deployment - The “auths” key from
~/.docker/config.json
after your successful
docker login
- A few lines of Docker worker logs around “Logging into Docker registry...” Helpful references - Prefect Docker integration reference - Docker worker login code (source)
o
@Marvin the error stays the same, and iam also able to pull images on the host with no issue.
m
thought for 55.2 seconds
Understood — since
docker login
and
docker pull
work on the host but the Prefect Docker worker still gets a 500 on /auth, this usually comes down to how the worker is logging in vs. how your CLI supplies credentials. Key points to check - Is your Docker worker running: - on the host as a process, or - inside a container? If it’s in a container, it won’t see your host’s
~/.docker/config.json
unless you mount it or provide explicit credentials via a block. - The worker calls
docker_client.login(...)
if
registry_credentials
is set. That login hits the Docker daemon’s /auth endpoint. Some registries/daemons reject certain combinations (e.g., registry URL value, reauth behavior). - The registry URL must match exactly what works with the CLI. Check the key under
auths
in
~/.docker/config.json
after
docker login
and use that exact string as
registry_url
(no repo paths). - For Artifactory, don’t include path segments in
registry_url
(just host[:port]), and ensure image name uses that host as prefix. Try these, in order 1) Run the Python Docker SDK login test on the SAME machine and environment as your worker This isolates whether it’s Prefect or the Docker SDK/daemon interaction:
Copy code
python - <<'PY'
import docker, os, json
c = docker.from_env()
print("DOCKER_HOST:", os.environ.get("DOCKER_HOST"))
print("Logging in...")
# Replace with your values
c.login(
    username="my-artifactory-user",
    password="<<token-or-api-key>>",
    registry="<http://artifactory.myco.com|artifactory.myco.com>",  # EXACTLY match the key in ~/.docker/config.json
    reauth=True,
)
print("Pulling image...")
c.images.pull("<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>")
print("OK")
PY
- If this fails with the same 500, the issue is with the registry_url/credentials/reauth at the Docker API level. - If it succeeds, the worker’s environment differs (HOME/DOCKER_CONFIG/DOCKER_HOST, or it’s running in a container). 2) Try disabling re-auth Some setups (esp. Artifactory/proxies) error on explicit re-auth:
Copy code
from prefect_docker.credentials import DockerRegistryCredentials

creds = DockerRegistryCredentials(
    username="my-artifactory-user",
    password="<<token-or-api-key>>",
    registry_url="<http://artifactory.myco.com|artifactory.myco.com>",
    reauth=False,  # <-- try False
)
await creds.save("artifactory-prod", overwrite=True)
Use that block in your deployment. 3) Ensure the worker sees the same Docker credentials/config as your CLI - If the worker runs in a container, mount your Docker config: - Mount host
~/.docker
to the worker container at
/root/.docker
(or set
DOCKER_CONFIG
to a mounted path) - If the worker runs as a different OS user, it won’t see your
~/.docker/config.json
. Either: - provide
registry_credentials
via block (preferred), or - set
DOCKER_CONFIG
env to the path containing a usable
config.json
4) As a temporary workaround, avoid login/pull entirely If the image is already present on the worker host: - Pre-pull the image on the host:
docker pull <http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>
- Set pull policy to skip pulls:
Copy code
job_variables={
  "image": "<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>",
  "image_pull_policy": "Never"   # or "IfNotPresent" if you want it to pull only when missing
}
- Remove
registry_credentials
so the worker doesn’t attempt
docker login
. 5) Double-check the exact values - Block’s `registry_url`: must match the key under
"auths"
in
~/.docker/config.json
(no extra paths; host and optional port only). - Image: must be
artifactory-host/.../repo/image:tag
and match the same host. - Username/token: for Artifactory, a username is still required; put the token in password. If it still fails, could you share: - How your Docker worker is running (host process vs container) - The
registry_url
value in your
DockerRegistryCredentials
block - The image string in your deployment - The exact
auths
key from
~/.docker/config.json
after
docker login
(just the key, not the creds)
- Whether the Python SDK snippet succeeds on the worker host Useful references: - Prefect Docker integration reference - Docker worker login code - DockerRegistryCredentials block
o
@Marvin the workaround "works" so if i manually pull the image from my artifact store the docker worker can execute the flow. but its kind of frustrating that prefect is not able to login and pull it without manual step.
m
thought for 80.2 seconds
Totally understand the frustration — if
docker login
and
docker pull
work on the host, the worker should be able to do the same. There are two reliable paths that avoid the /auth 500: Option A — Skip explicit login and use your Docker config This mirrors what works with the CLI. - Remove
registry_credentials
from your deployment and pool. - Ensure the worker process can read a
config.json
that already contains your Artifactory cred under auths. - If the worker runs as a host process: - Make sure the worker user has
~/.docker/config.json
populated (same one you used to login), or set
DOCKER_CONFIG
to point to the directory containing it. - If the worker runs inside a container: - Mount your host Docker config into the worker container, e.g. mount
~/.docker
to
/root/.docker
, or set
DOCKER_CONFIG
inside the container to a mounted path. - Keep
image_pull_policy
as
Always
or
IfNotPresent
so it pulls when needed. Example job_variables without login:
Copy code
job_variables={
  "image": "<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>",
  "image_pull_policy": "IfNotPresent"
}
This avoids the explicit
docker login
call that’s currently failing and lets the SDK/daemon use the existing creds from config.json during pull. Option B — Keep registry_credentials but adjust to match what Docker expects Artifactory is sensitive to the exact server address and re-auth behavior. - Set
registry_url
to exactly match the key under "auths" in
~/.docker/config.json
after a successful CLI login. Try both forms if needed: -
<http://artifactory.myco.com|artifactory.myco.com>
-
<https://artifactory.myco.com>
- Do not include path segments like
/artifactory
. - Set
reauth=False
(some setups 500 on explicit reauth):
Copy code
from prefect_docker.credentials import DockerRegistryCredentials

creds = DockerRegistryCredentials(
    username="your-artifactory-username",
    password="<<api-key-or-access-token>>",
    registry_url="<http://artifactory.myco.com|artifactory.myco.com>",  # or <https://artifactory.myco.com> — match your config.json
    reauth=False,
)
await creds.save("artifactory-prod", overwrite=True)
Then use either a block reference or load the block and pass it:
Copy code
job_variables={
  "image": "<http://artifactory.myco.com/docker-virtual/myapp:tag|artifactory.myco.com/docker-virtual/myapp:tag>",
  "registry_credentials": "{{ prefect.blocks.docker-registry-credentials.artifactory-prod }}"
}
# or
job_variables={"registry_credentials": DockerRegistryCredentials.load("artifactory-prod")}
Why A often works better here - The worker won’t call the Docker /auth endpoint at all — it just pulls and the daemon uses existing auth. - It matches your manual success path and avoids subtle differences in how docker-py formats login requests. If it still fails, can you share: - How your worker is running (host process vs container) - The exact
registry_url
in your block - The image string you’re pulling - The key shown under "auths" in
~/.docker/config.json
after
docker login
(just the server address) - Whether setting
reauth=False
changed anything For reference: - Prefect Docker integration reference - Docker worker login code (the worker only calls login if
registry_credentials
is set)