From 4dbf42c25bc550f3577d11bd1499cf2b0c595f21 Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Sun, 2 Nov 2025 22:33:07 +0530 Subject: [PATCH 1/2] feat: consolidate Dockerfiles with build arguments (Issue #115 Task #4) - Create unified Dockerfile.unified supporting both standalone and Kaapana - Add build-standalone.sh and build-kaapana.sh convenience scripts - Document consolidation approach and testing performed - Uses ARG for BASE_IMAGE and ENV_TYPE configuration Testing completed: - Standalone build: Successfully created (13.2GB) Image ID: 75a626d42f0b - Kaapana build: Successfully created (14GB) Image ID: f662fb55bfee - Both images build without errors - Conditional logic (if statements) work correctly - Entry points properly configured for each environment Integration testing requires: - Actual Kaapana base image (local-only/base-python-cpu:latest) - Kaapana platform deployment - Workflow execution in Kaapana UI --- Docker/DOCKERFILE_MERGE.md | 90 +++++++++++++++++++++++++++++ Docker/Dockerfile.unified | 114 +++++++++++++++++++++++++++++++++++++ Docker/build-kaapana.sh | 17 ++++++ Docker/build-standalone.sh | 16 ++++++ 4 files changed, 237 insertions(+) create mode 100644 Docker/DOCKERFILE_MERGE.md create mode 100644 Docker/Dockerfile.unified create mode 100644 Docker/build-kaapana.sh create mode 100644 Docker/build-standalone.sh diff --git a/Docker/DOCKERFILE_MERGE.md b/Docker/DOCKERFILE_MERGE.md new file mode 100644 index 0000000..891f9dd --- /dev/null +++ b/Docker/DOCKERFILE_MERGE.md @@ -0,0 +1,90 @@ +# Dockerfile Consolidation - Issue #115 Task #4 + +## Overview +This document describes the consolidation of two separate Dockerfiles into a single unified Dockerfile that supports both standalone and Kaapana deployment. + +## Problem +Previously maintained two separate Dockerfiles: +1. `Docker/Dockerfile` - Standalone IVIM fitting +2. `kaapana_ivim_osipi/.../Dockerfile` - Kaapana deployment + +This created: +- Code duplication +- Maintenance overhead +- Inconsistent updates + +## Solution +Created `Docker/Dockerfile.unified` that uses Docker build arguments to support both scenarios. + +## Build Arguments + +| Argument | Default | Options | Purpose | +|----------|---------|---------|---------| +| `BASE_IMAGE` | `python:3.11-slim` | Any valid Docker image | Choose base image | +| `ENV_TYPE` | `standalone` | `standalone` or `kaapana` | Select environment | + +## Building + +### Standalone Build + +Method 1: Using build script +./Docker/build-standalone.sh + +Method 2: Direct docker command +docker build +--build-arg ENV_TYPE=standalone +-t ivim-fitting:standalone +-f Docker/Dockerfile.unified . +### Kaapana Build +Method 1: Using build script +./Docker/build-kaapana.sh + +Method 2: Direct docker command +docker build +--build-arg BASE_IMAGE=local-only/base-python-cpu:latest +--build-arg ENV_TYPE=kaapana +-t ivim-fitting:kaapana +-f Docker/Dockerfile.unified . + +## Testing Completed + +### Local Testing (Docker Desktop - Windows) +- [x] Standalone build succeeds (13.2GB, ID: 75a626d42f0b) +- [x] Kaapana build succeeds (14GB, ID: f662fb55bfee) +- [x] Both conditional logic statements work correctly +- [x] File copying and dependencies install without errors +- [x] Build scripts execute correctly + +### Integration Testing (Requires Kaapana Platform) +- [ ] Runtime with actual `local-only/base-python-cpu:latest` base image +- [ ] Volume mounts work (`OPERATOR_IN_DIR`, `OPERATOR_OUT_DIR`) +- [ ] MinIO data integration +- [ ] Airflow DAG execution in Kaapana UI +- [ ] Workflow submission through web interface + +## Files Modified/Added + +| File | Change | Type | +|------|--------|------| +| `Docker/Dockerfile.unified` | New unified Dockerfile | New | +| `Docker/build-standalone.sh` | Build script for standalone | New | +| `Docker/build-kaapana.sh` | Build script for Kaapana | New | +| `Docker/DOCKERFILE_MERGE.md` | This documentation | New | + +## Notes for Reviewers + +### What I Could Test + Docker build process for both environments + Image creation and basic structure + Build argument passing + Entry point configuration + +### What Needs Your Testing + Runtime behavior in actual Kaapana deployment + Compatibility with Kaapana base image + Workflow execution through Kaapana UI + Data pipeline with MinIO + +## Related Issues +- Addresses #115 (Task #4) +- Related to PR #112 diff --git a/Docker/Dockerfile.unified b/Docker/Dockerfile.unified new file mode 100644 index 0000000..054ff0d --- /dev/null +++ b/Docker/Dockerfile.unified @@ -0,0 +1,114 @@ + +# Unified Dockerfile for IVIM Fitting Method +# +# Supports both standalone and Kaapana deployment using build arguments. +# +# BUILD COMMANDS: +# =============== +# +# For standalone (default): +# $ docker build --build-arg ENV_TYPE=standalone \ +# -t ivim-fitting:standalone \ +# -f Dockerfile.unified . +# +# For Kaapana deployment: +# $ docker build --build-arg BASE_IMAGE=local-only/base-python-cpu:latest \ +# --build-arg ENV_TYPE=kaapana \ +# -t ivim-fitting:kaapana \ +# -f Dockerfile.unified . +# + + +# Step 1: Set base image (before FROM) +ARG BASE_IMAGE=python:3.11-slim + +FROM ${BASE_IMAGE} + +# Step 2: Define build-time configuration +ARG ENV_TYPE=standalone +ARG WORKDIR_PATH=/usr/src/app + +# Metadata labels +LABEL IMAGE="ivim-fitting-method" +LABEL VERSION="0.2.4" +LABEL BUILD_IGNORE="False" + + +# COMMON SETUP (applies to both standalone and Kaapana) +# Install common system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + + +# ENVIRONMENT-SPECIFIC SETUP +# Kaapana setup +RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ + echo "=== Configuring for KAAPANA ==="; \ + apt-get update && apt-get install -y --no-install-recommends \ + texlive-xetex \ + texlive-fonts-recommended \ + texlive-plain-generic \ + git && \ + apt-get clean && rm -rf /var/lib/apt/lists/*; \ + fi + +# Standalone setup +RUN if [ "$ENV_TYPE" = "standalone" ]; then \ + echo "=== Configuring for STANDALONE ==="; \ + fi + +# CODE ACQUISITION +# For Kaapana: Clone from GitHub and install dependencies +RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ + mkdir -p /kaapana/app && \ + cd /kaapana/app && \ + git clone https://github.com/OSIPI/TF2.4_IVIM-MRI_CodeCollection.git && \ + cd TF2.4_IVIM-MRI_CodeCollection && \ + pip install --no-cache-dir -r requirements.txt; \ + fi + +# For Standalone: Copy requirements and install +RUN if [ "$ENV_TYPE" = "standalone" ]; then \ + mkdir -p /usr/src/app; \ + fi + +# Set working directory +WORKDIR ${WORKDIR_PATH} + + +# COPY FILES AND INSTALL DEPENDENCIES +# Copy requirements.txt from project root to current working directory +COPY requirements.txt ./ + +# Copy source code (WrapImage and other files) +COPY WrapImage ./WrapImage/ + +# Install Python dependencies for standalone +RUN if [ "$ENV_TYPE" = "standalone" ]; then \ + pip install --no-cache-dir -r requirements.txt; \ + fi + + +# SET ENTRYPOINT +# Kaapana entrypoint with verbose output +RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ + echo "Kaapana wrapper selected"; \ + else \ + echo "Standalone wrapper selected"; \ + fi + +# Use entrypoint script approach for flexibility +RUN echo '#!/bin/bash' > /entrypoint.sh && \ + if [ "$ENV_TYPE" = "kaapana" ]; then \ + echo 'cd /kaapana/app/TF2.4_IVIM-MRI_CodeCollection' >> /entrypoint.sh && \ + echo 'exec python3 -u -m WrapImage.nifti_wrapper_kaapana "$@"' >> /entrypoint.sh; \ + else \ + echo 'cd /usr/src/app' >> /entrypoint.sh && \ + echo 'exec python3 -m WrapImage.nifti_wrapper "$@"' >> /entrypoint.sh; \ + fi && \ + chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] +CMD [] diff --git a/Docker/build-kaapana.sh b/Docker/build-kaapana.sh new file mode 100644 index 0000000..a90fcd1 --- /dev/null +++ b/Docker/build-kaapana.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +echo " Building IVIM Fitting for KAAPANA..." +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +docker build \ + --build-arg BASE_IMAGE=local-only/base-python-cpu:latest \ + --build-arg ENV_TYPE=kaapana \ + -t ivim-fitting:kaapana \ + -f Docker/Dockerfile.unified \ + . + +echo "" +echo " Build successful!" +echo " Image: ivim-fitting:kaapana" +docker images | grep "ivim-fitting.*kaapana" diff --git a/Docker/build-standalone.sh b/Docker/build-standalone.sh new file mode 100644 index 0000000..2af6da5 --- /dev/null +++ b/Docker/build-standalone.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +echo " Building IVIM Fitting for STANDALONE..." +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +docker build \ + --build-arg ENV_TYPE=standalone \ + -t ivim-fitting:standalone \ + -f Docker/Dockerfile.unified \ + . + +echo "" +echo " Build successful!" +echo " Image: ivim-fitting:standalone" +docker images | grep "ivim-fitting.*standalone" From c1c0b2b9f0880a24f801e25a6e013a96df9dfffe Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Wed, 19 Nov 2025 23:18:08 +0530 Subject: [PATCH 2/2] refactor: convert to multi-stage Docker build per reviewer feedback - Refactored Dockerfile.unified to use multi-stage builds - Eliminated conditional if statements for cleaner code flow - Separated base, standalone, and kaapana stages - Updated build scripts to use --target flag Testing: - Standalone build succeeds (13.2GB, ID: 7b877408f593) - Kaapana build succeeds (14GB, ID: 8d8c72fbd004) - Both images build without errors - Multi-stage approach eliminates conditionals - Build flow is now easier to follow --- Docker/DOCKERFILE_MERGE.md | 74 +++++++++++++-------- Docker/Dockerfile.unified | 131 +++++++++++++++---------------------- Docker/build-kaapana.sh | 10 +-- Docker/build-standalone.sh | 10 +-- 4 files changed, 109 insertions(+), 116 deletions(-) diff --git a/Docker/DOCKERFILE_MERGE.md b/Docker/DOCKERFILE_MERGE.md index 891f9dd..0ea422e 100644 --- a/Docker/DOCKERFILE_MERGE.md +++ b/Docker/DOCKERFILE_MERGE.md @@ -1,27 +1,44 @@ # Dockerfile Consolidation - Issue #115 Task #4 ## Overview + This document describes the consolidation of two separate Dockerfiles into a single unified Dockerfile that supports both standalone and Kaapana deployment. ## Problem + Previously maintained two separate Dockerfiles: + 1. `Docker/Dockerfile` - Standalone IVIM fitting 2. `kaapana_ivim_osipi/.../Dockerfile` - Kaapana deployment This created: + - Code duplication - Maintenance overhead - Inconsistent updates ## Solution -Created `Docker/Dockerfile.unified` that uses Docker build arguments to support both scenarios. -## Build Arguments +Created `Docker/Dockerfile.unified` using **Docker multi-stage builds** with named stages: + +- `base` - Common dependencies shared by both environments +- `standalone` - Standalone IVIM fitting stage (target) +- `kaapana` - Kaapana deployment stage (target) + +### Why Multi-Stage? + +Following reviewer feedback, this approach: +Eliminates conditional `if` statements for cleaner code +Makes the build flow easier to follow +Allows Docker to better cache and optimize layers +Each stage is self-contained and easier to debug + +### Build Arguments -| Argument | Default | Options | Purpose | -|----------|---------|---------|---------| -| `BASE_IMAGE` | `python:3.11-slim` | Any valid Docker image | Choose base image | -| `ENV_TYPE` | `standalone` | `standalone` or `kaapana` | Select environment | +| Argument | Default | Purpose | +| ------------ | ------------------ | --------------------------------------------- | +| `BASE_IMAGE` | `python:3.11-slim` | Specify base Docker image | +| `--target` | (required) | Choose build stage: `standalone` or `kaapana` | ## Building @@ -31,31 +48,33 @@ Method 1: Using build script ./Docker/build-standalone.sh Method 2: Direct docker command -docker build ---build-arg ENV_TYPE=standalone +docker build --target standalone -t ivim-fitting:standalone -f Docker/Dockerfile.unified . + ### Kaapana Build + Method 1: Using build script ./Docker/build-kaapana.sh Method 2: Direct docker command -docker build +docker build --target kaapana --build-arg BASE_IMAGE=local-only/base-python-cpu:latest ---build-arg ENV_TYPE=kaapana -t ivim-fitting:kaapana -f Docker/Dockerfile.unified . ## Testing Completed -### Local Testing (Docker Desktop - Windows) +### Local Testing (Docker Desktop - Windows) + - [x] Standalone build succeeds (13.2GB, ID: 75a626d42f0b) - [x] Kaapana build succeeds (14GB, ID: f662fb55bfee) - [x] Both conditional logic statements work correctly - [x] File copying and dependencies install without errors - [x] Build scripts execute correctly -### Integration Testing (Requires Kaapana Platform) +### Integration Testing (Requires Kaapana Platform) + - [ ] Runtime with actual `local-only/base-python-cpu:latest` base image - [ ] Volume mounts work (`OPERATOR_IN_DIR`, `OPERATOR_OUT_DIR`) - [ ] MinIO data integration @@ -64,27 +83,30 @@ docker build ## Files Modified/Added -| File | Change | Type | -|------|--------|------| -| `Docker/Dockerfile.unified` | New unified Dockerfile | New | -| `Docker/build-standalone.sh` | Build script for standalone | New | -| `Docker/build-kaapana.sh` | Build script for Kaapana | New | -| `Docker/DOCKERFILE_MERGE.md` | This documentation | New | +| File | Change | Type | +| ---------------------------- | --------------------------- | ---- | +| `Docker/Dockerfile.unified` | New unified Dockerfile | New | +| `Docker/build-standalone.sh` | Build script for standalone | New | +| `Docker/build-kaapana.sh` | Build script for Kaapana | New | +| `Docker/DOCKERFILE_MERGE.md` | This documentation | New | ## Notes for Reviewers ### What I Could Test - Docker build process for both environments - Image creation and basic structure - Build argument passing - Entry point configuration + +Docker build process for both environments +Image creation and basic structure +Build argument passing +Entry point configuration ### What Needs Your Testing - Runtime behavior in actual Kaapana deployment - Compatibility with Kaapana base image - Workflow execution through Kaapana UI - Data pipeline with MinIO + +Runtime behavior in actual Kaapana deployment +Compatibility with Kaapana base image +Workflow execution through Kaapana UI +Data pipeline with MinIO ## Related Issues + - Addresses #115 (Task #4) - Related to PR #112 diff --git a/Docker/Dockerfile.unified b/Docker/Dockerfile.unified index 054ff0d..fe4f233 100644 --- a/Docker/Dockerfile.unified +++ b/Docker/Dockerfile.unified @@ -1,113 +1,84 @@ +# Multi-Stage Unified Dockerfile for IVIM Fitting Method -# Unified Dockerfile for IVIM Fitting Method -# -# Supports both standalone and Kaapana deployment using build arguments. +# Supports both standalone and Kaapana deployment using multi-stage builds. +# This approach is cleaner than using if statements throughout. # # BUILD COMMANDS: -# =============== +# Note: Run from PROJECT ROOT, not from Docker/ folder! # -# For standalone (default): -# $ docker build --build-arg ENV_TYPE=standalone \ -# -t ivim-fitting:standalone \ -# -f Dockerfile.unified . +# For standalone: +# $ docker build --target standalone -t ivim-fitting:standalone -f Docker/Dockerfile.unified . # -# For Kaapana deployment: -# $ docker build --build-arg BASE_IMAGE=local-only/base-python-cpu:latest \ -# --build-arg ENV_TYPE=kaapana \ +# For Kaapana: +# $ docker build --target kaapana \ +# --build-arg BASE_IMAGE=local-only/base-python-cpu:latest \ # -t ivim-fitting:kaapana \ -# -f Dockerfile.unified . +# -f Docker/Dockerfile.unified . # - -# Step 1: Set base image (before FROM) +# Build argument for base image (default for standalone) ARG BASE_IMAGE=python:3.11-slim -FROM ${BASE_IMAGE} - -# Step 2: Define build-time configuration -ARG ENV_TYPE=standalone -ARG WORKDIR_PATH=/usr/src/app +# Stage: BASE - Common setup shared by both environments +FROM ${BASE_IMAGE} AS base # Metadata labels LABEL IMAGE="ivim-fitting-method" LABEL VERSION="0.2.4" LABEL BUILD_IGNORE="False" - -# COMMON SETUP (applies to both standalone and Kaapana) # Install common system dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libssl-dev \ && rm -rf /var/lib/apt/lists/* +# Stage: STANDALONE - For standalone IVIM fitting +FROM base AS standalone -# ENVIRONMENT-SPECIFIC SETUP -# Kaapana setup -RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ - echo "=== Configuring for KAAPANA ==="; \ - apt-get update && apt-get install -y --no-install-recommends \ - texlive-xetex \ - texlive-fonts-recommended \ - texlive-plain-generic \ - git && \ - apt-get clean && rm -rf /var/lib/apt/lists/*; \ - fi - -# Standalone setup -RUN if [ "$ENV_TYPE" = "standalone" ]; then \ - echo "=== Configuring for STANDALONE ==="; \ - fi - -# CODE ACQUISITION -# For Kaapana: Clone from GitHub and install dependencies -RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ - mkdir -p /kaapana/app && \ - cd /kaapana/app && \ - git clone https://github.com/OSIPI/TF2.4_IVIM-MRI_CodeCollection.git && \ - cd TF2.4_IVIM-MRI_CodeCollection && \ - pip install --no-cache-dir -r requirements.txt; \ - fi - -# For Standalone: Copy requirements and install -RUN if [ "$ENV_TYPE" = "standalone" ]; then \ - mkdir -p /usr/src/app; \ - fi - -# Set working directory -WORKDIR ${WORKDIR_PATH} - - -# COPY FILES AND INSTALL DEPENDENCIES -# Copy requirements.txt from project root to current working directory -COPY requirements.txt ./ +WORKDIR /usr/src/app -# Copy source code (WrapImage and other files) +# Copy requirements and source code +COPY requirements.txt ./ COPY WrapImage ./WrapImage/ -# Install Python dependencies for standalone -RUN if [ "$ENV_TYPE" = "standalone" ]; then \ - pip install --no-cache-dir -r requirements.txt; \ - fi +# Install Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Create entrypoint script +RUN echo '#!/bin/bash' > /entrypoint.sh && \ + echo 'cd /usr/src/app' >> /entrypoint.sh && \ + echo 'exec python3 -m WrapImage.nifti_wrapper "$@"' >> /entrypoint.sh && \ + chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] +CMD [] + +# Stage: KAAPANA - For Kaapana platform deployment +FROM base AS kaapana + +# Install additional Kaapana dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + texlive-xetex \ + texlive-fonts-recommended \ + texlive-plain-generic \ + git && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +WORKDIR /kaapana/app +# Clone IVIM code collection and install dependencies +RUN git clone https://github.com/OSIPI/TF2.4_IVIM-MRI_CodeCollection.git && \ + cd TF2.4_IVIM-MRI_CodeCollection && \ + pip install --no-cache-dir -r requirements.txt -# SET ENTRYPOINT -# Kaapana entrypoint with verbose output -RUN if [ "$ENV_TYPE" = "kaapana" ]; then \ - echo "Kaapana wrapper selected"; \ - else \ - echo "Standalone wrapper selected"; \ - fi +# Set final working directory +WORKDIR /kaapana/app/TF2.4_IVIM-MRI_CodeCollection -# Use entrypoint script approach for flexibility +# Create entrypoint script RUN echo '#!/bin/bash' > /entrypoint.sh && \ - if [ "$ENV_TYPE" = "kaapana" ]; then \ - echo 'cd /kaapana/app/TF2.4_IVIM-MRI_CodeCollection' >> /entrypoint.sh && \ - echo 'exec python3 -u -m WrapImage.nifti_wrapper_kaapana "$@"' >> /entrypoint.sh; \ - else \ - echo 'cd /usr/src/app' >> /entrypoint.sh && \ - echo 'exec python3 -m WrapImage.nifti_wrapper "$@"' >> /entrypoint.sh; \ - fi && \ + echo 'cd /kaapana/app/TF2.4_IVIM-MRI_CodeCollection' >> /entrypoint.sh && \ + echo 'exec python3 -u -m WrapImage.nifti_wrapper_kaapana "$@"' >> /entrypoint.sh && \ chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] diff --git a/Docker/build-kaapana.sh b/Docker/build-kaapana.sh index a90fcd1..e9dcfea 100644 --- a/Docker/build-kaapana.sh +++ b/Docker/build-kaapana.sh @@ -1,17 +1,17 @@ #!/bin/bash set -e -echo " Building IVIM Fitting for KAAPANA..." -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📦 Building IVIM Fitting for KAAPANA (multi-stage)..." +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" docker build \ + --target kaapana \ --build-arg BASE_IMAGE=local-only/base-python-cpu:latest \ - --build-arg ENV_TYPE=kaapana \ -t ivim-fitting:kaapana \ -f Docker/Dockerfile.unified \ . echo "" -echo " Build successful!" -echo " Image: ivim-fitting:kaapana" +echo "Build successful!" +echo "Image: ivim-fitting:kaapana" docker images | grep "ivim-fitting.*kaapana" diff --git a/Docker/build-standalone.sh b/Docker/build-standalone.sh index 2af6da5..24e849c 100644 --- a/Docker/build-standalone.sh +++ b/Docker/build-standalone.sh @@ -1,16 +1,16 @@ #!/bin/bash set -e -echo " Building IVIM Fitting for STANDALONE..." -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "📦 Building IVIM Fitting for STANDALONE (multi-stage)..." +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" docker build \ - --build-arg ENV_TYPE=standalone \ + --target standalone \ -t ivim-fitting:standalone \ -f Docker/Dockerfile.unified \ . echo "" -echo " Build successful!" -echo " Image: ivim-fitting:standalone" +echo "Build successful!" +echo "Image: ivim-fitting:standalone" docker images | grep "ivim-fitting.*standalone"