Sign inSign up

upstreamyard/conductor

By upstreamyard

•Updated 1 day ago

Conductor OSS workflow engine with UI. Non-root, multi-arch, signed, SBOM.

Image
Integration & delivery
Machine learning & AI
0

439

upstreamyard/conductor repository overview

upstreamyard logo

⁠Conductor container image

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/LICENSE inside the image).

RegistryImage
Docker Hubupstreamyard/conductor
GitHub Container Registryghcr.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.

⁠At a glance

Ports8080 API and Swagger UI (/swagger-ui/index.html), 5000 UI (nginx, proxies /api to the server)
HealthGET /health on 8080. It reports the process only, not the database
MetricsGET /actuator/prometheus on 8080
Requiresnothing for a quick trial (built-in SQLite). For production: PostgreSQL (tested with postgres:16), or one of Conductor's other backends
Runs asnon-root UID 10001
Migrationsautomatic on startup
Default authnone. 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.

⁠Quick start

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.

⁠Configuration

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 files (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):

  • The config file wins over environment variables. This is how Conductor itself works: values from CONFIG_PROP are loaded as Java system properties, which take precedence. Don't set the same property in both places.
  • A missing file stops the container. If /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.
⁠Other settings
VariableDefault in imageNotes
CONFIG_PROP–Properties file name in /app/config
JAVA_OPTSemptyJVM options, e.g. -Xmx2g or -XX:MaxRAMPercentage=75
SERVER_PORT8080The 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.

⁠Kubernetes

A Helm chart for this image is in preparation in upstreamyard/helm-charts⁠. Until then, the facts you need for your own manifests:

  • The container runs as non-root UID 10001 and works with runAsNonRoot: true.
  • Use GET /health on port 8080 for liveness and readiness. It doesn't check the database.
  • Run one replica for now. Conductor's default workflow lock is 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.
  • Pass passwords as environment variables from a Secret (SPRING_DATASOURCE_PASSWORD), not in a config file.

⁠Verifying images

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 }}'

⁠How it's built

.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:

  • runs as non-root UID 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;
  • logs go to stdout only (the Conductor project's image also writes /app/logs/server.log);
  • a CONFIG_PROP file that doesn't exist stops the container with an error, instead of falling back to SQLite;
  • base images pinned by digest instead of debian:stable-slim;
  • release candidates are never tagged. The Conductor project's latest sometimes points to an RC.

⁠Support

Issues with the image: open an issue here⁠. Issues with Conductor itself: conductor-oss/conductor⁠.

Tag summary

Content type

Image

Digest

sha256:3fa99b195…

Size

403.2 MB

Last updated

1 day ago

docker pull upstreamyard/conductor