Skip to content

Commit da4ee07

Browse files
authored
Merge pull request #505 from nipreps/gha-docker
feat: Add base Docker image
2 parents f588b83 + fc2078f commit da4ee07

File tree

4 files changed

+261
-81
lines changed

4 files changed

+261
-81
lines changed

.circleci/config.yml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,25 @@ jobs:
109109
- run: *docker_auth
110110
- run: *setup_docker_registry
111111
- run:
112-
name: Create named builder
113-
command: docker buildx create --use --name=builder --driver=docker-container
112+
name: Get base image information
113+
command: |
114+
export BASE_IMAGE=$( grep BASE_IMAGE= Dockerfile | cut -d= -f2 )
115+
export BASE_IMAGE_NAME=${BASE_IMAGE%:*}
116+
export BASE_TAG=${BASE_IMAGE#*:}
117+
echo "BASE_IMAGE=$BASE_IMAGE" >> $BASH_ENV
118+
echo "BASE_IMAGE_NAME=$BASE_IMAGE_NAME" >> $BASH_ENV
119+
echo "BASE_TAG=$BASE_TAG" >> $BASH_ENV
120+
env
121+
- run:
122+
name: Build base image, if needed
123+
command: |
124+
if ! docker manifest inspect $BASE_IMAGE; then
125+
docker buildx build --load \
126+
--cache-from $BASE_IMAGE_NAME:latest \
127+
-t $BASE_IMAGE \
128+
--platform linux/amd64 \
129+
-f Dockerfile.base .
130+
fi
114131
- run:
115132
name: Build Docker image
116133
no_output_timeout: 60m
@@ -126,7 +143,7 @@ jobs:
126143
echo "them to your fork with ``git push origin --tags``"
127144
fi
128145
# Build docker image
129-
docker buildx build --load --builder builder \
146+
docker buildx build --load \
130147
--cache-from localhost:5000/smriprep \
131148
--cache-from nipreps/smriprep:latest \
132149
-t nipreps/smriprep:latest \

.github/workflows/docker.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Docker build
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ "master", "main", "maint/*", "gha-docker*" ]
7+
tags: "*"
8+
pull_request:
9+
branches: [ "master", "main", "maint/*" ]
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
env:
16+
REGISTRY: ghcr.io
17+
IMAGE_NAME: ${{ github.repository }}
18+
FORCE_COLOR: true
19+
20+
jobs:
21+
build-container:
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
packages: write
26+
steps:
27+
- name: Checkout repository
28+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
29+
with:
30+
fetch-depth: 200
31+
fetch-tags: true
32+
ref: ${{ github.ref }}
33+
persist-credentials: false
34+
35+
- name: Setup Docker buildx
36+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
37+
with:
38+
driver: docker
39+
40+
- name: Log into registry ${{ env.REGISTRY }}
41+
if: github.event_name != 'pull_request'
42+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
43+
with:
44+
registry: ${{ env.REGISTRY }}
45+
username: ${{ github.actor }}
46+
password: ${{ secrets.GITHUB_TOKEN }}
47+
48+
- name: Get base image tag, check
49+
id: base
50+
run: |
51+
export BASE_IMAGE=$( grep BASE_IMAGE= Dockerfile | cut -d= -f2 )
52+
export BASE_IMAGE_NAME=${BASE_IMAGE%:*}
53+
export BASE_TAG=${BASE_IMAGE#*:}
54+
echo "image=$BASE_IMAGE" >> $GITHUB_OUTPUT
55+
echo "name=$BASE_IMAGE_NAME" >> $GITHUB_OUTPUT
56+
echo "tag=$BASE_TAG" >> $GITHUB_OUTPUT
57+
env
58+
if docker manifest inspect $BASE_IMAGE; then
59+
echo "build=false" >> $GITHUB_OUTPUT
60+
else
61+
echo "build=true" >> $GITHUB_OUTPUT
62+
fi
63+
64+
- name: Build base image
65+
if: steps.base.outputs.build == 'true'
66+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
67+
with:
68+
file: Dockerfile.base
69+
load: true
70+
push: ${{ github.event_name != 'pull_request' }}
71+
tags: |
72+
${{ steps.base.outputs.image }}
73+
${{ steps.base.outputs.name }}:latest
74+
platforms: linux/amd64
75+
cache-from: |
76+
type=registry,ref=${{ steps.base.outputs.name }}:latest
77+
cache-to: type=inline
78+
79+
- name: Extract Docker metadata
80+
id: meta
81+
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5
82+
with:
83+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
84+
85+
- name: Build and push Docker image
86+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
87+
with:
88+
context: .
89+
push: ${{ github.event_name != 'pull_request' }}
90+
tags: ${{ steps.meta.outputs.tags }}
91+
labels: ${{ steps.meta.outputs.labels }}
92+
platforms: linux/amd64
93+
cache-from: |
94+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:gha-docker
95+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TARGET_BRANCH }}
96+
type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.tags[0] }}
97+
cache-to: type=inline
98+
env:
99+
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}

Dockerfile

Lines changed: 7 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2323
# SOFTWARE.
2424

25-
# Ubuntu 22.04 LTS - Jammy
26-
ARG BASE_IMAGE=ubuntu:jammy-20240125
25+
ARG BASE_IMAGE=ghcr.io/nipreps/smriprep-base:20251104
2726

2827
#
2928
# Build wheel
@@ -38,7 +37,7 @@ RUN uvx --from=build pyproject-build --installer=uv /src
3837
#
3938

4039
# Utilities for downloading packages
41-
FROM ${BASE_IMAGE} as downloader
40+
FROM ubuntu:jammy-20240125 AS downloader
4241
# Bump the date to current to refresh curl/certificates/etc
4342
RUN echo "2023.07.20"
4443
RUN apt-get update && \
@@ -50,20 +49,8 @@ RUN apt-get update && \
5049
unzip && \
5150
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
5251

53-
# FreeSurfer 7.3.2
54-
FROM downloader as freesurfer
55-
COPY docker/files/freesurfer7.3.2-exclude.txt /usr/local/etc/freesurfer7.3.2-exclude.txt
56-
RUN curl -sSL https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.3.2/freesurfer-linux-ubuntu22_amd64-7.3.2.tar.gz \
57-
| tar zxv --no-same-owner -C /opt --exclude-from=/usr/local/etc/freesurfer7.3.2-exclude.txt
58-
5952
# Micromamba
60-
FROM downloader as micromamba
61-
62-
# Install a C compiler to build extensions when needed.
63-
# traits<6.4 wheels are not available for Python 3.11+, but build easily.
64-
RUN apt-get update && \
65-
apt-get install -y --no-install-recommends build-essential && \
66-
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
53+
FROM downloader AS micromamba
6754

6855
WORKDIR /
6956
# Bump the date to current to force update micromamba
@@ -87,65 +74,20 @@ RUN npm install -g svgo@^3.2.0 bids-validator@^1.14.0 && \
8774
#
8875
# Main stage
8976
#
90-
FROM ${BASE_IMAGE} as smriprep
91-
92-
# Configure apt
93-
ENV DEBIAN_FRONTEND="noninteractive" \
94-
LANG="en_US.UTF-8" \
95-
LC_ALL="en_US.UTF-8"
96-
97-
# Some baseline tools
98-
# bc, tcsh are needed for FreeSurfer
99-
# libglu1-mesa is needed for Connectome Workbench
100-
RUN apt-get update && \
101-
apt-get install -y --no-install-recommends \
102-
bc \
103-
ca-certificates \
104-
curl \
105-
git \
106-
gnupg \
107-
libglu1-mesa \
108-
lsb-release \
109-
netbase \
110-
tcsh \
111-
xvfb && \
112-
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
113-
114-
# Install files from stages
115-
COPY --from=freesurfer /opt/freesurfer /opt/freesurfer
116-
117-
# Simulate SetUpFreeSurfer.sh
118-
ENV OS="Linux" \
119-
FS_OVERRIDE=0 \
120-
FIX_VERTEX_AREA="" \
121-
FSF_OUTPUT_FORMAT="nii.gz" \
122-
FREESURFER_HOME="/opt/freesurfer"
123-
ENV SUBJECTS_DIR="$FREESURFER_HOME/subjects" \
124-
FUNCTIONALS_DIR="$FREESURFER_HOME/sessions" \
125-
MNI_DIR="$FREESURFER_HOME/mni" \
126-
LOCAL_DIR="$FREESURFER_HOME/local" \
127-
MINC_BIN_DIR="$FREESURFER_HOME/mni/bin" \
128-
MINC_LIB_DIR="$FREESURFER_HOME/mni/lib" \
129-
MNI_DATAPATH="$FREESURFER_HOME/mni/data"
130-
ENV PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
131-
MNI_PERL5LIB="$MINC_LIB_DIR/perl5/5.8.5" \
132-
PATH="$FREESURFER_HOME/bin:$FREESURFER_HOME/tktools:$MINC_BIN_DIR:$PATH"
77+
FROM ${BASE_IMAGE} AS smriprep
13378

13479
# Create a shared $HOME directory
13580
RUN useradd -m -s /bin/bash -G users smriprep
13681
WORKDIR /home/smriprep
137-
ENV HOME="/home/smriprep" \
138-
LD_LIBRARY_PATH="/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH"
82+
ENV HOME="/home/smriprep"
13983

14084
COPY --from=micromamba /bin/micromamba /bin/micromamba
14185
COPY --from=micromamba /opt/conda/envs/smriprep /opt/conda/envs/smriprep
14286

14387
ENV MAMBA_ROOT_PREFIX="/opt/conda"
14488
RUN micromamba shell init -s bash && \
14589
echo "micromamba activate smriprep" >> $HOME/.bashrc
146-
ENV PATH="/opt/conda/envs/smriprep/bin:$PATH" \
147-
CPATH="/opt/conda/envs/smriprep/include:$CPATH" \
148-
LD_LIBRARY_PATH="/opt/conda/envs/smriprep/lib:$LD_LIBRARY_PATH"
90+
ENV PATH="/opt/conda/envs/smriprep/bin:$PATH"
14991

15092
# Precaching atlases
15193
COPY scripts/fetch_templates.py fetch_templates.py
@@ -155,20 +97,7 @@ RUN python fetch_templates.py && \
15597
find $HOME/.cache/templateflow -type f -exec chmod go=u {} +
15698

15799
# FSL environment
158-
ENV LANG="C.UTF-8" \
159-
LC_ALL="C.UTF-8" \
160-
PYTHONNOUSERSITE=1 \
161-
FSLDIR="/opt/conda/envs/smriprep" \
162-
FSLOUTPUTTYPE="NIFTI_GZ" \
163-
FSLMULTIFILEQUIT="TRUE" \
164-
FSLLOCKDIR="" \
165-
FSLMACHINELIST="" \
166-
FSLREMOTECALL="" \
167-
FSLGECUDAQ="cuda.q"
168-
169-
# MSM
170-
RUN curl -L -H "Accept: application/octet-stream" https://api.github.com/repos/ecr05/MSM_HOCR/releases/assets/16253707 -o /usr/local/bin/msm \
171-
&& chmod +x /usr/local/bin/msm
100+
ENV FSLDIR="/opt/conda/envs/smriprep"
172101

173102
# Unless otherwise specified each process should only use one thread - nipype
174103
# will handle parallelization

0 commit comments

Comments
 (0)