-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
179 lines (152 loc) · 7.41 KB
/
Copy pathDockerfile
File metadata and controls
179 lines (152 loc) · 7.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# Dockerfile - Full Development Environment
#
# Multi-stage build combining:
# - Python 3.11 with uv package manager
# - R 4.4 with renv for reproducible packages
# - Node.js 20 LTS for visualization app
#
# Build: docker build -t foundation-plr .
# Run: docker run --rm -it foundation-plr
# Test: docker run --rm foundation-plr python -c "import duckdb; print('OK')"
#
# For scientific reproducibility, this image:
# 1. Uses pinned base images with specific versions
# 2. Uses uv for Python, renv for R, npm for Node.js
# 3. Includes all STRATOS-compliant statistical packages
#
# =============================================================================
# -----------------------------------------------------------------------------
# Stage 1: Python environment builder
# -----------------------------------------------------------------------------
# Pinned 2026-02-13 for reproducibility (TRIPOD-Code area B)
FROM python:3.11-slim-bookworm@sha256:067222884359a2476ff344f92278df8fbe4792b7cf1a43d82d4a98befe8f89fb AS python-builder
# Install build dependencies for Python packages requiring compilation
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install uv
# Pin uv version for reproducibility
# Pinned 2026-02-13 for reproducibility
COPY --from=ghcr.io/astral-sh/uv:0.9@sha256:e96d483a9ed7924d2acf01bdd1d537d0d5e6d8f21b74fff3373005f6c9446696 /uv /usr/local/bin/uv
WORKDIR /project
# Copy Python dependency files
COPY pyproject.toml uv.lock ./
# Create virtual environment and install dependencies
ENV UV_PROJECT_ENVIRONMENT=/opt/venv
RUN uv venv /opt/venv && \
uv sync --frozen --no-dev
# Copy Python itself for the final image
RUN cp -r /usr/local/lib/python3.11 /opt/python-lib && \
cp /usr/local/bin/python3.11 /opt/python-bin
# -----------------------------------------------------------------------------
# Stage 2: Final combined image (based on rocker for R 4.4)
# -----------------------------------------------------------------------------
# Pinned 2026-02-13 for reproducibility (TRIPOD-Code area B)
FROM rocker/tidyverse:4.5.2@sha256:17dca9381149911b201184ab46e6c8628b68ddc1386b9562bc26ca8b6b4c6f81 AS final
LABEL maintainer="Foundation PLR Team"
LABEL description="Full development environment for Foundation PLR (Python + R + Node.js)"
LABEL version="1.0.0"
LABEL org.opencontainers.image.source="https://github.com/petteri-lab/foundation_plr"
# =============================================================================
# System dependencies
# =============================================================================
RUN apt-get update && apt-get install -y --no-install-recommends \
# Python 3.11 (from deadsnakes PPA for Ubuntu)
software-properties-common \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3.11 \
python3.11-venv \
python3.11-dev \
# Additional tools
libgit2-dev \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 20 LTS
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# =============================================================================
# Python setup
# =============================================================================
# Copy uv for package management
# Pin uv version for reproducibility
# Pinned 2026-02-13 for reproducibility
COPY --from=ghcr.io/astral-sh/uv:0.9@sha256:e96d483a9ed7924d2acf01bdd1d537d0d5e6d8f21b74fff3373005f6c9446696 /uv /usr/local/bin/uv
# Copy the pre-built Python virtual environment
COPY --from=python-builder /opt/venv /opt/venv
# Make python3.11 the default python
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1 && \
update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 1
# Fix venv symlinks to point to this image's Python
RUN rm /opt/venv/bin/python /opt/venv/bin/python3 /opt/venv/bin/python3.11 && \
ln -s /usr/bin/python3.11 /opt/venv/bin/python && \
ln -s python /opt/venv/bin/python3 && \
ln -s python /opt/venv/bin/python3.11
# Set Python to use the virtual environment
ENV VIRTUAL_ENV=/opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# =============================================================================
# R setup - renv already installed in rocker image
# =============================================================================
ENV RENV_VERSION=1.1.6
RUN R -e "install.packages('remotes', repos = 'https://cloud.r-project.org'); remotes::install_version('renv', version = '1.1.6', repos = 'https://cloud.r-project.org')"
# =============================================================================
# Working directory
# =============================================================================
WORKDIR /project
# =============================================================================
# R packages
# =============================================================================
COPY renv.lock renv.lock
COPY .Rprofile .Rprofile
COPY renv/activate.R renv/activate.R
COPY renv/settings.json renv/settings.json
# Restore R packages from lockfile
RUN R -e "options(warn = 1); renv::restore(prompt = FALSE)"
# =============================================================================
# Python project files
# =============================================================================
COPY pyproject.toml uv.lock ./
# =============================================================================
# Node.js packages (visualization app)
# =============================================================================
COPY apps/visualization/package*.json apps/visualization/
# Install Node.js packages for visualization app
RUN cd apps/visualization && npm ci --omit=dev
# =============================================================================
# Application code
# =============================================================================
COPY src/ src/
COPY configs/ configs/
COPY scripts/ scripts/
COPY tests/ tests/
COPY Makefile ./
COPY apps/ apps/
# =============================================================================
# Output directories
# =============================================================================
RUN mkdir -p figures/generated/ggplot2 \
&& mkdir -p figures/generated/matplotlib \
&& mkdir -p outputs/r_data \
&& mkdir -p outputs/tables \
&& mkdir -p outputs/latex
# =============================================================================
# Environment configuration
# =============================================================================
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
ENV R_LIBS_USER=/project/renv/library
ENV PYTHONPATH=/project/src
ENV PREFECT_DISABLED=1
# =============================================================================
# Health check
# =============================================================================
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD bash -c "python -c 'import duckdb' && R -e 'library(ggplot2)' && node --version"
# =============================================================================
# Default command
# =============================================================================
CMD ["bash", "-c", "echo '=== Foundation PLR Development Environment ===' && python --version && R --version | head -1 && node --version && echo '=== Ready ===' && bash"]