Skip to content
Draft
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
120 changes: 115 additions & 5 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,115 @@
assetstore
db
logs
**/node_modules
.env
# Git
.gitignore
.gitattributes
dive-dsa-slicer/
scripts/
testutils/
# Documentation
docs/
*.md
README*

# Development files
.vscode/
.idea/
*.swp
*.swo
*~

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# Virtual environments
.env
.venv
env/
venv/
server/.venv/
ENV/
env.bak/
venv.bak/

# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
coverage.xml
*.cover
.hypothesis/

# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Build artifacts
client/dist/
client/node_modules/
*.log

# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Temporary files
*.tmp
*.temp
/tmp/
/var/tmp/

# Docker
Dockerfile*
docker-compose*.yml
.dockerignore

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
.circleci/

# IDE
.vscode/
.idea/
*.sublime-*

# Large data files
*.zip
*.tar.gz
*.tar.bz2
*.7z
*.rar

# Test data
testutils/
tests/
*_test.py
test_*.py
4 changes: 2 additions & 2 deletions docker/entrypoint_server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ chmod 777 /var/run/docker.sock 2>/dev/null || true


set -e
python /server_setup.py
exec girder serve --host 0.0.0.0 $@
uv run python /server_setup.py
exec uv run girder serve --host 0.0.0.0 $@
2 changes: 1 addition & 1 deletion docker/entrypoint_worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ if [ -n "$WORKER_CONCURRENCY" ]; then
CONCURRENCY_ARGUMENT="--concurrency $WORKER_CONCURRENCY"
fi

su $(id -nu ${DSA_USER%%:*}) -c "GW_DIRECT_PATHS=true python -m dive_tasks -l info --without-gossip --without-mingle $QUEUE_ARGUMENT $CONCURRENCY_ARGUMENT -Ofair --prefetch-multiplier=1"
su $(id -nu ${DSA_USER%%:*}) -c "GW_DIRECT_PATHS=true uv run python -m dive_tasks -l info --without-gossip --without-mingle $QUEUE_ARGUMENT $CONCURRENCY_ARGUMENT -Ofair --prefetch-multiplier=1"

# su $(id -nu ${DSA_USER%%:*}) -c "GW_DIRECT_PATHS=true python -m girder_worker $CONCURRENCY_ARGUMENT -Ofair --prefetch-multiplier=1"
# exec python \
Expand Down
60 changes: 46 additions & 14 deletions docker/entrypoint_worker_gpu.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,55 @@
#!/bin/sh
#!/bin/bash
set -euo pipefail

# Environment variables that may be supplied
# WORKER_CONCURRENCY: The number of concurrent jobs to run at once. If not supplied, the celery default is used.
# WORKER_WATCHING_QUEUES: The comma separated list of queues to take tasks from. If not supplied, the celery default of 'celery' is used.
export PATH="/opt/dive/local/ffmpeg:$PATH"
# Environment variables that may be supplied:
# WORKER_CONCURRENCY: The number of concurrent jobs to run at once. If not supplied, celery default is used.
# WORKER_WATCHING_QUEUES: The comma-separated list of queues to take tasks from. If not supplied, default 'celery' is used.

QUEUE_ARGUMENT=
CONCURRENCY_ARGUMENT=
QUEUE_ARGUMENT=""
CONCURRENCY_ARGUMENT=""

if [ -n "$WORKER_WATCHING_QUEUES" ]; then
if [[ -z "${DSA_USER:-}" ]]; then
echo "Set the DSA_USER before starting (e.g., DSA_USER=\$$(id -u):\$$(id -g) <up command>)"
exit 1
fi

USER_ID=${DSA_USER%%:*}
GROUP_ID=${DSA_USER#*:}

# Ensure group exists
if ! getent group "${GROUP_ID}" >/dev/null 2>&1; then
groupadd -g "${GROUP_ID}" dsa_group
fi

# Ensure user exists
if ! id -u "${USER_ID}" >/dev/null 2>&1; then
useradd -m -u "${USER_ID}" -g "${GROUP_ID}" -s /bin/bash ubuntu2 || true
fi

# Handle docker.sock if present
if [[ -S /var/run/docker.sock ]]; then
DOCKER_GID=$(stat -c "%g" /var/run/docker.sock)
if ! getent group "${DOCKER_GID}" >/dev/null 2>&1; then
groupadd -g "${DOCKER_GID}" docker
fi
usermod -aG "${DOCKER_GID}" "$(id -nu ${USER_ID})" || true
chmod 777 /var/run/docker.sock || true
fi

# Ensure tmp is writable
chmod 1777 "${TMPDIR:-/tmp}" || true

# Worker arguments
if [[ -n "${WORKER_WATCHING_QUEUES:-}" ]]; then
QUEUE_ARGUMENT="--queues $WORKER_WATCHING_QUEUES"
fi

if [ -n "$WORKER_CONCURRENCY" ]; then
if [[ -n "${WORKER_CONCURRENCY:-}" ]]; then
CONCURRENCY_ARGUMENT="--concurrency $WORKER_CONCURRENCY"
fi

exec poetry run python \
-m dive_tasks \
-l info \
--without-gossip --without-mingle \
$QUEUE_ARGUMENT $CONCURRENCY_ARGUMENT
# Sanity checks for required tools
command -v uv >/dev/null 2>&1 || { echo "Error: 'uv' not found in PATH"; exit 1; }
command -v python >/dev/null 2>&1 || { echo "Error: 'python' not found in PATH"; exit 1; }

su $(id -nu ${DSA_USER%%:*}) -c "GW_DIRECT_PATHS=true uv run python -m dive_tasks -l info --without-gossip --without-mingle $QUEUE_ARGUMENT $CONCURRENCY_ARGUMENT -Ofair --prefetch-multiplier=1"
78 changes: 51 additions & 27 deletions docker/girder.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# ========================
FROM node:20 AS client-builder
WORKDIR /app
SHELL ["/bin/bash", "-c"]

# Install dependencies
COPY client/package.json client/yarn.lock /app/
Expand All @@ -15,34 +16,43 @@ RUN yarn build:web
# ========================
# == SERVER BUILD STAGE ==
# ========================
# Note: server-builder stage will be the same in both dockerfiles
FROM python:3.11-bookworm AS server-builder
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim AS server-builder
SHELL ["/bin/bash", "-c"]

WORKDIR /opt/dive/src

# https://cryptography.io/en/latest/installation/#debian-ubuntu
RUN apt-get update
RUN apt-get install -y build-essential libssl-dev libffi-dev python3-dev cargo npm libgl1
# Recommended poetry install https://python-poetry.org/docs/master/#installation
RUN curl -sSL https://install.python-poetry.org | POETRY_VERSION=2.1.2 POETRY_HOME=/opt/dive/poetry python -
ENV PATH="/opt/dive/poetry/bin:$PATH"
# Create a virtual environment for the installation
RUN python -m venv /opt/dive/local/venv
# Poetry needs this set to recognize it as ane existing environment
# Install only essential build dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
curl \
git \
pkg-config \
libgomp1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
ENV VIRTUAL_ENV="/opt/dive/local/venv"
ENV UV_PROJECT_ENVIRONMENT=/opt/dive/local/venv
ENV PATH="/opt/dive/local/venv/bin:$PATH"

# Copy only the lock and project files to optimize cache
# Create virtual environment
RUN uv venv /opt/dive/local/venv

# Copy dependency files first for better caching
COPY server/pyproject.toml /opt/dive/src/
COPY server/uv.lock /opt/dive/src/
COPY .git/ /opt/dive/src/.git/
RUN poetry env use system
RUN poetry config virtualenvs.create false
# Install dependencies only
RUN poetry install --no-root
# Build girder client, including plugins like worker/jobs
# Copy full source code and install

# Install dependencies without SAM2 (web server doesn't need it)
RUN uv sync --frozen --no-install-project --no-dev

# Copy source and install project
COPY server/ /opt/dive/src/
RUN poetry install --only main
RUN uv sync --frozen --no-dev --extra cpu

# Install Node.js for Girder build
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
RUN . ~/.bashrc && \
nvm install 14 && \
Expand All @@ -51,28 +61,42 @@ RUN . ~/.bashrc && \
ln -s $(dirname `which npm`) /usr/local/node

ENV PATH="/usr/local/node:$PATH"

RUN girder build

# Clean up build artifacts and cache
RUN rm -rf /root/.cache /tmp/* /var/tmp/* && \
find /opt/dive/local/venv -name "*.pyc" -delete && \
find /opt/dive/local/venv -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true

# =================
# == DIST SERVER ==
# =================
FROM python:3.11-slim-bookworm AS server
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim AS server

RUN apt-get update
RUN apt-get install -y libgl1 libglib2.0-0
# Install only runtime dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libgomp1 \
ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Hack: Tell GitPython to be quiet, we aren't using git
ENV GIT_PYTHON_REFRESH="quiet"
ENV PATH="/opt/dive/local/venv/bin:$PATH"
ENV PATH="/opt/dive/local/venv/bin:/usr/local/bin:$PATH"

# Copy site packages and executables
# Copy only the essential parts from builder
COPY --from=server-builder /opt/dive/local/venv /opt/dive/local/venv
# Copy the source code of the editable module
COPY --from=server-builder /opt/dive/src /opt/dive/src
# Copy the client code into the static source location
COPY --from=client-builder /app/dist/ /opt/dive/local/venv/share/girder/static/dive/

# Copy uv binary for runtime use
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

# Install startup scripts
COPY docker/entrypoint_server.sh docker/server_setup.py /

# Create non-root user for security
RUN useradd --create-home --uid 1000 --shell=/bin/bash dive && \
chown -R dive:dive /opt/dive
ENTRYPOINT [ "/entrypoint_server.sh" ]
Loading