From 9930649205b10b0e55c70402deaeac5ed4d43fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20ceylan?= Date: Fri, 14 Aug 2026 13:09:23 +0300 Subject: [PATCH 1/2] Add containerised deployment for the Streamlit dashboard Adds the files needed to run dashboard.py on Asimov, alongside the lab's other web projects. Nothing existing is modified. The deployment is driven by kafka-cluster-ansible, which clones the repo as the webuser account and runs ./deploy.sh. That script builds the image and starts the container on the shared bittremieuxlab-public network, where nginx reaches it by service name and serves it at denovobenchmarks.bittremieuxlab.org. Dependencies are pinned in a separate requirements-dashboard.txt rather than the root requirements.txt, which targets the benchmarking pipeline. Streamlit Community Cloud installed streamlit automatically and pulled in pandas as one of its dependencies, so neither was previously listed; a container image gets no such treatment and both must be explicit. The pins mean dashboard dependencies now need deliberate upgrades instead of arriving automatically. results/ is copied into the image at build time, so refreshed benchmark results reach the dashboard by committing them and redeploying. .dockerignore keeps the pipeline out of the build context (sample_data, algorithms, evaluation, tests), reducing it from ~370 MB to ~47 MB. Co-Authored-By: Claude Opus 5 (1M context) --- .dockerignore | 44 ++++++++++++++++++++++++++++++++++ Dockerfile | 26 ++++++++++++++++++++ deploy.sh | 7 ++++++ docker-compose.deployment.yaml | 33 +++++++++++++++++++++++++ requirements-dashboard.txt | 13 ++++++++++ 5 files changed, 123 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100755 deploy.sh create mode 100644 docker-compose.deployment.yaml create mode 100644 requirements-dashboard.txt diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..33373d9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,44 @@ +# Keep the build context small. The dashboard needs dashboard.py, +# datasets_info.py and results/ — everything below belongs to the benchmarking +# pipeline, which does not run in this image. +# +# Without this file the context is ~370 MB; with it, ~47 MB. + +.git +.github +.devcontainer + +# Benchmarking pipeline: Apptainer definitions, demo spectra, evaluation code +algorithms/ +sample_data/ +evaluation/ +tests/ +evaluation.def + +# Pipeline entrypoints and helpers +run.sh +run_dataset.sh +run_split.sh +run_test.sh +build_apptainer_images.sh +augment_predictions.sh +create_dataset.py +dataset_utils.py +dataset_config.py +update_tags.py +test_output_format.py + +# Deployment files themselves are not needed inside the image +Dockerfile +.dockerignore +docker-compose.deployment.yaml +deploy.sh + +# Local/editor cruft +__pycache__/ +*.py[cod] +.venv/ +venv/ +.env +.env.template +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e8bbeee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Streamlit dashboard for the de novo benchmarking results. +# +# Only the dashboard runs here. The benchmarking pipeline itself needs Apptainer +# and GPUs and is excluded from the build context via .dockerignore. + +FROM python:3.12-slim + +WORKDIR /app + +# curl is needed by the container healthcheck +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + && rm -rf /var/lib/apt/lists/* + +COPY ./requirements-dashboard.txt /app/requirements-dashboard.txt + +RUN pip3 install --no-cache-dir -r requirements-dashboard.txt + +# Brings in dashboard.py, datasets_info.py and results/ +COPY . /app + +EXPOSE 8501 + +HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health + +ENTRYPOINT ["streamlit", "run", "dashboard.py", "--server.port=8501", "--server.address=0.0.0.0"] diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..97475de --- /dev/null +++ b/deploy.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Build images +docker compose -f docker-compose.deployment.yaml build + +# Start services +docker compose -f docker-compose.deployment.yaml up -d diff --git a/docker-compose.deployment.yaml b/docker-compose.deployment.yaml new file mode 100644 index 0000000..6f3ac76 --- /dev/null +++ b/docker-compose.deployment.yaml @@ -0,0 +1,33 @@ +services: + denovo-benchmarks-streamlit-app: + build: + context: . + dockerfile: Dockerfile + image: bittremieuxlab/denovo-benchmarks-streamlit-app:latest + restart: unless-stopped + + # No host port is published: the reverse proxy reaches the container over + # the shared bittremieuxlab-public network. + expose: + - "8501" + + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:8501/_stcore/health"] + interval: 30s + timeout: 5s + retries: 3 + + environment: + STREAMLIT_SERVER_PORT: 8501 + STREAMLIT_SERVER_ADDRESS: 0.0.0.0 + STREAMLIT_SERVER_HEADLESS: "true" + STREAMLIT_SERVER_ENABLE_CORS: "false" + STREAMLIT_SERVER_ENABLE_XSRF_PROTECTION: "false" + TZ: Europe/Brussels + + networks: + - bittremieuxlab-public + +networks: + bittremieuxlab-public: + external: true diff --git a/requirements-dashboard.txt b/requirements-dashboard.txt new file mode 100644 index 0000000..f7ff8f6 --- /dev/null +++ b/requirements-dashboard.txt @@ -0,0 +1,13 @@ +# Dependencies for the Streamlit dashboard (dashboard.py) only. +# +# The root requirements.txt targets the benchmarking pipeline. On Streamlit +# Community Cloud, streamlit was installed automatically and pandas came in as +# one of its dependencies, so neither needed to be listed. A container image +# gets no such treatment, so both are pinned explicitly here. +# +# Versions are pinned so that rebuilds are reproducible: deploy.sh rebuilds the +# image on every deployment, and an unpinned dependency would let an unrelated +# deploy silently pull a breaking major version. Bump these deliberately. +streamlit==1.61.1 +pandas==3.0.5 +plotly==6.5.2 From 79b8e84387cae0904f06ebe7c9cd57478a425d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20ceylan?= Date: Fri, 14 Aug 2026 13:17:36 +0300 Subject: [PATCH 2/2] Keep Streamlit CORS and XSRF protection enabled These two overrides were carried over from the gnps-rdd deployment, which in turn appears to follow .devcontainer/devcontainer.json. Neither is needed here: verified behind nginx with both protections at their secure defaults, the dashboard renders and its websocket works normally. Removing them avoids disabling protections without a reason to. Co-Authored-By: Claude Opus 5 (1M context) --- docker-compose.deployment.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.deployment.yaml b/docker-compose.deployment.yaml index 6f3ac76..f01c7f5 100644 --- a/docker-compose.deployment.yaml +++ b/docker-compose.deployment.yaml @@ -21,8 +21,6 @@ services: STREAMLIT_SERVER_PORT: 8501 STREAMLIT_SERVER_ADDRESS: 0.0.0.0 STREAMLIT_SERVER_HEADLESS: "true" - STREAMLIT_SERVER_ENABLE_CORS: "false" - STREAMLIT_SERVER_ENABLE_XSRF_PROTECTION: "false" TZ: Europe/Brussels networks: