|
22 | 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | 23 | # SOFTWARE. |
24 | 24 |
|
25 | | -# Ubuntu 22.04 LTS - Jammy |
26 | | -ARG BASE_IMAGE=ubuntu:jammy-20240125 |
| 25 | +ARG BASE_IMAGE=ghcr.io/nipreps/fmriprep-base:20251006 |
27 | 26 |
|
28 | 27 | # |
29 | | -# Build wheel |
| 28 | +# Build pixi environment |
| 29 | +# The Pixi environment includes: |
| 30 | +# - Python |
| 31 | +# - Scientific Python stack (via conda-forge) |
| 32 | +# - General Python dependencies (via PyPI) |
| 33 | +# - FSL (via fslconda) |
| 34 | +# - ants (via conda-forge) |
| 35 | +# - connectome-workbench (via conda-forge) |
| 36 | +# - ... |
30 | 37 | # |
31 | | -FROM python:slim AS src |
32 | | -RUN pip install build |
33 | | -RUN apt-get update && \ |
34 | | - apt-get install -y --no-install-recommends git |
35 | | -COPY . /src |
36 | | -RUN python -m build /src |
37 | | - |
38 | | -# |
39 | | -# Download stages |
40 | | -# |
41 | | - |
42 | | -# Utilities for downloading packages |
43 | | -FROM ${BASE_IMAGE} as downloader |
44 | | -# Bump the date to current to refresh curl/certificates/etc |
45 | | -RUN echo "2024.03.08" |
| 38 | +FROM ghcr.io/prefix-dev/pixi:0.53.0 AS build |
46 | 39 | RUN apt-get update && \ |
47 | 40 | apt-get install -y --no-install-recommends \ |
48 | | - binutils \ |
49 | | - bzip2 \ |
50 | 41 | ca-certificates \ |
51 | | - curl \ |
52 | | - unzip && \ |
| 42 | + git && \ |
53 | 43 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* |
| 44 | +# Run post-link scripts during install, but use global to keep out of source tree |
| 45 | +RUN pixi config set --global run-post-link-scripts insecure |
| 46 | + |
| 47 | +# Install dependencies before the package itself to leverage caching |
| 48 | +RUN mkdir /app |
| 49 | +COPY pixi.lock pyproject.toml /app |
| 50 | +WORKDIR /app |
| 51 | +RUN --mount=type=cache,target=/root/.cache/rattler pixi install -e niworkflows -e test --frozen --skip niworkflows |
| 52 | +# Note that PATH gets hard-coded. Remove it and re-apply in final image |
| 53 | +RUN pixi shell-hook -e niworkflows --as-is | grep -v PATH > /shell-hook.sh |
| 54 | +RUN pixi shell-hook -e test --as-is | grep -v PATH > /test-shell-hook.sh |
| 55 | + |
| 56 | +# Finally, install the package |
| 57 | +COPY . /app |
| 58 | +RUN --mount=type=cache,target=/root/.cache/rattler pixi install -e niworkflows -e test --frozen |
54 | 59 |
|
55 | | -# FreeSurfer 7.3.2 |
56 | | -FROM downloader as freesurfer |
57 | | -COPY docker/files/freesurfer7.3.2-exclude.txt /usr/local/etc/freesurfer7.3.2-exclude.txt |
58 | | -RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.3.2/freesurfer-linux-ubuntu22_amd64-7.3.2.tar.gz \ |
59 | | - | tar zxv --no-same-owner -C /opt --exclude-from=/usr/local/etc/freesurfer7.3.2-exclude.txt |
60 | | - |
61 | | -# AFNI |
62 | | -FROM downloader as afni |
63 | | -# Bump the date to current to update AFNI |
64 | | -RUN echo "2024.03.08" |
65 | | -RUN mkdir -p /opt/afni-latest \ |
66 | | - && curl -fsSL --retry 5 https://afni.nimh.nih.gov/pub/dist/tgz/linux_openmp_64.tgz \ |
67 | | - | tar -xz -C /opt/afni-latest --strip-components 1 \ |
68 | | - --exclude "linux_openmp_64/*.gz" \ |
69 | | - --exclude "linux_openmp_64/funstuff" \ |
70 | | - --exclude "linux_openmp_64/shiny" \ |
71 | | - --exclude "linux_openmp_64/afnipy" \ |
72 | | - --exclude "linux_openmp_64/lib/RetroTS" \ |
73 | | - --exclude "linux_openmp_64/lib_RetroTS" \ |
74 | | - --exclude "linux_openmp_64/meica.libs" \ |
75 | | - # Keep only what we use |
76 | | - && find /opt/afni-latest -type f -not \( \ |
77 | | - -name "3dTshift" -or \ |
78 | | - -name "3dUnifize" -or \ |
79 | | - -name "3dAutomask" -or \ |
80 | | - -name "3dvolreg" \) -delete |
81 | | - |
82 | | -# Micromamba |
83 | | -FROM downloader as micromamba |
84 | | - |
85 | | -# Install a C compiler to build extensions when needed. |
86 | | -# traits<6.4 wheels are not available for Python 3.11+, but build easily. |
87 | | -RUN apt-get update && \ |
88 | | - apt-get install -y --no-install-recommends build-essential && \ |
89 | | - apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* |
90 | | - |
91 | | -WORKDIR / |
92 | | -# Bump the date to current to force update micromamba |
93 | | -RUN echo "2024.03.08" |
94 | | -RUN curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba |
| 60 | +# |
| 61 | +# Pre-fetch templates |
| 62 | +# |
| 63 | +FROM ghcr.io/astral-sh/uv:python3.12-alpine AS templates |
| 64 | +ENV TEMPLATEFLOW_HOME="/templateflow" |
| 65 | +RUN uv pip install --system templateflow |
| 66 | +COPY docker/fetch_templates.py fetch_templates.py |
| 67 | +RUN python fetch_templates.py |
95 | 68 |
|
96 | | -ENV MAMBA_ROOT_PREFIX="/opt/conda" |
97 | | -COPY env.yml /tmp/env.yml |
98 | | -COPY requirements.txt /tmp/requirements.txt |
99 | | -WORKDIR /tmp |
100 | | -RUN micromamba create -y -f /tmp/env.yml && \ |
101 | | - micromamba clean -y -a |
102 | 69 |
|
103 | 70 | # |
104 | 71 | # Main stage |
105 | 72 | # |
106 | | -FROM ${BASE_IMAGE} as main |
107 | | - |
108 | | -# Configure apt |
109 | | -ENV DEBIAN_FRONTEND="noninteractive" \ |
110 | | - LANG="en_US.UTF-8" \ |
111 | | - LC_ALL="en_US.UTF-8" |
112 | | - |
113 | | -# Some baseline tools; bc is needed for FreeSurfer, so don't drop it |
114 | | -RUN apt-get update && \ |
115 | | - apt-get install -y --no-install-recommends \ |
116 | | - bc \ |
117 | | - ca-certificates \ |
118 | | - curl \ |
119 | | - git \ |
120 | | - gnupg \ |
121 | | - lsb-release \ |
122 | | - netbase \ |
123 | | - xvfb && \ |
124 | | - apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* |
125 | | - |
126 | | -# Configure PPAs for libpng12 and libxp6 |
127 | | -RUN GNUPGHOME=/tmp gpg --keyserver hkps://keyserver.ubuntu.com --no-default-keyring --keyring /usr/share/keyrings/linuxuprising.gpg --recv 0xEA8CACC073C3DB2A \ |
128 | | - && GNUPGHOME=/tmp gpg --keyserver hkps://keyserver.ubuntu.com --no-default-keyring --keyring /usr/share/keyrings/zeehio.gpg --recv 0xA1301338A3A48C4A \ |
129 | | - && echo "deb [signed-by=/usr/share/keyrings/linuxuprising.gpg] https://ppa.launchpadcontent.net/linuxuprising/libpng12/ubuntu jammy main" > /etc/apt/sources.list.d/linuxuprising.list \ |
130 | | - && echo "deb [signed-by=/usr/share/keyrings/zeehio.gpg] https://ppa.launchpadcontent.net/zeehio/libxp/ubuntu jammy main" > /etc/apt/sources.list.d/zeehio.list |
131 | | - |
132 | | -# Dependencies for AFNI; requires a discontinued multiarch-support package from bionic (18.04) |
133 | | -RUN apt-get update -qq \ |
134 | | - && apt-get install -y -q --no-install-recommends \ |
135 | | - ed \ |
136 | | - gsl-bin \ |
137 | | - libglib2.0-0 \ |
138 | | - libglu1-mesa-dev \ |
139 | | - libglw1-mesa \ |
140 | | - libgomp1 \ |
141 | | - libjpeg62 \ |
142 | | - libpng12-0 \ |
143 | | - libxm4 \ |
144 | | - libxp6 \ |
145 | | - netpbm \ |
146 | | - tcsh \ |
147 | | - xfonts-base \ |
148 | | - xvfb \ |
149 | | - && curl -sSL --retry 5 -o /tmp/multiarch.deb http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/multiarch-support_2.27-3ubuntu1.5_amd64.deb \ |
150 | | - && dpkg -i /tmp/multiarch.deb \ |
151 | | - && rm /tmp/multiarch.deb \ |
152 | | - && apt-get install -f \ |
153 | | - && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ |
154 | | - && gsl2_path="$(find / -name 'libgsl.so.19' || printf '')" \ |
155 | | - && if [ -n "$gsl2_path" ]; then \ |
156 | | - ln -sfv "$gsl2_path" "$(dirname $gsl2_path)/libgsl.so.0"; \ |
157 | | - fi \ |
158 | | - && ldconfig |
159 | | - |
160 | | -# Install files from stages |
161 | | -COPY --from=freesurfer /opt/freesurfer /opt/freesurfer |
162 | | -COPY --from=afni /opt/afni-latest /opt/afni-latest |
163 | | - |
164 | | -# Simulate SetUpFreeSurfer.sh |
165 | | -ENV OS="Linux" \ |
166 | | - FS_OVERRIDE=0 \ |
167 | | - FIX_VERTEX_AREA="" \ |
168 | | - FSF_OUTPUT_FORMAT="nii.gz" \ |
169 | | - FREESURFER_HOME="/opt/freesurfer" |
170 | | -ENV SUBJECTS_DIR="$FREESURFER_HOME/subjects" \ |
171 | | - FUNCTIONALS_DIR="$FREESURFER_HOME/sessions" \ |
172 | | - MNI_DIR="$FREESURFER_HOME/mni" \ |
173 | | - LOCAL_DIR="$FREESURFER_HOME/local" \ |
174 | | - MINC_BIN_DIR="$FREESURFER_HOME/mni/bin" \ |
175 | | - MINC_LIB_DIR="$FREESURFER_HOME/mni/lib" \ |
176 | | - MNI_DATAPATH="$FREESURFER_HOME/mni/data" |
177 | | -ENV PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \ |
178 | | - MNI_PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \ |
179 | | - PATH="$FREESURFER_HOME/bin:$FREESURFER_HOME/tktools:$MINC_BIN_DIR:$PATH" |
180 | | - |
181 | | -# AFNI config |
182 | | -ENV PATH="/opt/afni-latest:$PATH" \ |
183 | | - AFNI_IMSAVE_WARNINGS="NO" \ |
184 | | - AFNI_PLUGINPATH="/opt/afni-latest" |
| 73 | +FROM ${BASE_IMAGE} AS base |
185 | 74 |
|
186 | 75 | # Create a shared $HOME directory |
187 | 76 | RUN useradd -m -s /bin/bash -G users niworkflows |
188 | 77 | WORKDIR /home/niworkflows |
189 | | -ENV HOME="/home/niworkflows" \ |
190 | | - LD_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH" |
191 | | - |
192 | | -COPY --from=micromamba /bin/micromamba /bin/micromamba |
193 | | -COPY --from=micromamba /opt/conda/envs/niworkflows /opt/conda/envs/niworkflows |
194 | | - |
195 | | -ENV MAMBA_ROOT_PREFIX="/opt/conda" |
196 | | -RUN micromamba shell init -s bash && \ |
197 | | - echo "micromamba activate niworkflows" >> $HOME/.bashrc |
198 | | -ENV PATH="/opt/conda/envs/niworkflows/bin:$PATH" \ |
199 | | - CPATH="/opt/conda/envs/niworkflows/include:$CPATH" \ |
200 | | - LD_LIBRARY_PATH="/opt/conda/envs/niworkflows/lib:$LD_LIBRARY_PATH" |
201 | | - |
202 | | -COPY docker/fetch_templates.py /tmp/fetch_templates.py |
203 | | -RUN python /tmp/fetch_templates.py && \ |
204 | | - rm /tmp/fetch_templates.py && \ |
205 | | - find $HOME/.cache/templateflow -type d -exec chmod go=u {} + && \ |
206 | | - find $HOME/.cache/templateflow -type f -exec chmod go=u {} + |
207 | | - |
208 | | -# FSL environment |
209 | | -ENV LANG="C.UTF-8" \ |
210 | | - LC_ALL="C.UTF-8" \ |
211 | | - PYTHONNOUSERSITE=1 \ |
212 | | - FSLDIR="/opt/conda/envs/fmriprep" \ |
213 | | - FSLOUTPUTTYPE="NIFTI_GZ" \ |
214 | | - FSLMULTIFILEQUIT="TRUE" \ |
215 | | - FSLLOCKDIR="" \ |
216 | | - FSLMACHINELIST="" \ |
217 | | - FSLREMOTECALL="" \ |
218 | | - FSLGECUDAQ="cuda.q" |
| 78 | +ENV HOME="/home/niworkflows" |
| 79 | + |
| 80 | +COPY --link --from=templates /templateflow /home/fmriprep/.cache/templateflow |
| 81 | + |
| 82 | +RUN chmod -R go=u $HOME |
219 | 83 |
|
220 | 84 | # Unless otherwise specified each process should only use one thread - nipype |
221 | 85 | # will handle parallelization |
222 | 86 | ENV MKL_NUM_THREADS=1 \ |
223 | 87 | OMP_NUM_THREADS=1 |
224 | 88 |
|
225 | | -# Installing niworkflows |
226 | | -COPY --from=src /src/dist/*.whl . |
227 | | -RUN pip install --no-cache-dir $( ls *.whl )[all] |
228 | | - |
229 | 89 | COPY docker/files/nipype.cfg /home/niworkflows/.nipype/nipype.cfg |
230 | 90 |
|
231 | | -# Cleanup and ensure perms. |
232 | | -RUN rm -rf $HOME/.npm $HOME/.conda $HOME/.empty && \ |
233 | | - find $HOME -type d -exec chmod go=u {} + && \ |
234 | | - find $HOME -type f -exec chmod go=u {} + |
235 | | - |
236 | | -# Final settings |
237 | 91 | WORKDIR /tmp |
238 | | -ARG BUILD_DATE |
239 | | -ARG VCS_REF |
240 | | -LABEL org.label-schema.build-date=$BUILD_DATE \ |
241 | | - org.label-schema.name="niworkflows" \ |
242 | | - org.label-schema.description="niworkflows - NeuroImaging workflows" \ |
243 | | - org.label-schema.url="https://github.com/nipreps/niworkflows" \ |
244 | | - org.label-schema.vcs-ref=$VCS_REF \ |
245 | | - org.label-schema.vcs-url="https://github.com/nipreps/niworkflows" \ |
246 | | - org.label-schema.version=$VERSION \ |
247 | | - org.label-schema.schema-version="1.0" |
| 92 | + |
| 93 | +FROM base AS test |
| 94 | + |
| 95 | +COPY --link --from=build /app/.pixi/envs/test /app/.pixi/envs/test |
| 96 | +COPY --link --from=build /test-shell-hook.sh /shell-hook.sh |
| 97 | +RUN cat /shell-hook.sh >> $HOME/.bashrc |
| 98 | +ENV PATH="/app/.pixi/envs/test/bin:$PATH" |
| 99 | + |
| 100 | +ENV FSLDIR="/app/.pixi/envs/test" |
0 commit comments