Run a solution with Docker Compose#
SAF solutions can run as containerized services using Docker Compose. Every SAF solution generated via
saf new includes pre-configured Compose files in the deployments/ directory:
deployments/
├── standalone/
│ └── compose.yaml # Solution only
├── standalone-with-hps/
│ └── compose.yaml # Solution + HPS
├── external/
│ └── compose.yaml # Solution using pre-built images
└── distributed-deployment-template/
└── compose.yaml # Solution + HPS + Web Portal
The standalone, standalone-with-HPS, and distributed deployments build solution images locally from
deployments/Dockerfile. The external deployment uses pre-built solution images instead, so the
deployment machine does not need access to the Python package sources used to build those images.
Container deployment prerequisites#
Prerequisite |
Description |
|---|---|
WSL (Windows only) |
|
Virtualization |
Docker Desktop (requires a license) or Docker Engine (open-source) |
Environment variables |
Set |
Standalone deployment#
Purpose:
Development and testing environment for the solution in isolation.
Description:
The standalone deployment is designed for developers to verify that the solution works properly in containerized mode. It starts only the core services of the solution without external dependencies.
Services included:
PostgreSQL database
Solution REST API (SAF GLOW)
Solution UI (Dash framework, if configured)
OpenTelemetry dashboard for observability
Usage:
This deployment is not meant for production but is ideal for:
Developing and testing solutions locally
Verifying solution functionality in containers
Debugging solution-specific issues
Run the solution#
Navigate to the solution root directory.
Start the services (wait for all services to start):
docker compose -f deployments/standalone/compose.yaml up --build
Open a web page and reach the GLOW API Swagger UI:
http://localhost:8000/docsCreate a project using the
Create ProjectPOST request.Copy the project name from the response. It should look like:
projects/<project-id>Open the Solution UI:
http://localhost:8001/projects/<project-id>
Now you can walk through the solution workflow.
Shut down the solution#
To shut down the solution:
Press CTRL+C in the terminal where you executed the previous Docker command, or
Turn the Docker containers down:
docker compose -f deployments/standalone/compose.yaml down
Standalone deployment with HPS#
Purpose:
Development environment that includes HPS (HPC Platform Services) integration.
Description:
This deployment extends the standalone setup by adding HPS components to the landscape. It helps developers debug the connection between HPS and SAF.
Services included:
All services from standalone deployment
Integration with external HPS network
Traefik labels for external routing
Prerequisites:
HPS must be started first and running.
EXT_NETWORK_NAMEenvironment variable must be set to match the HPS external network.
Usage:
This deployment is not meant for production but is ideal for:
Testing HPS integration
Debugging communication between SAF and HPS
Validating solution behavior with HPS services
Run the solution#
Ensure that HPS is running.
Set the external network name:
export EXT_NETWORK_NAME=<hps-network-name>
Navigate to the solution root directory.
Start the services (wait for all services to start):
docker compose -f deployments/standalone-with-hps/compose.yaml up --build
Access the solution API and UI as described in the Standalone deployment instructions (points 3 to 6).
Shut down the solution#
Press CTRL+C in the terminal where you executed the previous Docker command, or
Turn the Docker containers down:
docker compose -f deployments/standalone-with-hps/compose.yaml down
External deployment with pre-built images#
Use the external deployment to run a solution without building its API and UI images on the deployment machine. It provides the same core services as the standalone deployment: PostgreSQL, the solution API, the optional solution UI, and an OpenTelemetry dashboard.
Build and download the images#
The generated solution includes a build solution images GitHub Actions workflow in
.github/workflows/build-image.yml. It builds the solution_api Dockerfile target and, when a UI
is configured, the solution_ui target. It saves the images into a single tar file and uploads that
file as a workflow artifact.
The workflow also runs as part of the generated solution’s build and release workflow through a
reusable workflow call, using the default image tag main. To build images manually with another tag:
Open the generated solution repository on GitHub and select the Actions tab.
Select build solution images, then Run workflow.
Select the branch to build and set
image_tagto a valid Docker image tag, such as1.1.0. The default ismain.After the workflow succeeds, download the
<APP_NAME>-images-<tag>artifact from the workflow run summary and extract its ZIP archive. It contains<APP_NAME>-images-<tag>.tar. Artifacts are retained for 30 days.
The tar file contains <APP_NAME>-api:<tag> and, when applicable, <APP_NAME>-ui:<tag>.
APP_NAME is the Docker name generated for the solution.
Note
The tar file contains only the solution images. PostgreSQL and the OpenTelemetry dashboard use
separate images referenced in deployments/external/compose.yaml. Docker may pull these images
when starting the deployment. For an offline deployment, these images must also be available on
the deployment machine.
Load and run the solution#
Transfer the image tar file and the generated
deployments/external/directory, including its.envfile, to the deployment machine.Load the images into the Docker engine that will run the solution. Replace the placeholders with the downloaded file’s name:
docker load -i <APP_NAME>-images-<tag>.tar
In
deployments/external/.env, ensure thatAPP_NAMEmatches the loaded images’ name andAPP_IMAGE_VERSIONmatches their tag. For example:APP_NAME=my-solution_1-1-0 APP_IMAGE_VERSION=1.1.0
Configure the other deployment settings as needed. Before sharing or deploying the solution, replace the placeholder OpenTelemetry API key in both
.envandcompose.yamlwith the same secure value.Navigate to the external deployment directory and start the services:
cd deployments/external docker compose up -d --wait
Access the API at
http://localhost:8000/docsand, when configured, the UI athttp://localhost:8001/projects/<project-id>. Create a project through the API first, as described in Run the solution. These URLs use the default ports from.env.
The API and UI services use pull_policy: never and have no build configuration. If a solution
image is missing or its name or tag does not match .env, startup fails instead of pulling or
building a replacement.
To stop the services, run the following command from deployments/external/:
docker compose down
Platform-specific dependencies configuration#
The deployments/Dockerfile supports platform-specific dependencies using Poetry extras and build arguments.
How to use:
By default, the Dockerfile installs only the base dependencies.
To install platform-specific dependencies (for example: HPS, Minerva, Dash), pass the
EXTRASbuild argument when building the container, separated by commas.
Examples:
docker compose build --build-arg EXTRAS="hps,pim,minerva"
solution-api:
build:
context: ../../
dockerfile: deployments/Docker/Dockerfile
args:
EXTRAS: "hps,pim,minerva"
Development workflow#
For development deployments configured with Docker Compose watch mode, use:
docker compose up --build --watch
This automatically syncs and restarts containers when you modify source files in the solution/ or ui/
directories.
The external deployment runs pre-built images and does not configure source synchronization or rebuilding. To apply source changes, build and load new images instead.
Stop services#
To stop and remove all containers:
docker compose down
To also remove persistent volumes (database data, project files):
docker compose down -v
Release a new solution version#
When you release a new version of an existing solution, two files must be updated — no changes to the Compose files themselves are required.
Update
pyproject.toml:Bump the
versionfield in your solution’spyproject.tomlto the new release version:[tool.poetry] name = "my-solution" version = "1.1.0" # <-- update this
Update the
.envfile for each deployment template:Each deployment template has its own
.envfile, as shown in the following table. UpdateAPP_NAMEin every.envfile you intend to use.Comparison of deployment template environment files# Deployment template
Path to the
.envfileStandalone
deployments/standalone/.envStandalone with HPS
deployments/standalone-with-hps/.envDistributed deployment
deployments/distributed-deployment-template/.envExternal deployment
deployments/external/.envNote
- The
APP_NAMEshould follow the same pattern as the value generated bysaf new: <solution-package-name>_<version-with-dashes>. The version is taken frompyproject.toml, with dots replaced by dashes (for example,1.1.0becomes1-1-0).
In each of those files, update
APP_NAMEto reflect the new version:# Docker resource name (derived from the pyproject.toml version; replace dots with dashes) APP_NAME=my-solution_1-1-0
Note
The
APP_NAMEenvironment variable is used to name all Docker resources (networks, volumes, and images such as${APP_NAME}-apiand${APP_NAME}-ui). Embedding the version inAPP_NAMEensures that each release produces uniquely tagged artefacts and avoids conflicts with previously deployed containers.- The
Update the images and restart the services:
For deployments that build locally, rebuild the images and restart the services:
docker compose -f deployments/<template>/compose.yaml up --build
For the external deployment, build and download new images as described in External deployment with pre-built images. Load the new tar file, match
APP_NAMEandAPP_IMAGE_VERSIONindeployments/external/.envto the loaded images, and restart fromdeployments/external/:docker compose up -d --wait
Changing
pyproject.tomlor.envalone does not update pre-built images.