Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ARG PYVER=3.12
FROM ghcr.io/astral-sh/uv:python${PYVER}-trixie-slim

ARG SIMDB_GIT_BRANCH=unknown
ARG SIMDB_GIT_COMMIT=unknown
ARG SIMDB_DEPLOYMENT=local

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 src/ ./src/
COPY alembic/ ./alembic/
RUN uv sync --locked --extra all

ENV SIMDB_SITE_CONFIG_PATH=/app/config/simdb.cfg

CMD ["uv", "run", "simdb_server"]
23 changes: 23 additions & 0 deletions deploy/nginx.dev.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
server {
listen 80;
server_name _;
client_max_body_size 16m;

add_header X-SimDB-Deployment "${SIMDB_DEPLOYMENT}" always;
add_header X-SimDB-Branch "${SIMDB_GIT_BRANCH}" always;
add_header X-SimDB-Commit "${SIMDB_GIT_COMMIT}" always;
add_header X-SimDB-Deployed-At "${SIMDB_DEPLOYED_AT}" always;

location = /__simdb_instance {
default_type application/json;
return 200 '{"deployment":"${SIMDB_DEPLOYMENT}","git_branch":"${SIMDB_GIT_BRANCH}","git_commit":"${SIMDB_GIT_COMMIT}","deployed_at":"${SIMDB_DEPLOYED_AT}"}';
}

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://web:5000;
}
}
184 changes: 184 additions & 0 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
services:
migrations:
build:
context: .
dockerfile: Dockerfile.dev
args:
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
volumes:
- ./config:/app/config:ro
environment:
DATABASE_URL: postgresql+psycopg2://simdb:simdb@postgres:5432/simdb
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYED_AT: ${SIMDB_DEPLOYED_AT:-unknown}
depends_on:
postgres:
condition: service_healthy
command: uv run alembic upgrade head
restart: "no"

web:
build:
context: .
dockerfile: Dockerfile.dev
args:
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
environment:
IMAS_LOCAL_HOSTS: localhost
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYED_AT: ${SIMDB_DEPLOYED_AT:-unknown}
labels:
org.simdb.deployment: ${SIMDB_DEPLOYMENT:-local}
org.simdb.git.branch: ${SIMDB_GIT_BRANCH:-unknown}
org.simdb.git.commit: ${SIMDB_GIT_COMMIT:-unknown}
volumes:
- ./validation:/app/validation:ro
- ./config:/app/config:ro
- ./tmp/partition_data:/data/simdb/partition:ro
- upload_data:/data/simdb/simulations
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
migrations:
condition: service_completed_successfully
restart: unless-stopped
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://localhost:5000/', timeout=5)"
interval: 5s
timeout: 5s
retries: 12
start_period: 10s

proxy:
image: nginx:1.29-alpine
ports:
- "${SIMDB_WEB_PORT:-5100}:80"
environment:
NGINX_ENVSUBST_FILTER: ^SIMDB_
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYED_AT: ${SIMDB_DEPLOYED_AT:-unknown}
labels:
org.simdb.deployment: ${SIMDB_DEPLOYMENT:-local}
org.simdb.git.branch: ${SIMDB_GIT_BRANCH:-unknown}
org.simdb.git.commit: ${SIMDB_GIT_COMMIT:-unknown}
volumes:
- ./deploy/nginx.dev.conf.template:/etc/nginx/templates/default.conf.template:ro
depends_on:
web:
condition: service_healthy
restart: unless-stopped
healthcheck:
test:
- CMD
- wget
- --quiet
- --spider
- http://127.0.0.1/__simdb_instance
interval: 5s
timeout: 5s
retries: 12
start_period: 5s

worker:
profiles: [with_workers]
# docker compose --profile with_workers enables this service
build:
context: .
dockerfile: Dockerfile.dev
args:
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
command: uv run simdb_worker
environment:
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYED_AT: ${SIMDB_DEPLOYED_AT:-unknown}
volumes:
- ./config:/app/config:ro
- ./tmp/partition_data:/data/simdb/partition:ro
- upload_data:/data/simdb/simulations
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
migrations:
condition: service_completed_successfully
restart: unless-stopped

beat:
profiles: [with_workers]
# docker compose --profile with_workers enables this service
build:
context: .
dockerfile: Dockerfile.dev
args:
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
command: uv run simdb_beat
environment:
SIMDB_DEPLOYMENT: ${SIMDB_DEPLOYMENT:-local}
SIMDB_GIT_BRANCH: ${SIMDB_GIT_BRANCH:-unknown}
SIMDB_GIT_COMMIT: ${SIMDB_GIT_COMMIT:-unknown}
SIMDB_DEPLOYED_AT: ${SIMDB_DEPLOYED_AT:-unknown}
volumes:
- ./config:/app/config:ro
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
migrations:
condition: service_completed_successfully
restart: unless-stopped

redis:
image: redis:8-alpine
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 5s
retries: 5
restart: unless-stopped

postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=simdb
- POSTGRES_PASSWORD=simdb
- POSTGRES_DB=simdb
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U simdb -d simdb"]
interval: 2s
timeout: 5s
retries: 15
start_period: 30s
restart: unless-stopped

volumes:
redis_data:
postgres_data:
upload_data:
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ services:

web:
build: .
environment:
IMAS_LOCAL_HOSTS: localhost
ports:
- "5000:5000"
volumes:
Expand Down Expand Up @@ -91,4 +93,3 @@ services:
volumes:
redis_data:
postgres_data:

8 changes: 8 additions & 0 deletions docs/developer_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,11 @@ port = 5432
...
```

For isolated branch and pull-request deployments with separate PostgreSQL
and Redis volumes, see the
[multi-instance deployment guide](multi_instance_deployment.md).
The standard allocation is `main` on port 5000, `develop` on port 5100, and
pull requests on ports 5101-5999.
These instances use the development-only Docker and Compose files and expose
the branch identity at `/__simdb_instance`.
96 changes: 96 additions & 0 deletions docs/multi_instance_deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Running multiple SimDB server instances

Each deployment uses a dedicated Git worktree and Docker Compose project. Compose
project names isolate PostgreSQL, Redis, uploaded files, containers, and networks.
The management script only updates worktrees beneath `SIMDB_INSTANCE_ROOT`; it does
not modify the checkout from which it is invoked. All instances use
`docker-compose-dev.yml` and `Dockerfile.dev`; the production Compose and
Dockerfile are not used or modified.

## Requirements

- Docker with the Compose plugin
- Git access to the configured remote
- A clean source repository containing `scripts/simdb-instance`

The default instance directory is a sibling of the repository named
`simdb-instances`. Override it when required:

```bash
export SIMDB_INSTANCE_ROOT=/srv/simdb/instances
```

## Deploy environments

Keep `main` on port 5000 and `develop` on port 5100:

```bash
scripts/simdb-instance deploy-main
scripts/simdb-instance deploy-develop
```

Deploy a pull request. If no port is supplied, the first unused port in
5101-5999 is assigned:

```bash
scripts/simdb-instance deploy-pr 123
scripts/simdb-instance deploy-pr 124 --port 5124
```

Deploy any remote branch:

```bash
scripts/simdb-instance deploy-branch feature/query-cache
scripts/simdb-instance deploy-branch feature/query-cache \
--name query-cache --port 5200
```

Updating an existing instance preserves its assigned port and named volumes.
Tracked changes inside a managed worktree are discarded because these worktrees
are deployment artifacts. Untracked runtime files are preserved.

## Inspect and remove environments

```bash
scripts/simdb-instance list
scripts/simdb-instance status pr-123
scripts/simdb-instance logs pr-123
scripts/simdb-instance stop pr-123
```

`stop` preserves PostgreSQL, Redis, and uploaded data. `destroy` permanently
removes them along with the managed worktree:

```bash
scripts/simdb-instance destroy pr-123
```

## Verify the deployed revision

Open the development-only identity endpoint:

```bash
curl http://localhost:5100/__simdb_instance
```

It returns:

```json
{
"deployment": "pr-123",
"git_branch": "pull/123",
"git_commit": "81d992f...",
"deployed_at": "2026-06-24T10:00:00Z"
}
```

The development Nginx proxy also adds `X-SimDB-Deployment`,
`X-SimDB-Branch`, `X-SimDB-Commit`, and `X-SimDB-Deployed-At` to every
response:

```bash
curl -I http://localhost:5100/
```

This identity behavior exists only in `docker-compose-dev.yml`; no SimDB Python
API code is changed.
Loading
Loading