<@ULVA73B9P> when using the docker-compose deploym...
# ask-marvin
c
@Marvin when using the docker-compose deployment, how do you suggest building the worker?
m
thought for 365.3 seconds
Great question. In Prefect 3.x, the most reliable pattern is to run a “thin” Docker worker container built from the official Prefect image, with the Docker integration pre-installed, and connect it to your container runtime via the host socket. Since you’re on RHEL9 with Podman allowed and use Artifactory, here’s a setup I recommend. High-level approach - Build a minimal worker image FROM
prefecthq/prefect:3-python3.12
and install
prefect-docker
. - Run it via docker-compose (or podman-compose) and mount the Podman socket into the container. - Set
PREFECT_API_URL
to your Server/Cloud API and
DOCKER_HOST
to the mounted socket path. - Use Prefect’s Docker work pool and pass Artifactory credentials via job variables (preferred) or mount a Docker config. 1) Create a Docker work pool (once)
Copy code
prefect work-pool create my-docker-pool --type docker
2) Worker Dockerfile This bakes the docker integration so the container starts instantly without pip at runtime.
Copy code
# Dockerfile.worker
FROM prefecthq/prefect:3-python3.12

# Install the Docker integration for Prefect 3
RUN pip install --no-cache-dir prefect-docker

# Optional: pin versions or install any org-wide utilities here

# Default command can be overridden in compose
CMD ["prefect", "worker", "start", "--pool", "my-docker-pool"]
3) docker-compose.yml (with Podman socket on RHEL) If you’re also running Prefect Server in the same compose stack, include it; otherwise just run the worker service and point
PREFECT_API_URL
at your existing API.
Copy code
version: "3.9"

services:
  # Optional: only needed if you want to run Prefect Server in the same stack
  prefect-server:
    image: prefecthq/prefect:3-python3.12
    command: prefect server start --host 0.0.0.0
    environment:
      PREFECT_SERVER_API_HOST: 0.0.0.0
    ports:
      - "4200:4200"
    volumes:
      - prefect-server-data:/root/.prefect
    restart: unless-stopped

  prefect-worker:
    build:
      context: .
      dockerfile: Dockerfile.worker
    depends_on:
      - prefect-server
    environment:
      # If using Prefect Server in this compose stack
      PREFECT_API_URL: <http://prefect-server:4200/api>
      # If using Prefect Cloud instead, set:
      # PREFECT_API_URL: <https://api.prefect.cloud/api/accounts/<acct>/workspaces/<ws>>
      # PREFECT_API_KEY: <your-key>

      # Point the Docker SDK inside the container at the mounted Podman socket
      DOCKER_HOST: unix:///var/run/docker.sock

      # Optional tuning
      # PREFECT_WORKER_QUERY_SECONDS: "15"
      # PREFECT_WORKER_PREFETCH_SECONDS: "0"
    command:
      - prefect
      - worker
      - start
      - --pool
      - my-docker-pool
    volumes:
      # Rootful Podman socket on RHEL
      - /run/podman/podman.sock:/var/run/docker.sock

      # Optional: allow automatic pulls from Artifactory using your local docker config
      # - ${HOME}/.docker/config.json:/root/.docker/config.json:ro
    restart: unless-stopped

volumes:
  prefect-server-data:
Notes for Podman on RHEL - Rootful Podman socket is typically at
/run/podman/podman.sock
. We map it to
/var/run/docker.sock
inside the container and set
DOCKER_HOST=unix:///var/run/docker.sock
. The Docker SDK will happily talk to Podman’s Docker-compatible API. - If you run Podman rootless, your socket may be at
/run/user/<uid>/podman/podman.sock
. Mapping that into the container is trickier; many teams use the rootful socket for workers to keep it simple. - Ensure the worker container user can access the socket (ownership/permissions). If you see “permission denied,” adjust the socket’s group/permissions or run the worker as a user/group that can access it. 4) Artifactory (private registry) options Preferred: set registry credentials in your deployment’s job variables so the worker can pull images for each flow run: ``` # prefect.yaml (excerpt for a deployment) deployments: - name: my-flow entrypoint: flows/my_flow.py:flow work_pool: my-docker-pool job_variables:
image: "artifactory.myco.com/my-repo/my-image:latest" image_pull_policy: "Always" registry_credentials: username: "{{ env.ARTIFACTORY_USER }}" password: "{{ env.ARTIFACTORY_PASSWORD }}" registry_url: "artifactory.myco.com"
Copy code
Alternative: mount your Docker config that already has `docker login <http://artifactory.myco.com|artifactory.myco.com>`:
- Add to compose: `~/.docker/config.json:/root/.docker/config.json:ro`
- The worker will use these credentials to pull your flow images.

5) Build and run
- Build the worker image and start:
docker compose up -d --build # or podman-compose up -d --build ``` 6) Deploy flows to the Docker work pool In Prefect 3.x, use
flow.from_source(...).deploy(...)
or
prefect deploy
with a recipe. Ensure your deployments reference the
my-docker-pool
and set
image
to your Artifactory image for flow runs. Why this pattern? - Keeps the worker image small and generic (no flow code baked in). - Uses Podman’s Docker-compatible API via the socket mount. - Cleanly supports private registries through Prefect’s
registry_credentials
or your Docker config. - Clear separation: worker orchestrates; each flow run image contains runtime deps. Docs for reference - Docker worker and job variables: Docker worker guide - Self-hosted with docker-compose: Self-hosted docker-compose - Docker integration package: prefect-docker integration - Work pools and workers: Workers concept Quick check - Does your environment use Prefect Cloud or Prefect Server? - Will you run the worker against Podman’s rootful socket at
/run/podman/podman.sock
? If rootless, we can adjust the compose to map the user socket instead.
n
@Marvin shouldnt need a custom dockerfile at all in the simplest case our dockerfile comes with uv as well so
image: prefecthq/prefect:3-latest
and
command: uv run prefect worker start ...
is the simplest thing to do
m
thought for 69.7 seconds
Totally agree — you don’t need a custom Dockerfile for the simplest case. The official Prefect image includes uv, so you can start a Docker worker by running Prefect with the docker extra at runtime. Minimal steps 1) Create a Docker work pool (once)
Copy code
prefect work-pool create my-docker-pool --type docker
2) docker-compose.yml (Podman on RHEL)
Copy code
version: "3.9"

services:
  prefect-worker:
    image: prefecthq/prefect:3-latest
    environment:
      # Point to your API (Server or Cloud)
      # For Server in the same network: <http://prefect-server:4200/api>
      PREFECT_API_URL: <http://prefect-server:4200/api>
      # Point Docker SDK to the Podman socket mounted below
      DOCKER_HOST: unix:///var/run/docker.sock
    command:
      - uv
      - run
      - --with
      - prefect[docker]
      - prefect
      - worker
      - start
      - --pool
      - my-docker-pool
    volumes:
      # Podman socket (rootful)
      - /run/podman/podman.sock:/var/run/docker.sock
      # Optional: persist uv’s cache so extras aren’t re-fetched on every restart
      - /root/.cache/uv:/root/.cache/uv
      # Optional: use your Docker config for Artifactory pulls
      # - ${HOME}/.docker/config.json:/root/.docker/config.json:ro
    restart: unless-stopped
Notes - For Prefect Cloud, set
PREFECT_API_URL
to your workspace URL and add
PREFECT_API_KEY
. - If you run Podman rootless, your socket may be at
/run/user/<uid>/podman/podman.sock
— map that instead and keep
DOCKER_HOST=unix:///var/run/docker.sock
inside the container. - Ensure the container user can access the socket (permissions/group). - For Artifactory pulls, either mount a
config.json
as above or set
registry_credentials
in your deployment’s job variables. Docs - Docker worker how-to: Docker worker guide - Self-hosted with docker-compose: Self-hosted docker-compose - Docker integration: prefect-docker integration If you want, I can tailor the compose snippet with your actual API URL and whether you’re using rootful or rootless Podman.