Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0e43e0f
Dockerfile: better multi-layer caching, return to gunicorn
Louwrensth Sep 11, 2026
3f9597b
docker-compose: only need to build image once
Louwrensth Sep 11, 2026
cd4970a
gunicorn: expose access and error logs to stdout
Louwrensth Sep 15, 2026
c2cbe1f
docker: uv sync --no-build for dependencies
Louwrensth Sep 16, 2026
51cad9a
pyproject: bump flask-mail>=0.10.0
Louwrensth Sep 16, 2026
27e82ac
.gitignore: add common data folders
Louwrensth Sep 18, 2026
f888889
scripts/simdb{,_server}: remove redundant scripts
Louwrensth Sep 18, 2026
f613436
deps: drop unused flask-mail
Louwrensth Sep 18, 2026
f3b46a5
docker: remove docker-compose-pyver.yml
Louwrensth Sep 18, 2026
4475eb6
.gitignore, .dockerignore: cleanup
Louwrensth Sep 18, 2026
b687b99
add gunicorn.conf.py
Louwrensth Sep 21, 2026
220bbb9
simdb instance: move nginx.dev.conf to docker/
Louwrensth Sep 21, 2026
cc9b189
phase out legacy SysV init examples and docs
Louwrensth Sep 21, 2026
8c4adb9
docker: pin base image tags
Louwrensth Sep 22, 2026
39e1c36
docker-compose.yaml: bugfix postgres initdb issue
Louwrensth Sep 22, 2026
9b8d21e
Dockerfile: setuptools tweak
Louwrensth Sep 22, 2026
dff1797
Dockerfile: multi-stage build + server
Louwrensth Sep 22, 2026
54cfabe
Dockerfile: add validation stage
Louwrensth Sep 22, 2026
2076fbb
Dockerfile: uv sync --no-dev only,
Louwrensth Sep 22, 2026
f8f05d9
Dockerfile: non-root user
Louwrensth Sep 22, 2026
f0145b5
cache.py: add TODO remove hard-coded config_file path
Louwrensth Sep 22, 2026
ae5523c
simdb.cfg: add cache.type=SimpleCache
Louwrensth Sep 22, 2026
d01caa8
ci: add docker_image.yml
Louwrensth Sep 23, 2026
88b48f2
stub-add
Louwrensth Sep 24, 2026
f71c379
systemd: add compose layer and service files
Louwrensth Sep 24, 2026
30c4d6e
systemd: add Makefile.systemd for easy deployment
Louwrensth Sep 24, 2026
e198a38
systemd: can run locally build image
Louwrensth Sep 24, 2026
962323b
systemd: move Makefile, add docs
Louwrensth Sep 30, 2026
85be298
docker: do not mount gunicorn.conf.py
Louwrensth Sep 30, 2026
23a0424
docker, ci and docs: make consistent, simplify and trim unused code
Louwrensth Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.git
.github
.gitattributes
.gitignore
.gitlab-ci.yml
.venv
.pytest_cache
.coverage
**/__pycache__
**/*.pyc
**/*.egg-info
*.log
docs/
tests/
ci/
Dockerfile
Dockerfile.dev
docker-compose*.yml
/sims
/upload_folder
115 changes: 115 additions & 0 deletions .github/workflows/docker_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Docker Image build and publish

# Triggers and action summary:
# pull-request -> ignored in this GHA, linting and testing done elsewhere.
# push develop -> build and push image tagged :<version> and :develop.
# push main -> build and push image tagged :latest.
# push tag -> build and push image tagged :<version>.

env:
CACHE_FROM: type=gha,scope=simdb-server
CACHE_TO: type=gha,mode=max,scope=simdb-server
SETUPTOOLS_SCM_OVERRIDES_FOR_IMAS_SIMDB: '{local_scheme = "no-local-version-strict"}'

on:
push:
branches: [ "develop", "main" ]
tags: [ "*" ]

# Serialize runs per ref, so that two merges in quick succession can't race to
# move the "develop" image tag backward. The running job is never cancelled;
# GitHub does however keep only the newest *pending* run per group, so a third
# queued run supersedes the second.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
build-and-publish:
name: Build and publish
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-tags: true
fetch-depth: 0

- name: Get version
id: version
run: |
# A commit between tags describes as "<tag>-<n>-g<sha>", turned into the
# PEP 440 version "<tag>.dev<n>+g<sha>"; a commit on a tag describes as
# just "<tag>" and is used as is.
VERSION=$(git describe --tags --always | sed -r 's/-([0-9]+)-g([0-9a-f]+)$/.dev\1+g\2/')
# A Docker tag allows only [A-Za-z0-9_.-], so drop the '+' local segment
# for the image tag. That is the version setuptools-scm bakes into the
# image (local_scheme = no-local-version-strict), so the tag and
# "simdb --version" agree.
echo "value=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag_value=${VERSION%%+*}" >> "$GITHUB_OUTPUT"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Build build image
uses: docker/build-push-action@v7
with:
target: build
load: true
tags: simdb-server:build
build-args: APP_VERSION=${{ steps.version.outputs.value }}
cache-from: ${{ env.CACHE_FROM }}
cache-to: ${{ env.CACHE_TO }}

- name: Build service image
uses: docker/build-push-action@v7
with:
target: service
load: true
tags: simdb-server:service
build-args: APP_VERSION=${{ steps.version.outputs.value }}
cache-from: ${{ env.CACHE_FROM }}
cache-to: ${{ env.CACHE_TO }}

- name: Lowercase repo-owner
id: repo_owner
run: echo "value=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT"

- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ steps.repo_owner.outputs.value }}
password: ${{ secrets.GITHUB_TOKEN }}

# Versioned tag: develop pushes and any tag push. main is excluded -- it
# follows develop and only publishes :latest.
- name: Tag and push service image with version tag
if: ${{ github.ref_type == 'tag' || github.ref_name == 'develop' }}
run: |
docker tag \
simdb-server:service \
ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:${{ steps.version.outputs.tag_value }}
docker push ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:${{ steps.version.outputs.tag_value }}

# Run on develop pushes only
- name: Tag image :develop and publish
if: ${{ github.ref_type == 'branch' && github.ref_name == 'develop' }}
run: |
docker tag \
simdb-server:service \
ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:develop
docker push ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:develop

# Run on main pushes only
- name: Tag image :latest and publish
if: ${{ github.ref_type == 'branch' && github.ref_name == 'main' }}
run: |
docker tag \
simdb-server:service \
ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:latest
docker push ghcr.io/${{ steps.repo_owner.outputs.value }}/simdb-server:latest
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ environment.yml
git_update
runtests
sdb
src/simdb/cli/runtests
src/simdb.egg-info
test.yml
test4_manifest.yml
test7_manifest.yml
Expand All @@ -31,3 +29,5 @@ src/simdb/_version.py
*.egg-info
*.egg
*.whl
/sims
/upload_folder
72 changes: 65 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
ARG PYVER=3.12
FROM ghcr.io/astral-sh/uv:python${PYVER}-trixie-slim
# Build stage: Install dependencies and prepare the application
FROM ghcr.io/astral-sh/uv:0.12.17-python3.12-trixie-slim@sha256:9a59bb7206905ccaae4f7dab222fbac47c125a21e5fc16f43f427cd6c940ade3 \
AS build

ENV UV_NO_DEV=1
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0
ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

Expand All @@ -14,11 +16,67 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libmagic1 \
&& rm -rf /var/lib/apt/lists/*

COPY uv.lock pyproject.toml alembic.ini ./
# Install dependencies in their own layer, cached independently.
COPY uv.lock pyproject.toml ./
RUN uv sync --locked --no-dev --no-install-project --no-build --extra all

ARG APP_VERSION=0.0.0

# Add the project source and finish the sync.
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_IMAS_SIMDB="${APP_VERSION}"
COPY alembic.ini ./
COPY docker/gunicorn.conf.py ./docker/gunicorn.conf.py
COPY src/ ./src/
RUN uv sync --locked --extra all
RUN uv sync --locked --no-dev --extra all

ENV SIMDB_SITE_CONFIG_PATH=/app/config/simdb.cfg

# Runtime stage: Minimal image with only runtime dependencies
FROM ghcr.io/astral-sh/uv:0.12.17-python3.12-trixie-slim@sha256:9a59bb7206905ccaae4f7dab222fbac47c125a21e5fc16f43f427cd6c940ade3 \
AS service

ARG APP_UID=1000
ARG APP_GID=1000

ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

# Install only runtime dependencies (no build-essential, no *-dev variants, etc.)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
libldap2 \
libsasl2-2 \
libmagic1 \
&& rm -rf /var/lib/apt/lists/*

RUN groupadd --gid ${APP_GID} simdb \
&& useradd --uid ${APP_UID} --gid ${APP_GID} --create-home --shell /usr/sbin/nologin simdb \
&& mkdir -p /data/simdb/simulations /home/simdb/.gunicorn \
&& chown -R simdb:simdb /data/simdb /home/simdb /app

# Copy the prepared application and dependencies from build stage
COPY --from=build --chown=simdb:simdb /app/.venv /app/.venv
COPY --from=build --chown=simdb:simdb /app/alembic.ini ./
COPY --from=build --chown=simdb:simdb /app/docker/gunicorn.conf.py ./docker/gunicorn.conf.py
COPY --from=build --chown=simdb:simdb /app/src/ ./src/

ARG APP_VERSION=0.0.0

LABEL org.opencontainers.image.title="SimDB" \
org.opencontainers.image.description="SimDB Server — ITER simulation management tool" \
org.opencontainers.image.source="https://github.com/iterorganization/SimDB" \
org.opencontainers.image.licenses="LGPL-3.0-only" \
org.opencontainers.image.version="${APP_VERSION}" \
io.simdb.component="server"

ENV SIMDB_SITE_CONFIG_PATH=/app/config/simdb.cfg

CMD ["uv", "run", "simdb_server"]
USER simdb

EXPOSE 5000

# Run under Gunicorn rather than the Werkzeug dev server
CMD ["uv", "run", "gunicorn", "--config=/app/docker/gunicorn.conf.py", "simdb.remote.wsgi:app"]
40 changes: 26 additions & 14 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
ARG PYVER=3.12
FROM ghcr.io/astral-sh/uv:python${PYVER}-trixie-slim

ENV UV_LINK_MODE=copy \
PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
libldap2-dev \
libsasl2-dev \
libmagic1 \
&& rm -rf /var/lib/apt/lists/*

# Install dependencies in their own layer, cached independently.
COPY uv.lock pyproject.toml ./
RUN uv sync --locked --no-dev --no-install-project --no-build --extra all

# Add the project source and finish the sync.
ARG APP_VERSION=0.0.0
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_IMAS_SIMDB="${APP_VERSION}"

ARG SIMDB_GIT_BRANCH=unknown
ARG SIMDB_GIT_COMMIT=unknown
ARG SIMDB_DEPLOYMENT=local
Expand All @@ -9,26 +30,17 @@ LABEL org.simdb.deployment="${SIMDB_DEPLOYMENT}" \
org.simdb.git.branch="${SIMDB_GIT_BRANCH}" \
org.simdb.git.commit="${SIMDB_GIT_COMMIT}"

ENV UV_NO_DEV=1
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0

ENV SIMDB_DEPLOYMENT="${SIMDB_DEPLOYMENT}"
ENV SIMDB_GIT_BRANCH="${SIMDB_GIT_BRANCH}"
ENV SIMDB_GIT_COMMIT="${SIMDB_GIT_COMMIT}"

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
libldap2-dev \
libsasl2-dev \
libmagic1 \
&& rm -rf /var/lib/apt/lists/*

COPY uv.lock pyproject.toml alembic.ini ./
COPY alembic.ini ./
COPY src/ ./src/
RUN uv sync --locked --extra all
RUN uv sync --locked --no-dev --extra all

ENV SIMDB_SITE_CONFIG_PATH=/app/config/simdb.cfg

EXPOSE 5000

CMD ["uv", "run", "simdb_server"]
Loading
Loading