Conductor OSS workflow engine with UI. Non-root, multi-arch, signed, SBOM.
439
Multi-arch (amd64, arm64), signed container images for Conductor OSS, the open-source workflow orchestration engine originally built at Netflix. Server and UI in one image.
Community-maintained by upstreamyard. This is not an official Conductor image. Conductor is © its authors and licensed under Apache-2.0 (license text in
/licenses/conductor/LICENSEinside the image).
| Registry | Image |
|---|---|
| Docker Hub | upstreamyard/conductor |
| GitHub Container Registry | ghcr.io/upstreamyard/conductor |
Tags: latest, <major>.<minor> (e.g. 3.32), <version> (e.g. 3.32.5, matching the Conductor releases). Only stable releases are built: release candidates (-rc) never get a tag here, and latest always points to the newest stable release. New releases are built automatically within 24 hours.
| Ports | 8080 API and Swagger UI (/swagger-ui/index.html), 5000 UI (nginx, proxies /api to the server) |
| Health | GET /health on 8080. It reports the process only, not the database |
| Metrics | GET /actuator/prometheus on 8080 |
| Requires | nothing for a quick trial (built-in SQLite). For production: PostgreSQL (tested with postgres:16), or one of Conductor's other backends |
| Runs as | non-root UID 10001 |
| Migrations | automatic on startup |
| Default auth | none. Anyone who can reach ports 8080 or 5000 can create and run workflows |
AI agents and coding assistants: read AGENTS.md for deployment rules, and llms.txt for an index of all docs.
Try it without any dependencies (data is stored in SQLite inside the container and lost when it is removed):
docker run -d -p 8080:8080 -p 5000:5000 upstreamyard/conductor:latest
curl http://localhost:8080/health
Open the UI at http://localhost:5000 and the API docs at http://localhost:8080/swagger-ui/index.html.
With PostgreSQL, using our Compose file:
curl -O https://raw.githubusercontent.com/upstreamyard/conductor/main/docker-compose.yml
docker compose up -d
Your workers (your own code, in any language with a Conductor SDK) connect to http://<host>:8080/api.
Conductor is a Spring Boot application, so every property can be set as an environment variable: upper-case, with . and - replaced by _ (conductor.db.type becomes CONDUCTOR_DB_TYPE). PostgreSQL for persistence, queues and search:
docker run -d -p 8080:8080 -p 5000:5000 \
-e CONDUCTOR_DB_TYPE=postgres \
-e CONDUCTOR_QUEUE_TYPE=postgres \
-e CONDUCTOR_INDEXING_ENABLED=true \
-e CONDUCTOR_INDEXING_TYPE=postgres \
-e CONDUCTOR_ELASTICSEARCH_VERSION=0 \
-e CONDUCTOR_EXTERNAL_PAYLOAD_STORAGE_TYPE=postgres \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://your-postgres:5432/conductor \
-e SPRING_DATASOURCE_USERNAME=conductor \
-e SPRING_DATASOURCE_PASSWORD=... \
upstreamyard/conductor:latest
CONFIG_PROP)As in the Conductor project's own image (conductoross/conductor), CONFIG_PROP selects a properties file in /app/config. Mount your own file there:
docker run -d -p 8080:8080 -p 5000:5000 \
-v ./conductor.properties:/app/config/conductor.properties:ro \
-e CONFIG_PROP=conductor.properties \
upstreamyard/conductor:latest
The image also contains the Conductor project's example files (config-postgres.properties, config-redis-os.properties, …). They expect the host names from the Conductor project's Compose files (postgresdb, rs, os) and default passwords, so for real deployments use your own file or environment variables.
Two things to know (both tested):
CONFIG_PROP are loaded as Java system properties, which take precedence. Don't set the same property in both places./app/config/$CONFIG_PROP doesn't exist, the container exits with ERROR: CONFIG_PROP=..., but /app/config/... does not exist. The Conductor project's own image instead starts silently with the built-in SQLite defaults, which ignores your database.| Variable | Default in image | Notes |
|---|---|---|
CONFIG_PROP | – | Properties file name in /app/config |
JAVA_OPTS | empty | JVM options, e.g. -Xmx2g or -XX:MaxRAMPercentage=75 |
SERVER_PORT | 8080 | The UI on 5000 proxies to localhost:8080, so keep the default if you use the UI |
OPENAI_API_KEY, ANTHROPIC_API_KEY, … | – | Optional keys for Conductor's LLM tasks. Without them the server logs cannot init ... model errors at startup. These are harmless |
All properties and their defaults: the Conductor project's application.properties. Like the Conductor project's own image, the server is built with the Elasticsearch 7 client. OpenSearch and Elasticsearch 8 need a different build of the server and aren't included. Tested here: SQLite (default) and PostgreSQL for persistence, queues and indexing.
A Helm chart for this image is in preparation in upstreamyard/helm-charts. Until then, the facts you need for your own manifests:
10001 and works with runAsNonRoot: true.GET /health on port 8080 for liveness and readiness. It doesn't check the database.local_only, also in the Conductor project's PostgreSQL example config, so several replicas aren't safe without a distributed lock. Multi-replica setups will be tested and documented with the Helm chart.SPRING_DATASOURCE_PASSWORD), not in a config file.Images are signed keylessly with cosign and include an SBOM and SLSA provenance:
cosign verify upstreamyard/conductor:latest \
--certificate-identity-regexp '^https://github.com/upstreamyard/conductor/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
docker buildx imagetools inspect upstreamyard/conductor:latest --format '{{ json .SBOM }}'
.github/workflows/build.yml checks out the Conductor release tag and builds Dockerfile with the same Gradle command as the Conductor project's release workflow. Before publishing, scripts/smoke-test.sh runs on native amd64 and arm64 runners. It starts the image against PostgreSQL, runs a workflow end to end, checks the UI and its /api proxy, and checks that a missing config file is rejected. Nothing is published unless both architectures pass. Everything is public and reproducible.
Same layout as the Conductor project's own image conductoross/conductor (docker/server/Dockerfile): server on 8080, nginx with the UI on 5000, CONFIG_PROP, files under /app. The differences:
10001 instead of root;tini as PID 1, and Java gets stop signals, so docker stop shuts down cleanly instead of being killed after the timeout;/app/logs/server.log);CONFIG_PROP file that doesn't exist stops the container with an error, instead of falling back to SQLite;debian:stable-slim;latest sometimes points to an RC.Issues with the image: open an issue here. Issues with Conductor itself: conductor-oss/conductor.
Content type
Image
Digest
sha256:3fa99b195…
Size
403.2 MB
Last updated
1 day ago
docker pull upstreamyard/conductor