Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
25 changes: 21 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,25 @@ jobs:
- run: *docker_auth
- run: *setup_docker_registry
- run:
name: Create named builder
command: docker buildx create --use --name=builder --driver=docker-container
name: Get base image information
command: |
export BASE_IMAGE=$( grep BASE_IMAGE= Dockerfile | cut -d= -f2 )
export BASE_IMAGE_NAME=${BASE_IMAGE%:*}
export BASE_TAG=${BASE_IMAGE#*:}
echo "BASE_IMAGE=$BASE_IMAGE" >> $BASH_ENV
echo "BASE_IMAGE_NAME=$BASE_IMAGE_NAME" >> $BASH_ENV
echo "BASE_TAG=$BASE_TAG" >> $BASH_ENV
env
- run:
name: Build base image, if needed
command: |
if ! docker manifest inspect $BASE_IMAGE; then
docker buildx build --load \
--cache-from $BASE_IMAGE_NAME:latest \
-t $BASE_IMAGE \
--platform linux/amd64 \
-f Dockerfile.base .
fi
- run:
name: Build Docker image (production environment)
no_output_timeout: 60m
Expand All @@ -192,7 +209,7 @@ jobs:
echo "them to your fork with ``git push origin --tags``"
fi
# Build docker image
docker buildx build --load --builder builder \
docker buildx build --load \
--cache-from localhost:5000/fmriprep \
--cache-from nipreps/fmriprep:latest \
-t nipreps/fmriprep:latest \
Expand All @@ -204,7 +221,7 @@ jobs:
name: Build Docker image (test environment)
no_output_timeout: 60m
command: |
docker buildx build --load --builder builder \
docker buildx build --load \
--cache-from localhost:5000/fmriprep \
--cache-from nipreps/fmriprep:latest \
-t nipreps/fmriprep:test \
Expand Down
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ fmriprep.egg-info
.eggs

.pixi
.tox
33 changes: 33 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:

- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
with:
driver: docker

- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
Expand All @@ -41,6 +43,37 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Get base image tag, check
id: base
run: |
export BASE_IMAGE=$( grep BASE_IMAGE= Dockerfile | cut -d= -f2 )
export BASE_IMAGE_NAME=${BASE_IMAGE%:*}
export BASE_TAG=${BASE_IMAGE#*:}
echo "image=$BASE_IMAGE" >> $GITHUB_OUTPUT
echo "name=$BASE_IMAGE_NAME" >> $GITHUB_OUTPUT
echo "tag=$BASE_TAG" >> $GITHUB_OUTPUT
env
if docker manifest inspect $BASE_IMAGE; then
echo "build=false" >> $GITHUB_OUTPUT
else
echo "build=true" >> $GITHUB_OUTPUT
fi

- name: Build base image
if: steps.base.outputs.build == 'true'
uses: docker/build-push-action@v6
with:
file: Dockerfile.base
load: true
push: ${{ github.event_name != 'pull_request' }}
tags: |
${{ steps.base.outputs.image }}
${{ steps.base.outputs.name }}:latest
platforms: linux/amd64
cache-from: |
type=registry,ref=${{ steps.base.outputs.name }}:latest
cache-to: type=inline

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
Expand Down
106 changes: 2 additions & 104 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# Ubuntu 22.04 LTS - Jammy
ARG BASE_IMAGE=ubuntu:jammy-20250730
ARG BASE_IMAGE=ghcr.io/nipreps/fmriprep-base:20250915

#
# Build pixi environment
Expand Down Expand Up @@ -71,121 +70,20 @@ RUN uv pip install --system templateflow
COPY scripts/fetch_templates.py fetch_templates.py
RUN python fetch_templates.py

#
# Download stages
#

# Utilities for downloading packages
FROM ${BASE_IMAGE} AS downloader
ENV DEBIAN_FRONTEND="noninteractive" \
LANG="en_US.UTF-8" \
LC_ALL="en_US.UTF-8"

# Bump the date to current to refresh curl/certificates/etc
RUN echo "2025.08.20"
RUN apt-get update && \
apt-get install -y --no-install-recommends \
binutils \
bzip2 \
ca-certificates \
curl \
unzip && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# FreeSurfer 7.3.2
FROM downloader AS freesurfer
COPY docker/files/freesurfer7.3.2-exclude.txt /usr/local/etc/freesurfer7.3.2-exclude.txt
RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.3.2/freesurfer-linux-ubuntu22_amd64-7.3.2.tar.gz \
| tar zxv --no-same-owner -C /opt --exclude-from=/usr/local/etc/freesurfer7.3.2-exclude.txt

# MSM HOCR (Nov 19, 2019 release)
FROM downloader AS msm
RUN curl -L -H "Accept: application/octet-stream" https://api.github.com/repos/ecr05/MSM_HOCR/releases/assets/16253707 -o /usr/local/bin/msm \
&& chmod +x /usr/local/bin/msm

#
# Main stage
#
FROM ${BASE_IMAGE} AS base

# Configure apt
ENV DEBIAN_FRONTEND="noninteractive" \
LANG="en_US.UTF-8" \
LC_ALL="en_US.UTF-8"

# Some baseline tools; bc is needed for FreeSurfer, so don't drop it
RUN apt-get update && \
apt-get install -y --no-install-recommends \
bc \
ca-certificates \
curl \
libgomp1 \
libopenblas0-openmp \
lsb-release \
netbase \
tcsh \
xvfb && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*


# Install downloaded files from stages
COPY --link --from=freesurfer /opt/freesurfer /opt/freesurfer
COPY --link --from=msm /usr/local/bin/msm /usr/local/bin/msm

# Install AFNI from Docker container
# Find libraries with `ldd $BINARIES | grep afni`
COPY --link --from=afni/afni_make_build:AFNI_25.2.09 \
/opt/afni/install/libf2c.so \
/opt/afni/install/libmri.so \
/usr/local/lib/
COPY --link --from=afni/afni_make_build:AFNI_25.2.09 \
/opt/afni/install/3dAutomask \
/opt/afni/install/3dTshift \
/opt/afni/install/3dUnifize \
/opt/afni/install/3dvolreg \
/usr/local/bin/

# Changing library paths requires a re-ldconfig
RUN ldconfig

# Simulate SetUpFreeSurfer.sh
ENV OS="Linux" \
FS_OVERRIDE=0 \
FIX_VERTEX_AREA="" \
FSF_OUTPUT_FORMAT="nii.gz" \
FREESURFER_HOME="/opt/freesurfer"
ENV SUBJECTS_DIR="$FREESURFER_HOME/subjects" \
FUNCTIONALS_DIR="$FREESURFER_HOME/sessions" \
MNI_DIR="$FREESURFER_HOME/mni" \
LOCAL_DIR="$FREESURFER_HOME/local" \
MINC_BIN_DIR="$FREESURFER_HOME/mni/bin" \
MINC_LIB_DIR="$FREESURFER_HOME/mni/lib" \
MNI_DATAPATH="$FREESURFER_HOME/mni/data"
ENV PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
MNI_PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
PATH="$FREESURFER_HOME/bin:$FREESURFER_HOME/tktools:$MINC_BIN_DIR:$PATH"

# AFNI config
ENV AFNI_IMSAVE_WARNINGS="NO"

# Create a shared $HOME directory
RUN useradd -m -s /bin/bash -G users fmriprep
WORKDIR /home/fmriprep
ENV HOME="/home/fmriprep"
RUN chmod -R go=u $HOME

COPY --link --from=templates /templateflow /home/fmriprep/.cache/templateflow

# FSL environment
ENV LANG="C.UTF-8" \
LC_ALL="C.UTF-8" \
PYTHONNOUSERSITE=1 \
FSLOUTPUTTYPE="NIFTI_GZ" \
FSLMULTIFILEQUIT="TRUE" \
FSLLOCKDIR="" \
FSLMACHINELIST="" \
FSLREMOTECALL="" \
FSLGECUDAQ="cuda.q"

# Unless otherwise specified each process should only use one thread - nipype
# will handle parallelization
ENV MKL_NUM_THREADS=1 \
Expand Down
134 changes: 134 additions & 0 deletions Dockerfile.base
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# fMRIPrep Docker Container Image distribution
#
# MIT License
#
# Copyright (c) The NiPreps Developers
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# Ubuntu 22.04 LTS - Jammy
ARG BASE_IMAGE=ubuntu:jammy-20250730

#
# Download stages
#

# Utilities for downloading packages
FROM ${BASE_IMAGE} AS downloader
ENV DEBIAN_FRONTEND="noninteractive" \
LANG="en_US.UTF-8" \
LC_ALL="en_US.UTF-8"

# Bump the date to current to refresh curl/certificates/etc
RUN echo "2025.08.20"
RUN apt-get update && \
apt-get install -y --no-install-recommends \
binutils \
bzip2 \
ca-certificates \
curl \
unzip && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# FreeSurfer 7.3.2
FROM downloader AS freesurfer
COPY docker/files/freesurfer7.3.2-exclude.txt /usr/local/etc/freesurfer7.3.2-exclude.txt
RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.3.2/freesurfer-linux-ubuntu22_amd64-7.3.2.tar.gz \
| tar zxv --no-same-owner -C /opt --exclude-from=/usr/local/etc/freesurfer7.3.2-exclude.txt

# MSM HOCR (Nov 19, 2019 release)
FROM downloader AS msm
RUN curl -L -H "Accept: application/octet-stream" https://api.github.com/repos/ecr05/MSM_HOCR/releases/assets/16253707 -o /usr/local/bin/msm \
&& chmod +x /usr/local/bin/msm

#
# Main stage
#
FROM ${BASE_IMAGE} AS base

# Configure apt
ENV DEBIAN_FRONTEND="noninteractive" \
LANG="en_US.UTF-8" \
LC_ALL="en_US.UTF-8"

# Install downloaded files from stages
COPY --link --from=freesurfer /opt/freesurfer /opt/freesurfer
COPY --link --from=msm /usr/local/bin/msm /usr/local/bin/msm

# Some baseline tools; bc is needed for FreeSurfer, so don't drop it
RUN apt-get update && \
apt-get install -y --no-install-recommends \
bc \
ca-certificates \
curl \
libgomp1 \
libopenblas0-openmp \
lsb-release \
netbase \
tcsh \
xvfb && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*


# Install AFNI from Docker container
# Find libraries with `ldd $BINARIES | grep afni`
COPY --link --from=afni/afni_make_build:AFNI_25.2.09 \
/opt/afni/install/libf2c.so \
/opt/afni/install/libmri.so \
/usr/local/lib/
COPY --link --from=afni/afni_make_build:AFNI_25.2.09 \
/opt/afni/install/3dAutomask \
/opt/afni/install/3dTshift \
/opt/afni/install/3dUnifize \
/opt/afni/install/3dvolreg \
/usr/local/bin/

# Changing library paths requires a re-ldconfig
RUN ldconfig

# Simulate SetUpFreeSurfer.sh
ENV OS="Linux" \
FS_OVERRIDE=0 \
FIX_VERTEX_AREA="" \
FSF_OUTPUT_FORMAT="nii.gz" \
FREESURFER_HOME="/opt/freesurfer"
ENV SUBJECTS_DIR="$FREESURFER_HOME/subjects" \
FUNCTIONALS_DIR="$FREESURFER_HOME/sessions" \
MNI_DIR="$FREESURFER_HOME/mni" \
LOCAL_DIR="$FREESURFER_HOME/local" \
MINC_BIN_DIR="$FREESURFER_HOME/mni/bin" \
MINC_LIB_DIR="$FREESURFER_HOME/mni/lib" \
MNI_DATAPATH="$FREESURFER_HOME/mni/data"
ENV PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
MNI_PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
PATH="$FREESURFER_HOME/bin:$FREESURFER_HOME/tktools:$MINC_BIN_DIR:$PATH"

# AFNI config
ENV AFNI_IMSAVE_WARNINGS="NO"

# FSL environment
ENV LANG="C.UTF-8" \
LC_ALL="C.UTF-8" \
PYTHONNOUSERSITE=1 \
FSLOUTPUTTYPE="NIFTI_GZ" \
FSLMULTIFILEQUIT="TRUE" \
FSLLOCKDIR="" \
FSLMACHINELIST="" \
FSLREMOTECALL="" \
FSLGECUDAQ="cuda.q"