From de280fd916780eb6a867933a39b399df2522ea52 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 12:08:33 -0500 Subject: [PATCH 01/32] adding initial container support --- Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 89e993283..c10e768df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,15 @@ -FROM python:3.12-slim AS builder - -RUN pip install --upgrade pip -RUN pip install chainforge --no-cache-dir +FROM python:3.12-slim +RUN apt-get --allow-releaseinfo-change update && apt-get install -y \ + build-essential && rm -rf /var/lib/apt/lists/* + WORKDIR /chainforge +RUN pip install --upgrade pip +COPY chainforge/requirements.txt . +RUN pip install -r requirements.txt +COPY . ./chainforge +RUN python setup.py sdist +RUN pip install -e . EXPOSE 8000 ENTRYPOINT [ "chainforge", "serve", "--host", "0.0.0.0" ] From 87fb83a76bc16e11c38e727beb343701ca076d2b Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 12:17:47 -0500 Subject: [PATCH 02/32] adding initial container support --- Dockerfile | 4 ++-- docker-compose.yml | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index c10e768df..e820d830a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,13 +2,13 @@ FROM python:3.12-slim RUN apt-get --allow-releaseinfo-change update && apt-get install -y \ build-essential && rm -rf /var/lib/apt/lists/* - + WORKDIR /chainforge RUN pip install --upgrade pip COPY chainforge/requirements.txt . RUN pip install -r requirements.txt -COPY . ./chainforge +COPY . . RUN python setup.py sdist RUN pip install -e . EXPOSE 8000 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..c02efca9e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +services: + chainforge: + image: :gauransh/chainforge:rag + ports: + - "8000:8000" + volumes: + - ./data:~/.local/share/chainforge + command: ["chainforge", "serve", "--host", "0.0.0.0"] \ No newline at end of file From b34f6c9cc46807f3ec05e3749f6b3f26b535a344 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 13:28:15 -0500 Subject: [PATCH 03/32] reducing docker image size --- Dockerfile | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index e820d830a..ccd1b2cca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,12 @@ -FROM python:3.12-slim +FROM python:3.12-alpine -RUN apt-get --allow-releaseinfo-change update && apt-get install -y \ - build-essential && rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache build-base git WORKDIR /chainforge -RUN pip install --upgrade pip +RUN pip install --no-cache-dir --upgrade pip COPY chainforge/requirements.txt . -RUN pip install -r requirements.txt +RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN python setup.py sdist RUN pip install -e . From f517a92a7cb003a8e72e0d5a2a3dd58048fe0e79 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 13:44:44 -0500 Subject: [PATCH 04/32] reducing docker image size --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ccd1b2cca..6ec235138 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM python:3.12-alpine -RUN apk add --no-cache build-base git +RUN apk update && apk add --virtual build-dependencies build-base gcc wget git WORKDIR /chainforge From bf5c73ac3f6d27b2ec830b17b82bcc2ce26f1741 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 13:58:40 -0500 Subject: [PATCH 05/32] reducing docker image size --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6ec235138..e8d59346c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12-alpine +FROM python:3.12-slim RUN apk update && apk add --virtual build-dependencies build-base gcc wget git From ec15faebc3d0e5aaa599c0890c964d471154272e Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 13 Nov 2025 13:59:33 -0500 Subject: [PATCH 06/32] reducing docker image size --- Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e8d59346c..4e7f27b9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,9 @@ FROM python:3.12-slim -RUN apk update && apk add --virtual build-dependencies build-base gcc wget git +RUN apt-get --allow-releaseinfo-change update && apt-get install -y \ + build-essential \ + git \ + && rm -rf /var/lib/apt/lists/* WORKDIR /chainforge From 34837b140f0e062196c28c1a857e77547b487277 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 10:37:30 -0500 Subject: [PATCH 07/32] revamp docker --- Dockerfile | 76 +++++++++++++++++++++++++++++++++++++++++----- docker-compose.yml | 25 +++++++++++++-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e7f27b9b..65541e474 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,77 @@ -FROM python:3.12-slim +# Multi-stage build: Stage 1 - Build React frontend +FROM node:20-slim AS frontend-builder + +WORKDIR /app + +# Copy package files and install dependencies +COPY chainforge/react-server/package*.json ./ +RUN npm ci --legacy-peer-deps --omit=dev -RUN apt-get --allow-releaseinfo-change update && apt-get install -y \ +# Copy source files and build +COPY chainforge/react-server/ ./ +RUN npm run build + +# Stage 2 - Build Python dependencies +FROM python:3.12-slim AS python-builder + +# Install only the build dependencies we need +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends \ build-essential \ git \ && rm -rf /var/lib/apt/lists/* -WORKDIR /chainforge +WORKDIR /build -RUN pip install --no-cache-dir --upgrade pip +# Install Python dependencies with no cache +RUN pip install --no-cache-dir --upgrade pip setuptools wheel + +# Copy requirements and install to a specific directory COPY chainforge/requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt -COPY . . -RUN python setup.py sdist -RUN pip install -e . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt + +# Copy project files and build the package +COPY setup.py README.md ./ +COPY chainforge/ ./chainforge/ +RUN pip install --no-cache-dir --prefix=/install -e . + +# Stage 3 - Final minimal runtime image +FROM python:3.12-slim + +# Install only runtime dependencies (no build tools) +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends \ + git \ + libgomp1 \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean + +WORKDIR /chainforge + +# Copy Python packages from builder +COPY --from=python-builder /install /usr/local + +# Copy only necessary application files +COPY setup.py README.md ./ +COPY chainforge/ ./chainforge/ + +# Copy the built React app from the frontend-builder stage +COPY --from=frontend-builder /app/build ./chainforge/react-server/build + +# Clean up any unnecessary files to reduce image size +RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ + find /usr/local -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \ + find /usr/local -name "*.pyc" -delete && \ + find /usr/local -name "*.pyo" -delete && \ + find /usr/local -name "*.md" -delete 2>/dev/null || true + +# Run as non-root user for security +RUN useradd -m -u 1000 chainforge && \ + mkdir -p /home/chainforge/.local/share/chainforge && \ + chown -R chainforge:chainforge /chainforge /home/chainforge + +USER chainforge + EXPOSE 8000 + ENTRYPOINT [ "chainforge", "serve", "--host", "0.0.0.0" ] diff --git a/docker-compose.yml b/docker-compose.yml index c02efca9e..f44dc697e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,27 @@ services: chainforge: - image: :gauransh/chainforge:rag + build: + context: . + dockerfile: Dockerfile + image: gauransh/chainforge:rag + container_name: chainforge ports: - "8000:8000" volumes: - - ./data:~/.local/share/chainforge - command: ["chainforge", "serve", "--host", "0.0.0.0"] \ No newline at end of file + # Mount data directory for persistent storage + - chainforge-data:/home/chainforge/.local/share/chainforge + environment: + - FLASK_ENV=production + # Add API keys as environment variables if needed + # - OPENAI_API_KEY=${OPENAI_API_KEY} + # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + # - COHERE_API_KEY=${COHERE_API_KEY} + # - GOOGLE_API_KEY=${GOOGLE_API_KEY} + # - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} + # - HUGGINGFACE_API_KEY=${HUGGINGFACE_API_KEY} + restart: unless-stopped + +# Named volume for persistent data +volumes: + chainforge-data: + driver: local \ No newline at end of file From aaa18bb48c0e2d761a13c078e63e07ebbce1a974 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 10:37:40 -0500 Subject: [PATCH 08/32] revamp docker --- .dockerignore | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..00f7280af --- /dev/null +++ b/.dockerignore @@ -0,0 +1,106 @@ +# Git files +.git +.gitignore +.gitattributes +.github + +# Documentation (we only need README.md) +docs/ +INSTALL_GUIDE.md +CONTRIBUTING.md +LICENSE +*.md +!README.md + +# Development files +.vscode +.idea +*.swp +*.swo +*~ +.editorconfig + +# Python cache and build artifacts +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info +dist +build +.pytest_cache +.coverage +htmlcov +*.egg +MANIFEST +.mypy_cache +.ruff_cache +.tox +.nox +*.cover +.hypothesis + +# Node (we'll install and build in Docker) +chainforge/react-server/node_modules +chainforge/react-server/.pnp +chainforge/react-server/.pnp.js +chainforge/react-server/coverage +chainforge/react-server/build + +# Testing and development +tests/ +test/ +*.test.js +*.test.ts +*.test.tsx +*.spec.js +*.spec.ts +*.spec.tsx +coverage/ +.coverage +*.log +*.logs + +# Environment files +.env +.env.* +!.env.example +*.local + +# ChainForge specific +chainforge/cache +chainforge/examples/oaievals/ +chainforge_assets/ +packages/ +jobs/ +data/ + +# Docker files (avoid recursive copying) +Dockerfile* +docker-compose*.yml +.dockerignore + +# CI/CD +.circleci +.travis.yml +.gitlab-ci.yml +azure-pipelines.yml + +# IDE and editor files +*.sublime-* +.vscode +.idea +*.iml + +# OS files +.DS_Store +Thumbs.db +Desktop.ini + +# Temporary files +*.tmp +*.temp +*.bak +*.swp +*~ From ebcf4f60bd157b670ef6dce1b433d13b5681ee88 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 10:52:19 -0500 Subject: [PATCH 09/32] revamp docker for prod and dev --- DOCKER.md | 220 +++++++++++++++++++++++++++++++++++++++++ Dockerfile | 4 +- Dockerfile.dev | 41 ++++++++ docker-compose.dev.yml | 22 +++++ docker-compose.yml | 7 ++ 5 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 DOCKER.md create mode 100644 Dockerfile.dev create mode 100644 docker-compose.dev.yml diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 000000000..19a5b69b2 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,220 @@ +# ChainForge Docker Setup + +This document describes how to run ChainForge using Docker in both development and production environments. + +## Prerequisites + +- Docker (version 20.10 or later) +- Docker Compose (version 2.0 or later) + +## Production Setup + +### Using Docker Compose (Recommended) + +Build and run ChainForge in production mode: + +```bash +docker-compose up -d +``` + +This will: +- Build the production image with the optimized multi-stage build +- Start the ChainForge server on port 8000 +- Create a persistent volume for user data +- Restart automatically if the container crashes + +Access ChainForge at: http://localhost:8000 + +### Using Docker CLI + +Build the production image: + +```bash +docker build -t chainforge:latest . +``` + +Run the container: + +```bash +docker run -d \ + -p 8000:8000 \ + -v chainforge-data:/home/chainforge/.local/share/chainforge \ + --name chainforge \ + --restart unless-stopped \ + chainforge:latest +``` + +## Development Setup + +### Using Docker Compose (Recommended) + +For development with hot-reloading: + +```bash +docker-compose -f docker-compose.dev.yml up +``` + +This will: +- Build the development image with all dev dependencies +- Start the React dev server on port 3000 +- Start the Python backend on port 8000 +- Mount your source code for hot-reloading +- Enable file watching with polling (works better in Docker) + +Access the development server at: http://localhost:3000 + +### Using Docker CLI + +Build the development image: + +```bash +docker build -f Dockerfile.dev -t chainforge:dev . +``` + +Run the container with volume mounts: + +```bash +docker run -it \ + -p 3000:3000 \ + -p 8000:8000 \ + -v $(pwd)/chainforge/react-server:/app \ + -v $(pwd)/chainforge:/chainforge/chainforge \ + -v /app/node_modules \ + -e CHOKIDAR_USEPOLLING=true \ + --name chainforge-dev \ + chainforge:dev +``` + +## Managing Containers + +### View logs + +```bash +# Production +docker-compose logs -f + +# Development +docker-compose -f docker-compose.dev.yml logs -f +``` + +### Stop containers + +```bash +# Production +docker-compose down + +# Development +docker-compose -f docker-compose.dev.yml down +``` + +### Rebuild images + +```bash +# Production +docker-compose build --no-cache + +# Development +docker-compose -f docker-compose.dev.yml build --no-cache +``` + +### Remove volumes (delete all data) + +```bash +docker-compose down -v +``` + +## Environment Variables + +You can set API keys and other environment variables by: + +1. Creating a `.env` file in the project root +2. Adding your variables (they're already templated in docker-compose.yml): + +```env +OPENAI_API_KEY=your_key_here +ANTHROPIC_API_KEY=your_key_here +COHERE_API_KEY=your_key_here +GOOGLE_API_KEY=your_key_here +DEEPSEEK_API_KEY=your_key_here +HUGGINGFACE_API_KEY=your_key_here +``` + +3. Uncommenting the relevant lines in `docker-compose.yml` + +## Docker Image Structure + +### Production Image (Dockerfile) + +Multi-stage build optimized for size: + +1. **Stage 1**: Build React frontend with all dependencies +2. **Stage 2**: Build Python dependencies +3. **Stage 3**: Create minimal runtime image with only necessary files + +### Development Image (Dockerfile.dev) + +Single-stage build with: +- All dev dependencies for hot-reloading +- Both Node.js and Python environments +- Volume mounts for live code updates + +## Troubleshooting + +### ESLint Config Error + +If you see "ESLint couldn't find the config 'semistandard'": +- This is fixed in the current Dockerfile by installing devDependencies +- Rebuild the image: `docker-compose build --no-cache` + +### Port Already in Use + +If ports 3000 or 8000 are already in use: +- Change the port mapping in `docker-compose.yml` or `docker-compose.dev.yml` +- Example: `"3001:3000"` to use port 3001 on your host + +### File Changes Not Reflected (Development) + +If hot-reloading isn't working: +- Ensure `CHOKIDAR_USEPOLLING=true` is set +- Check that volumes are properly mounted +- Try restarting the development container + +### Permission Issues + +If you encounter permission errors: +- The production image runs as a non-root user (uid 1000) +- Ensure your volume permissions match this user +- You can adjust the UID in the Dockerfile if needed + +## Performance Tips + +### Production + +- Use the multi-stage build (default Dockerfile) +- The image is optimized to be under 1GB +- Unnecessary files and caches are cleaned during build + +### Development + +- Keep `node_modules` in a named volume (don't mount from host) +- Use polling for file watching in Docker (`CHOKIDAR_USEPOLLING=true`) +- Consider allocating more memory to Docker if builds are slow + +## Pushing to Registry + +To push the production image to a registry: + +```bash +# Tag the image +docker tag chainforge:latest your-registry/chainforge:tag + +# Push to registry +docker push your-registry/chainforge:tag +``` + +Or let docker-compose handle it: + +```bash +docker-compose build +docker-compose push +``` diff --git a/Dockerfile b/Dockerfile index 65541e474..6b7985779 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,9 @@ FROM node:20-slim AS frontend-builder WORKDIR /app -# Copy package files and install dependencies +# Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps --omit=dev +RUN npm ci --legacy-peer-deps # Copy source files and build COPY chainforge/react-server/ ./ diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 000000000..6d5f4d31f --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,41 @@ +# Development Dockerfile with hot-reloading +FROM node:20-slim AS frontend + +WORKDIR /app + +# Install Python for the backend +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends \ + python3 \ + python3-pip \ + python3-venv \ + git \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +# Copy package files first for better caching +COPY chainforge/react-server/package*.json ./ + +# Install Node dependencies (including dev dependencies for development) +RUN npm install --legacy-peer-deps + +# Copy Python requirements and install +WORKDIR /chainforge +COPY chainforge/requirements.txt ./chainforge/ +COPY setup.py README.md ./ +RUN pip3 install --no-cache-dir --break-system-packages -r chainforge/requirements.txt + +# Copy the rest of the application +COPY chainforge/ ./chainforge/ +COPY chainforge/react-server/ /app/ + +# Install chainforge in development mode +RUN pip3 install --no-cache-dir --break-system-packages -e . + +WORKDIR /app + +# Expose ports for React dev server and Python backend +EXPOSE 3000 8000 + +# Default command runs the React dev server +CMD ["npm", "start"] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 000000000..0765b16fd --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + chainforge-dev: + build: + context: . + dockerfile: Dockerfile.dev + ports: + - "3000:3000" # React dev server + - "8000:8000" # Python backend + environment: + - NODE_ENV=development + - CHOKIDAR_USEPOLLING=true # Enable polling for file watching in Docker + volumes: + # Mount source code for hot-reloading + - ./chainforge/react-server:/app + - ./chainforge:/chainforge/chainforge + # Exclude node_modules from mounting (use container's version) + - /app/node_modules + stdin_open: true + tty: true + command: npm start diff --git a/docker-compose.yml b/docker-compose.yml index f44dc697e..9ac30ccbb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: # Mount data directory for persistent storage - chainforge-data:/home/chainforge/.local/share/chainforge environment: + - NODE_ENV=production - FLASK_ENV=production # Add API keys as environment variables if needed # - OPENAI_API_KEY=${OPENAI_API_KEY} @@ -20,6 +21,12 @@ services: # - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} # - HUGGINGFACE_API_KEY=${HUGGINGFACE_API_KEY} restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8000 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s # Named volume for persistent data volumes: From 5fc74be2f8e3df07a27d8d57bb187c3f529e08f2 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 11:17:27 -0500 Subject: [PATCH 10/32] CPU only torch to reduce image size --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 6b7985779..7452ecbd2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,9 @@ WORKDIR /build # Install Python dependencies with no cache RUN pip install --no-cache-dir --upgrade pip setuptools wheel +# Install CPU only torch +RUN pip install --no-cache-dir --prefix=/install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu + # Copy requirements and install to a specific directory COPY chainforge/requirements.txt . RUN pip install --no-cache-dir --prefix=/install -r requirements.txt From 8960bf385e36219f0797d67c711f88c1e4d43e75 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 11:23:34 -0500 Subject: [PATCH 11/32] CPU only torch to reduce image size with constraints --- Dockerfile | 6 ++---- chainforge/constraints.txt | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 chainforge/constraints.txt diff --git a/Dockerfile b/Dockerfile index 7452ecbd2..e7a4d7aad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,12 +26,10 @@ WORKDIR /build # Install Python dependencies with no cache RUN pip install --no-cache-dir --upgrade pip setuptools wheel -# Install CPU only torch -RUN pip install --no-cache-dir --prefix=/install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu - # Copy requirements and install to a specific directory COPY chainforge/requirements.txt . -RUN pip install --no-cache-dir --prefix=/install -r requirements.txt +COPY chainforge/constraints.txt . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt -c constraints.txt # Copy project files and build the package COPY setup.py README.md ./ diff --git a/chainforge/constraints.txt b/chainforge/constraints.txt new file mode 100644 index 000000000..379510e80 --- /dev/null +++ b/chainforge/constraints.txt @@ -0,0 +1,4 @@ +--extra-index-url https://download.pytorch.org/whl/cpu +torch +torchvision +torchaudio \ No newline at end of file From ac4a6bac57e182d6438c095d5b7b4dbbf48234e6 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 11:35:56 -0500 Subject: [PATCH 12/32] docker bugfix --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e7a4d7aad..cffeb79e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,7 +34,7 @@ RUN pip install --no-cache-dir --prefix=/install -r requirements.txt -c constrai # Copy project files and build the package COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip install --no-cache-dir --prefix=/install -e . +RUN pip install --no-cache-dir --prefix=/install . # Stage 3 - Final minimal runtime image FROM python:3.12-slim From 3e82dadac3d9a7dce2a4fe8c55521787cd72b409 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 11:49:31 -0500 Subject: [PATCH 13/32] docker bugfix --- Dockerfile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index cffeb79e0..fdd5b7e7d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,12 +52,8 @@ WORKDIR /chainforge # Copy Python packages from builder COPY --from=python-builder /install /usr/local -# Copy only necessary application files -COPY setup.py README.md ./ -COPY chainforge/ ./chainforge/ - -# Copy the built React app from the frontend-builder stage -COPY --from=frontend-builder /app/build ./chainforge/react-server/build +# Copy the built React app from the frontend-builder stage to the installed package location +COPY --from=frontend-builder /app/build /usr/local/lib/python3.12/site-packages/chainforge/react-server/build # Clean up any unnecessary files to reduce image size RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ From 83924580ddad8da2f62910ad830b73d87029dcb8 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 12:03:02 -0500 Subject: [PATCH 14/32] completely working CPU only build --- DOCKER.md | 98 +++++++------------------------------------------------ 1 file changed, 11 insertions(+), 87 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 19a5b69b2..456b31988 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,24 +1,24 @@ # ChainForge Docker Setup -This document describes how to run ChainForge using Docker in both development and production environments. +This document describes how to run ChainForge using Docker. ## Prerequisites - Docker (version 20.10 or later) - Docker Compose (version 2.0 or later) -## Production Setup +## Quick Start ### Using Docker Compose (Recommended) -Build and run ChainForge in production mode: +Build and run ChainForge: ```bash docker-compose up -d ``` This will: -- Build the production image with the optimized multi-stage build +- Build the optimized multi-stage Docker image - Start the ChainForge server on port 8000 - Create a persistent volume for user data - Restart automatically if the container crashes @@ -27,7 +27,7 @@ Access ChainForge at: http://localhost:8000 ### Using Docker CLI -Build the production image: +Build the image: ```bash docker build -t chainforge:latest . @@ -44,77 +44,24 @@ docker run -d \ chainforge:latest ``` -## Development Setup - -### Using Docker Compose (Recommended) - -For development with hot-reloading: - -```bash -docker-compose -f docker-compose.dev.yml up -``` - -This will: -- Build the development image with all dev dependencies -- Start the React dev server on port 3000 -- Start the Python backend on port 8000 -- Mount your source code for hot-reloading -- Enable file watching with polling (works better in Docker) - -Access the development server at: http://localhost:3000 - -### Using Docker CLI - -Build the development image: - -```bash -docker build -f Dockerfile.dev -t chainforge:dev . -``` - -Run the container with volume mounts: - -```bash -docker run -it \ - -p 3000:3000 \ - -p 8000:8000 \ - -v $(pwd)/chainforge/react-server:/app \ - -v $(pwd)/chainforge:/chainforge/chainforge \ - -v /app/node_modules \ - -e CHOKIDAR_USEPOLLING=true \ - --name chainforge-dev \ - chainforge:dev -``` - ## Managing Containers ### View logs ```bash -# Production docker-compose logs -f - -# Development -docker-compose -f docker-compose.dev.yml logs -f ``` ### Stop containers ```bash -# Production docker-compose down - -# Development -docker-compose -f docker-compose.dev.yml down ``` ### Rebuild images ```bash -# Production docker-compose build --no-cache - -# Development -docker-compose -f docker-compose.dev.yml build --no-cache ``` ### Remove volumes (delete all data) @@ -143,21 +90,12 @@ HUGGINGFACE_API_KEY=your_key_here ## Docker Image Structure -### Production Image (Dockerfile) - Multi-stage build optimized for size: 1. **Stage 1**: Build React frontend with all dependencies 2. **Stage 2**: Build Python dependencies 3. **Stage 3**: Create minimal runtime image with only necessary files -### Development Image (Dockerfile.dev) - -Single-stage build with: -- All dev dependencies for hot-reloading -- Both Node.js and Python environments -- Volume mounts for live code updates - ## Troubleshooting ### ESLint Config Error @@ -168,41 +106,27 @@ If you see "ESLint couldn't find the config 'semistandard'": ### Port Already in Use -If ports 3000 or 8000 are already in use: -- Change the port mapping in `docker-compose.yml` or `docker-compose.dev.yml` -- Example: `"3001:3000"` to use port 3001 on your host - -### File Changes Not Reflected (Development) - -If hot-reloading isn't working: -- Ensure `CHOKIDAR_USEPOLLING=true` is set -- Check that volumes are properly mounted -- Try restarting the development container +If port 8000 is already in use: +- Change the port mapping in `docker-compose.yml` +- Example: `"8080:8000"` to use port 8080 on your host ### Permission Issues If you encounter permission errors: -- The production image runs as a non-root user (uid 1000) +- The image runs as a non-root user (uid 1000) - Ensure your volume permissions match this user - You can adjust the UID in the Dockerfile if needed ## Performance Tips -### Production - -- Use the multi-stage build (default Dockerfile) +- The multi-stage build creates an optimized image - The image is optimized to be under 1GB - Unnecessary files and caches are cleaned during build - -### Development - -- Keep `node_modules` in a named volume (don't mount from host) -- Use polling for file watching in Docker (`CHOKIDAR_USEPOLLING=true`) - Consider allocating more memory to Docker if builds are slow ## Pushing to Registry -To push the production image to a registry: +To push the image to a registry: ```bash # Tag the image From 350f9076470421516a00a9336db9dbac87a18cb6 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 12:08:41 -0500 Subject: [PATCH 15/32] GA autmatic build with CPU and GPU --- .github/workflows/docker-build.yml | 111 +++++++++++++++++++++++++ DOCKER.md | 126 +++++++++++++++++++++++++---- Dockerfile | 4 +- Dockerfile.dev | 41 ---------- Dockerfile.gpu | 73 +++++++++++++++++ docker-compose.dev.yml | 22 ----- docker-compose.gpu.yml | 41 ++++++++++ docker-compose.yml | 4 +- 8 files changed, 339 insertions(+), 83 deletions(-) create mode 100644 .github/workflows/docker-build.yml delete mode 100644 Dockerfile.dev create mode 100644 Dockerfile.gpu delete mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.gpu.yml diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 000000000..c941cd2a9 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,111 @@ +name: Build Docker Images + +on: + pull_request: + branches: + - main + - master + - ragforge + push: + branches: + - main + - master + - ragforge + tags: + - 'v*' + +env: + REGISTRY: docker.io + IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/chainforge + +jobs: + build-cpu: + name: Build CPU Image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=cpu + type=raw,value=latest + + - name: Build and push CPU image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 + + build-gpu: + name: Build GPU Image + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch,suffix=-gpu + type=ref,event=pr,suffix=-gpu + type=semver,pattern={{version}},suffix=-gpu + type=semver,pattern={{major}}.{{minor}},suffix=-gpu + type=raw,value=gpu + + - name: Build and push GPU image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.gpu + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + platforms: linux/amd64,linux/arm64 diff --git a/DOCKER.md b/DOCKER.md index 456b31988..f3ef252dd 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,67 +1,129 @@ # ChainForge Docker Setup -This document describes how to run ChainForge using Docker. +This document describes how to run ChainForge using Docker. ChainForge provides two Docker image variants: + +- **CPU (latest)**: Optimized for CPU-only environments with dependency constraints +- **GPU**: Supports GPU acceleration without dependency constraints ## Prerequisites - Docker (version 20.10 or later) - Docker Compose (version 2.0 or later) +- For GPU: NVIDIA Docker runtime (nvidia-docker2) ## Quick Start -### Using Docker Compose (Recommended) +### CPU Version (Default) -Build and run ChainForge: +Using Docker Compose (Recommended): ```bash docker-compose up -d ``` -This will: -- Build the optimized multi-stage Docker image -- Start the ChainForge server on port 8000 -- Create a persistent volume for user data -- Restart automatically if the container crashes +Or using Docker CLI: -Access ChainForge at: http://localhost:8000 +```bash +# Pull pre-built image +docker pull gauransh/chainforge:latest + +# Or build locally +docker build -t chainforge:cpu . + +# Run +docker run -d \ + -p 8000:8000 \ + -v chainforge-data:/home/chainforge/.local/share/chainforge \ + --name chainforge \ + --restart unless-stopped \ + gauransh/chainforge:latest +``` -### Using Docker CLI +### GPU Version -Build the image: +Using Docker Compose (Recommended): ```bash -docker build -t chainforge:latest . +docker-compose -f docker-compose.gpu.yml up -d ``` -Run the container: +Or using Docker CLI: ```bash +# Pull pre-built image +docker pull gauransh/chainforge:gpu + +# Or build locally +docker build -f Dockerfile.gpu -t chainforge:gpu . + +# Run with GPU support docker run -d \ -p 8000:8000 \ -v chainforge-data:/home/chainforge/.local/share/chainforge \ - --name chainforge \ + --name chainforge-gpu \ + --gpus all \ --restart unless-stopped \ - chainforge:latest + gauransh/chainforge:gpu ``` +Access ChainForge at: http://localhost:8000 + +## Image Variants + +### CPU (latest) +- Uses `constraints.txt` for dependency version pinning +- Optimized for CPU-only environments +- Smaller image size +- Compatible with all platforms (amd64, arm64) +- Tagged as: `latest`, `cpu` + +### GPU +- Does NOT use `constraints.txt` for maximum GPU compatibility +- Supports NVIDIA GPU acceleration +- Larger image size due to GPU-enabled dependencies +- Requires NVIDIA Docker runtime +- Tagged as: `gpu` + +**When to use GPU variant:** +- You have NVIDIA GPUs available +- You need GPU acceleration for ML/AI workloads +- You want the latest versions of GPU-enabled packages + +**When to use CPU variant:** +- Running on CPU-only machines +- Deploying to cloud platforms without GPU +- Want stable, version-pinned dependencies + ## Managing Containers ### View logs ```bash +# CPU version docker-compose logs -f + +# GPU version +docker-compose -f docker-compose.gpu.yml logs -f ``` ### Stop containers ```bash +# CPU version docker-compose down + +# GPU version +docker-compose -f docker-compose.gpu.yml down ``` ### Rebuild images ```bash +# CPU version docker-compose build --no-cache + +# GPU version +docker-compose -f docker-compose.gpu.yml build --no-cache ``` ### Remove volumes (delete all data) @@ -93,9 +155,41 @@ HUGGINGFACE_API_KEY=your_key_here Multi-stage build optimized for size: 1. **Stage 1**: Build React frontend with all dependencies -2. **Stage 2**: Build Python dependencies +2. **Stage 2**: Build Python dependencies (with/without constraints) 3. **Stage 3**: Create minimal runtime image with only necessary files +## Automated Builds (CI/CD) + +Docker images are automatically built and pushed to Docker Hub via GitHub Actions when: + +- A pull request is created (images are built but not pushed) +- Code is pushed to main/master branch +- A version tag is created (e.g., `v1.0.0`) + +### GitHub Actions Workflow + +The workflow builds both CPU and GPU variants: + +**CPU Image Tags:** +- `latest` - Always points to the latest CPU build +- `cpu` - Explicit CPU tag +- `main` / `master` - Branch-specific tags +- `v1.0.0`, `v1.0` - Version tags (on release) + +**GPU Image Tags:** +- `gpu` - Latest GPU build +- `main-gpu` / `master-gpu` - Branch-specific GPU tags +- `v1.0.0-gpu`, `v1.0-gpu` - Version GPU tags (on release) + +### Required GitHub Secrets + +To enable automated image publishing, configure these secrets in your GitHub repository: + +- `DOCKER_USERNAME` - Your Docker Hub username +- `DOCKER_PASSWORD` - Your Docker Hub password or access token + +Navigate to: `Settings > Secrets and variables > Actions > New repository secret` + ## Troubleshooting ### ESLint Config Error diff --git a/Dockerfile b/Dockerfile index fdd5b7e7d..6bdc243e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN npm ci --legacy-peer-deps COPY chainforge/react-server/ ./ RUN npm run build -# Stage 2 - Build Python dependencies +# Stage 2 - Build Python dependencies (CPU version with constraints) FROM python:3.12-slim AS python-builder # Install only the build dependencies we need @@ -26,7 +26,7 @@ WORKDIR /build # Install Python dependencies with no cache RUN pip install --no-cache-dir --upgrade pip setuptools wheel -# Copy requirements and install to a specific directory +# Copy requirements and install with constraints for CPU-only compatibility COPY chainforge/requirements.txt . COPY chainforge/constraints.txt . RUN pip install --no-cache-dir --prefix=/install -r requirements.txt -c constraints.txt diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 6d5f4d31f..000000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,41 +0,0 @@ -# Development Dockerfile with hot-reloading -FROM node:20-slim AS frontend - -WORKDIR /app - -# Install Python for the backend -RUN apt-get --allow-releaseinfo-change update && \ - apt-get install -y --no-install-recommends \ - python3 \ - python3-pip \ - python3-venv \ - git \ - build-essential \ - && rm -rf /var/lib/apt/lists/* - -# Copy package files first for better caching -COPY chainforge/react-server/package*.json ./ - -# Install Node dependencies (including dev dependencies for development) -RUN npm install --legacy-peer-deps - -# Copy Python requirements and install -WORKDIR /chainforge -COPY chainforge/requirements.txt ./chainforge/ -COPY setup.py README.md ./ -RUN pip3 install --no-cache-dir --break-system-packages -r chainforge/requirements.txt - -# Copy the rest of the application -COPY chainforge/ ./chainforge/ -COPY chainforge/react-server/ /app/ - -# Install chainforge in development mode -RUN pip3 install --no-cache-dir --break-system-packages -e . - -WORKDIR /app - -# Expose ports for React dev server and Python backend -EXPOSE 3000 8000 - -# Default command runs the React dev server -CMD ["npm", "start"] diff --git a/Dockerfile.gpu b/Dockerfile.gpu new file mode 100644 index 000000000..f110865fa --- /dev/null +++ b/Dockerfile.gpu @@ -0,0 +1,73 @@ +# Multi-stage build: Stage 1 - Build React frontend +FROM node:20-slim AS frontend-builder + +WORKDIR /app + +# Copy package files and install dependencies (including dev for build) +COPY chainforge/react-server/package*.json ./ +RUN npm ci --legacy-peer-deps + +# Copy source files and build +COPY chainforge/react-server/ ./ +RUN npm run build + +# Stage 2 - Build Python dependencies (GPU version - no constraints) +FROM python:3.12-slim AS python-builder + +# Install only the build dependencies we need +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + git \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Install Python dependencies with no cache +RUN pip install --no-cache-dir --upgrade pip setuptools wheel + +# Copy requirements and install without constraints for GPU support +COPY chainforge/requirements.txt . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt + +# Copy project files and build the package +COPY setup.py README.md ./ +COPY chainforge/ ./chainforge/ +RUN pip install --no-cache-dir --prefix=/install . + +# Stage 3 - Final minimal runtime image +FROM python:3.12-slim + +# Install only runtime dependencies (no build tools) +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends \ + git \ + libgomp1 \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean + +WORKDIR /chainforge + +# Copy Python packages from builder +COPY --from=python-builder /install /usr/local + +# Copy the built React app from the frontend-builder stage to the installed package location +COPY --from=frontend-builder /app/build /usr/local/lib/python3.12/site-packages/chainforge/react-server/build + +# Clean up any unnecessary files to reduce image size +RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ + find /usr/local -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \ + find /usr/local -name "*.pyc" -delete && \ + find /usr/local -name "*.pyo" -delete && \ + find /usr/local -name "*.md" -delete 2>/dev/null || true + +# Run as non-root user for security +RUN useradd -m -u 1000 chainforge && \ + mkdir -p /home/chainforge/.local/share/chainforge && \ + chown -R chainforge:chainforge /chainforge /home/chainforge + +USER chainforge + +EXPOSE 8000 + +ENTRYPOINT [ "chainforge", "serve", "--host", "0.0.0.0" ] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml deleted file mode 100644 index 0765b16fd..000000000 --- a/docker-compose.dev.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3.8' - -services: - chainforge-dev: - build: - context: . - dockerfile: Dockerfile.dev - ports: - - "3000:3000" # React dev server - - "8000:8000" # Python backend - environment: - - NODE_ENV=development - - CHOKIDAR_USEPOLLING=true # Enable polling for file watching in Docker - volumes: - # Mount source code for hot-reloading - - ./chainforge/react-server:/app - - ./chainforge:/chainforge/chainforge - # Exclude node_modules from mounting (use container's version) - - /app/node_modules - stdin_open: true - tty: true - command: npm start diff --git a/docker-compose.gpu.yml b/docker-compose.gpu.yml new file mode 100644 index 000000000..a61975fd3 --- /dev/null +++ b/docker-compose.gpu.yml @@ -0,0 +1,41 @@ +services: + chainforge: + build: + context: . + dockerfile: Dockerfile.gpu + image: gauransh/chainforge:gpu + container_name: chainforge-gpu + ports: + - "8000:8000" + volumes: + # Mount data directory for persistent storage + - chainforge-data:/home/chainforge/.local/share/chainforge + environment: + - NODE_ENV=production + - FLASK_ENV=production + # Add API keys as environment variables if needed + # - OPENAI_API_KEY=${OPENAI_API_KEY} + # - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} + # - COHERE_API_KEY=${COHERE_API_KEY} + # - GOOGLE_API_KEY=${GOOGLE_API_KEY} + # - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} + # - HUGGINGFACE_API_KEY=${HUGGINGFACE_API_KEY} + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8000 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + +# Named volume for persistent data +volumes: + chainforge-data: + driver: local diff --git a/docker-compose.yml b/docker-compose.yml index 9ac30ccbb..cc45ee811 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,8 +3,8 @@ services: build: context: . dockerfile: Dockerfile - image: gauransh/chainforge:rag - container_name: chainforge + image: gauransh/chainforge:cpu + container_name: chainforge-cpu ports: - "8000:8000" volumes: From 915b71d5e974b729b2cb5bead1c3a60bedde45a7 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 17 Nov 2025 12:22:17 -0500 Subject: [PATCH 16/32] fixing GA build error --- .github/workflows/docker-build.yml | 23 +++++++++++++++++++++++ DOCKER.md | 13 +++++++++++++ 2 files changed, 36 insertions(+) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index c941cd2a9..11cf9b0a0 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -6,14 +6,33 @@ on: - main - master - ragforge + paths: + - 'Dockerfile' + - 'Dockerfile.gpu' + - 'chainforge/**' + - 'setup.py' + - 'requirements.txt' + - '.github/workflows/docker-build.yml' push: branches: - main - master - ragforge + paths: + - 'Dockerfile' + - 'Dockerfile.gpu' + - 'chainforge/**' + - 'setup.py' + - 'requirements.txt' + - '.github/workflows/docker-build.yml' tags: - 'v*' +# Concurrency: cancel in-progress runs when new one starts +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: REGISTRY: docker.io IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/chainforge @@ -22,6 +41,8 @@ jobs: build-cpu: name: Build CPU Image runs-on: ubuntu-latest + # Skip if commit message contains [skip ci] or [ci skip] + if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} permissions: contents: read packages: write @@ -68,6 +89,8 @@ jobs: build-gpu: name: Build GPU Image runs-on: ubuntu-latest + # Skip if commit message contains [skip ci] or [ci skip] + if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} permissions: contents: read packages: write diff --git a/DOCKER.md b/DOCKER.md index f3ef252dd..262cb7e3d 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -190,6 +190,19 @@ To enable automated image publishing, configure these secrets in your GitHub rep Navigate to: `Settings > Secrets and variables > Actions > New repository secret` +### Workflow Optimizations + +The workflow includes several optimizations to prevent unnecessary builds: + +1. **Path Filters**: Only triggers when Docker-related files change (Dockerfiles, chainforge/, setup.py, etc.) +2. **Concurrency Control**: Automatically cancels in-progress builds when a new one starts +3. **Skip CI**: Add `[skip ci]` or `[ci skip]` to your commit message to skip the build + +Example: +```bash +git commit -m "Update README [skip ci]" +``` + ## Troubleshooting ### ESLint Config Error From 5aa3ccc33b97cab74fd047de22d4a117ccd7cb63 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 20 Nov 2025 11:59:47 -0500 Subject: [PATCH 17/32] optimising build and fixing bugs --- .github/workflows/docker-build.yml | 18 +++++++--- Dockerfile | 24 ++++++++++---- Dockerfile.gpu | 53 +++++++++++++++++++++--------- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 11cf9b0a0..f0f15b10b 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -82,9 +82,14 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: | + type=gha,scope=cpu-build + type=registry,ref=${{ env.IMAGE_NAME }}:cpu + cache-to: type=gha,mode=max,scope=cpu-build platforms: linux/amd64,linux/arm64 + build-args: | + BUILDKIT_INLINE_CACHE=1 + BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 build-gpu: name: Build GPU Image @@ -129,6 +134,11 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: | + type=gha,scope=gpu-build + type=registry,ref=${{ env.IMAGE_NAME }}:gpu + cache-to: type=gha,mode=max,scope=gpu-build platforms: linux/amd64,linux/arm64 + build-args: | + BUILDKIT_INLINE_CACHE=1 + BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 diff --git a/Dockerfile b/Dockerfile index 6bdc243e1..2a69f30c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps +RUN npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ @@ -23,15 +23,25 @@ RUN apt-get --allow-releaseinfo-change update && \ WORKDIR /build -# Install Python dependencies with no cache +# Upgrade pip tools first (this layer is highly cacheable) RUN pip install --no-cache-dir --upgrade pip setuptools wheel -# Copy requirements and install with constraints for CPU-only compatibility -COPY chainforge/requirements.txt . -COPY chainforge/constraints.txt . -RUN pip install --no-cache-dir --prefix=/install -r requirements.txt -c constraints.txt +# Copy requirements first for better layer caching +COPY chainforge/requirements.txt chainforge/constraints.txt ./ -# Copy project files and build the package +# Install PyTorch CPU-only FIRST as it's the largest dependency +# This separates the longest-running install into its own layer +RUN pip install --no-cache-dir --prefix=/install \ + --extra-index-url https://download.pytorch.org/whl/cpu \ + torch torchvision torchaudio + +# Install remaining requirements with constraints +# Using --find-links to help pip resolve faster +RUN pip install --no-cache-dir --prefix=/install \ + -r requirements.txt \ + -c constraints.txt + +# Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ RUN pip install --no-cache-dir --prefix=/install . diff --git a/Dockerfile.gpu b/Dockerfile.gpu index f110865fa..120fa7c52 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -5,47 +5,68 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps +RUN npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ RUN npm run build -# Stage 2 - Build Python dependencies (GPU version - no constraints) -FROM python:3.12-slim AS python-builder +# Stage 2 - Build Python dependencies (GPU version with CUDA support) +# Using NVIDIA's official CUDA base image with Python 3.12 +FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 AS python-builder -# Install only the build dependencies we need -RUN apt-get --allow-releaseinfo-change update && \ +# Install Python 3.12 and build dependencies +RUN apt-get update && \ apt-get install -y --no-install-recommends \ + python3.12 \ + python3.12-dev \ + python3-pip \ build-essential \ git \ && rm -rf /var/lib/apt/lists/* +# Set Python 3.12 as default +RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \ + update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 + WORKDIR /build -# Install Python dependencies with no cache -RUN pip install --no-cache-dir --upgrade pip setuptools wheel +# Upgrade pip tools first (this layer is highly cacheable) +RUN pip3 install --no-cache-dir --upgrade pip setuptools wheel + +# Copy requirements first for better layer caching +COPY chainforge/requirements.txt ./ -# Copy requirements and install without constraints for GPU support -COPY chainforge/requirements.txt . -RUN pip install --no-cache-dir --prefix=/install -r requirements.txt +# Install PyTorch with CUDA support FIRST as it's the largest dependency +# Using CUDA 12.1 compatible PyTorch +RUN pip3 install --no-cache-dir --prefix=/install \ + torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 -# Copy project files and build the package +# Install remaining requirements (without constraints for full GPU support) +RUN pip3 install --no-cache-dir --prefix=/install -r requirements.txt + +# Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip install --no-cache-dir --prefix=/install . +RUN pip3 install --no-cache-dir --prefix=/install . -# Stage 3 - Final minimal runtime image -FROM python:3.12-slim +# Stage 3 - Final NVIDIA CUDA runtime image +FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 -# Install only runtime dependencies (no build tools) -RUN apt-get --allow-releaseinfo-change update && \ +# Install Python 3.12 and runtime dependencies (no build tools) +RUN apt-get update && \ apt-get install -y --no-install-recommends \ + python3.12 \ + python3-pip \ git \ libgomp1 \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean +# Set Python 3.12 as default +RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \ + update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 + WORKDIR /chainforge # Copy Python packages from builder From 894ce35759eb7636492df156f84a7bced7f6df52 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 20 Nov 2025 12:03:24 -0500 Subject: [PATCH 18/32] optimising build and fixing bugs --- .github/workflows/docker-build.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index f0f15b10b..38359da46 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -6,25 +6,11 @@ on: - main - master - ragforge - paths: - - 'Dockerfile' - - 'Dockerfile.gpu' - - 'chainforge/**' - - 'setup.py' - - 'requirements.txt' - - '.github/workflows/docker-build.yml' push: branches: - main - master - ragforge - paths: - - 'Dockerfile' - - 'Dockerfile.gpu' - - 'chainforge/**' - - 'setup.py' - - 'requirements.txt' - - '.github/workflows/docker-build.yml' tags: - 'v*' From e08ffede75eb42b37b34d5e295f92b6f40b9c544 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 20 Nov 2025 12:13:44 -0500 Subject: [PATCH 19/32] optimising build and fixing bugs for GPU --- Dockerfile.gpu | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Dockerfile.gpu b/Dockerfile.gpu index 120fa7c52..a239001b0 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -15,11 +15,16 @@ RUN npm run build # Using NVIDIA's official CUDA base image with Python 3.12 FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 AS python-builder -# Install Python 3.12 and build dependencies +# Install Python 3.12 using deadsnakes PPA for multi-arch support RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + software-properties-common \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update && \ apt-get install -y --no-install-recommends \ python3.12 \ python3.12-dev \ + python3.12-distutils \ python3-pip \ build-essential \ git \ @@ -53,13 +58,20 @@ RUN pip3 install --no-cache-dir --prefix=/install . # Stage 3 - Final NVIDIA CUDA runtime image FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 -# Install Python 3.12 and runtime dependencies (no build tools) +# Install Python 3.12 using deadsnakes PPA and runtime dependencies (no build tools) RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + software-properties-common \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update && \ apt-get install -y --no-install-recommends \ python3.12 \ + python3.12-distutils \ python3-pip \ git \ libgomp1 \ + && apt-get remove -y software-properties-common \ + && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean From fdd3ef4024129517ac9fb37e9d587311c8befa65 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 20 Nov 2025 14:39:32 -0500 Subject: [PATCH 20/32] removed caching and fixed GPU build --- .github/workflows/docker-build.yml | 36 +++++++++++++++--------------- Dockerfile.gpu | 27 ++-------------------- 2 files changed, 20 insertions(+), 43 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 38359da46..4a41d4d66 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -14,10 +14,10 @@ on: tags: - 'v*' -# Concurrency: cancel in-progress runs when new one starts -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +# # Concurrency: cancel in-progress runs when new one starts +# concurrency: +# group: ${{ github.workflow }}-${{ github.ref }} +# cancel-in-progress: true env: REGISTRY: docker.io @@ -68,14 +68,14 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: | - type=gha,scope=cpu-build - type=registry,ref=${{ env.IMAGE_NAME }}:cpu - cache-to: type=gha,mode=max,scope=cpu-build + # cache-from: | + # type=gha,scope=cpu-build + # type=registry,ref=${{ env.IMAGE_NAME }}:cpu + # cache-to: type=gha,mode=max,scope=cpu-build platforms: linux/amd64,linux/arm64 - build-args: | - BUILDKIT_INLINE_CACHE=1 - BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 + # build-args: | + # BUILDKIT_INLINE_CACHE=1 + # BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 build-gpu: name: Build GPU Image @@ -120,11 +120,11 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: | - type=gha,scope=gpu-build - type=registry,ref=${{ env.IMAGE_NAME }}:gpu - cache-to: type=gha,mode=max,scope=gpu-build + # cache-from: | + # type=gha,scope=gpu-build + # type=registry,ref=${{ env.IMAGE_NAME }}:gpu + # cache-to: type=gha,mode=max,scope=gpu-build platforms: linux/amd64,linux/arm64 - build-args: | - BUILDKIT_INLINE_CACHE=1 - BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 + # build-args: | + # BUILDKIT_INLINE_CACHE=1 + # BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 diff --git a/Dockerfile.gpu b/Dockerfile.gpu index a239001b0..36c9dae09 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -17,23 +17,12 @@ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 AS python-builder # Install Python 3.12 using deadsnakes PPA for multi-arch support RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - software-properties-common \ - && add-apt-repository ppa:deadsnakes/ppa \ && apt-get update && \ apt-get install -y --no-install-recommends \ - python3.12 \ - python3.12-dev \ - python3.12-distutils \ - python3-pip \ build-essential \ git \ && rm -rf /var/lib/apt/lists/* -# Set Python 3.12 as default -RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \ - update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 - WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) @@ -58,34 +47,22 @@ RUN pip3 install --no-cache-dir --prefix=/install . # Stage 3 - Final NVIDIA CUDA runtime image FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 -# Install Python 3.12 using deadsnakes PPA and runtime dependencies (no build tools) +# Install Python 3.11 using deadsnakes PPA and runtime dependencies (no build tools) RUN apt-get update && \ apt-get install -y --no-install-recommends \ - software-properties-common \ - && add-apt-repository ppa:deadsnakes/ppa \ - && apt-get update && \ - apt-get install -y --no-install-recommends \ - python3.12 \ - python3.12-distutils \ - python3-pip \ git \ libgomp1 \ - && apt-get remove -y software-properties-common \ && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean -# Set Python 3.12 as default -RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \ - update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 - WORKDIR /chainforge # Copy Python packages from builder COPY --from=python-builder /install /usr/local # Copy the built React app from the frontend-builder stage to the installed package location -COPY --from=frontend-builder /app/build /usr/local/lib/python3.12/site-packages/chainforge/react-server/build +COPY --from=frontend-builder /app/build /usr/local/lib/python3.11/site-packages/chainforge/react_server/build # Clean up any unnecessary files to reduce image size RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ From 45385b5ce80aa80503846398722e1eb7017cfe80 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 20 Nov 2025 14:41:31 -0500 Subject: [PATCH 21/32] removed caching and fixed GPU build --- Dockerfile.gpu | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/Dockerfile.gpu b/Dockerfile.gpu index 36c9dae09..e8e70d1ad 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -12,12 +12,10 @@ COPY chainforge/react-server/ ./ RUN npm run build # Stage 2 - Build Python dependencies (GPU version with CUDA support) -# Using NVIDIA's official CUDA base image with Python 3.12 -FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 AS python-builder +FROM python:3.12-slim AS python-builder -# Install Python 3.12 using deadsnakes PPA for multi-arch support -RUN apt-get update && \ - && apt-get update && \ +# Install only the build dependencies we need +RUN apt-get --allow-releaseinfo-change update && \ apt-get install -y --no-install-recommends \ build-essential \ git \ @@ -26,33 +24,36 @@ RUN apt-get update && \ WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) -RUN pip3 install --no-cache-dir --upgrade pip setuptools wheel +RUN pip install --no-cache-dir --upgrade pip setuptools wheel # Copy requirements first for better layer caching -COPY chainforge/requirements.txt ./ +COPY chainforge/requirements.txt chainforge/constraints.txt ./ -# Install PyTorch with CUDA support FIRST as it's the largest dependency -# Using CUDA 12.1 compatible PyTorch -RUN pip3 install --no-cache-dir --prefix=/install \ - torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 +# Install PyTorch CPU-only FIRST as it's the largest dependency +# This separates the longest-running install into its own layer +RUN pip install --no-cache-dir --prefix=/install \ + --extra-index-url https://download.pytorch.org/whl/cu121 \ + torch torchvision torchaudio -# Install remaining requirements (without constraints for full GPU support) -RUN pip3 install --no-cache-dir --prefix=/install -r requirements.txt +# Install remaining requirements with constraints +# Using --find-links to help pip resolve faster +RUN pip install --no-cache-dir --prefix=/install \ + -r requirements.txt \ + -c constraints.txt # Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip3 install --no-cache-dir --prefix=/install . +RUN pip install --no-cache-dir --prefix=/install . -# Stage 3 - Final NVIDIA CUDA runtime image -FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04 +# Stage 3 - Final minimal runtime image +FROM python:3.12-slim -# Install Python 3.11 using deadsnakes PPA and runtime dependencies (no build tools) -RUN apt-get update && \ +# Install only runtime dependencies (no build tools) +RUN apt-get --allow-releaseinfo-change update && \ apt-get install -y --no-install-recommends \ git \ libgomp1 \ - && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean @@ -62,7 +63,7 @@ WORKDIR /chainforge COPY --from=python-builder /install /usr/local # Copy the built React app from the frontend-builder stage to the installed package location -COPY --from=frontend-builder /app/build /usr/local/lib/python3.11/site-packages/chainforge/react_server/build +COPY --from=frontend-builder /app/build /usr/local/lib/python3.12/site-packages/chainforge/react-server/build # Clean up any unnecessary files to reduce image size RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ @@ -81,3 +82,4 @@ USER chainforge EXPOSE 8000 ENTRYPOINT [ "chainforge", "serve", "--host", "0.0.0.0" ] + From 0e0a9155627a35150533cae6d62a87946bec1968 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Tue, 25 Nov 2025 01:54:55 -0500 Subject: [PATCH 22/32] more optimisations --- .github/workflows/docker-build.yml | 22 ++++++++-------------- .github/workflows/python-package.yml | 3 ++- Dockerfile | 15 ++++++++++----- Dockerfile.gpu | 15 ++++++++++----- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 4a41d4d66..166ab3515 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -68,14 +68,11 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - # cache-from: | - # type=gha,scope=cpu-build - # type=registry,ref=${{ env.IMAGE_NAME }}:cpu - # cache-to: type=gha,mode=max,scope=cpu-build + cache-from: type=gha,scope=cpu-${{ github.ref_name }} + cache-to: type=gha,mode=max,scope=cpu-${{ github.ref_name }} platforms: linux/amd64,linux/arm64 - # build-args: | - # BUILDKIT_INLINE_CACHE=1 - # BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 + build-args: | + BUILDKIT_INLINE_CACHE=1 build-gpu: name: Build GPU Image @@ -120,11 +117,8 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - # cache-from: | - # type=gha,scope=gpu-build - # type=registry,ref=${{ env.IMAGE_NAME }}:gpu - # cache-to: type=gha,mode=max,scope=gpu-build + cache-from: type=gha,scope=gpu-${{ github.ref_name }} + cache-to: type=gha,mode=max,scope=gpu-${{ github.ref_name }} platforms: linux/amd64,linux/arm64 - # build-args: | - # BUILDKIT_INLINE_CACHE=1 - # BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 + build-args: | + BUILDKIT_INLINE_CACHE=1 diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 26446c23f..da32a8ccb 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -29,9 +29,10 @@ jobs: uses: actions/cache@v4 with: path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('chainforge/requirements.txt') }} + key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('chainforge/requirements.txt', 'chainforge/constraints.txt', 'setup.py') }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.python-version }}- + ${{ runner.os }}-pip- - name: Upgrade pip run: python -m pip install --upgrade pip diff --git a/Dockerfile b/Dockerfile index 2a69f30c7..6c49aa698 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,8 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps --prefer-offline +RUN --mount=type=cache,target=/root/.npm \ + npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ @@ -24,27 +25,31 @@ RUN apt-get --allow-releaseinfo-change update && \ WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) -RUN pip install --no-cache-dir --upgrade pip setuptools wheel +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --upgrade pip setuptools wheel # Copy requirements first for better layer caching COPY chainforge/requirements.txt chainforge/constraints.txt ./ # Install PyTorch CPU-only FIRST as it's the largest dependency # This separates the longest-running install into its own layer -RUN pip install --no-cache-dir --prefix=/install \ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install \ --extra-index-url https://download.pytorch.org/whl/cpu \ torch torchvision torchaudio # Install remaining requirements with constraints # Using --find-links to help pip resolve faster -RUN pip install --no-cache-dir --prefix=/install \ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install \ -r requirements.txt \ -c constraints.txt # Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip install --no-cache-dir --prefix=/install . +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install . # Stage 3 - Final minimal runtime image FROM python:3.12-slim diff --git a/Dockerfile.gpu b/Dockerfile.gpu index e8e70d1ad..39a97a969 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -5,7 +5,8 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps --prefer-offline +RUN --mount=type=cache,target=/root/.npm \ + npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ @@ -24,27 +25,31 @@ RUN apt-get --allow-releaseinfo-change update && \ WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) -RUN pip install --no-cache-dir --upgrade pip setuptools wheel +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --upgrade pip setuptools wheel # Copy requirements first for better layer caching COPY chainforge/requirements.txt chainforge/constraints.txt ./ # Install PyTorch CPU-only FIRST as it's the largest dependency # This separates the longest-running install into its own layer -RUN pip install --no-cache-dir --prefix=/install \ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install \ --extra-index-url https://download.pytorch.org/whl/cu121 \ torch torchvision torchaudio # Install remaining requirements with constraints # Using --find-links to help pip resolve faster -RUN pip install --no-cache-dir --prefix=/install \ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install \ -r requirements.txt \ -c constraints.txt # Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip install --no-cache-dir --prefix=/install . +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefix=/install . # Stage 3 - Final minimal runtime image FROM python:3.12-slim From 0c30fda17a440eff68560f385d0108da34dc0a3b Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 27 Nov 2025 17:34:42 -0500 Subject: [PATCH 23/32] segregating builds for faster proceccing and removing cacheing --- .github/workflows/docker-build.yml | 199 ++++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 29 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 166ab3515..6d5e0afa5 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -24,8 +24,8 @@ env: IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/chainforge jobs: - build-cpu: - name: Build CPU Image + build-cpu-amd64: + name: Build CPU AMD64 Image runs-on: ubuntu-latest # Skip if commit message contains [skip ci] or [ci skip] if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} @@ -53,14 +53,59 @@ jobs: with: images: ${{ env.IMAGE_NAME }} tags: | - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=raw,value=cpu - type=raw,value=latest - - - name: Build and push CPU image + type=ref,event=branch,suffix=-amd64 + type=ref,event=pr,suffix=-amd64 + type=semver,pattern={{version}},suffix=-amd64 + type=semver,pattern={{major}}.{{minor}},suffix=-amd64 + type=raw,value=cpu-amd64 + + - name: Build and push CPU AMD64 image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 + provenance: false + + build-cpu-arm64: + name: Build CPU ARM64 Image + runs-on: ubuntu-latest + # Skip if commit message contains [skip ci] or [ci skip] + if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch,suffix=-arm64 + type=ref,event=pr,suffix=-arm64 + type=semver,pattern={{version}},suffix=-arm64 + type=semver,pattern={{major}}.{{minor}},suffix=-arm64 + type=raw,value=cpu-arm64 + + - name: Build and push CPU ARM64 image uses: docker/build-push-action@v5 with: context: . @@ -68,14 +113,57 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=cpu-${{ github.ref_name }} - cache-to: type=gha,mode=max,scope=cpu-${{ github.ref_name }} - platforms: linux/amd64,linux/arm64 - build-args: | - BUILDKIT_INLINE_CACHE=1 - - build-gpu: - name: Build GPU Image + platforms: linux/arm64 + provenance: false + + build-gpu-amd64: + name: Build GPU AMD64 Image + runs-on: ubuntu-latest + # Skip if commit message contains [skip ci] or [ci skip] + if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch,suffix=-gpu-amd64 + type=ref,event=pr,suffix=-gpu-amd64 + type=semver,pattern={{version}},suffix=-gpu-amd64 + type=semver,pattern={{major}}.{{minor}},suffix=-gpu-amd64 + type=raw,value=gpu-amd64 + + - name: Build and push GPU AMD64 image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.gpu + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 + provenance: false + + build-gpu-arm64: + name: Build GPU ARM64 Image runs-on: ubuntu-latest # Skip if commit message contains [skip ci] or [ci skip] if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} @@ -103,13 +191,13 @@ jobs: with: images: ${{ env.IMAGE_NAME }} tags: | - type=ref,event=branch,suffix=-gpu - type=ref,event=pr,suffix=-gpu - type=semver,pattern={{version}},suffix=-gpu - type=semver,pattern={{major}}.{{minor}},suffix=-gpu - type=raw,value=gpu + type=ref,event=branch,suffix=-gpu-arm64 + type=ref,event=pr,suffix=-gpu-arm64 + type=semver,pattern={{version}},suffix=-gpu-arm64 + type=semver,pattern={{major}}.{{minor}},suffix=-gpu-arm64 + type=raw,value=gpu-arm64 - - name: Build and push GPU image + - name: Build and push GPU ARM64 image uses: docker/build-push-action@v5 with: context: . @@ -117,8 +205,61 @@ jobs: push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=gpu-${{ github.ref_name }} - cache-to: type=gha,mode=max,scope=gpu-${{ github.ref_name }} - platforms: linux/amd64,linux/arm64 - build-args: | - BUILDKIT_INLINE_CACHE=1 + platforms: linux/arm64 + provenance: false + + create-manifest: + name: Create Multi-Arch Manifests + runs-on: ubuntu-latest + needs: [build-cpu-amd64, build-cpu-arm64, build-gpu-amd64, build-gpu-arm64] + if: ${{ github.event_name != 'pull_request' && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} + permissions: + contents: read + packages: write + + steps: + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Create and push CPU manifest + run: | + # Determine tags based on ref + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION=${GITHUB_REF#refs/tags/v} + MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2) + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION} \ + -t ${{ env.IMAGE_NAME }}:${MAJOR_MINOR} \ + -t ${{ env.IMAGE_NAME }}:cpu \ + -t ${{ env.IMAGE_NAME }}:latest \ + ${{ env.IMAGE_NAME }}:cpu-amd64 \ + ${{ env.IMAGE_NAME }}:cpu-arm64 + else + BRANCH=${GITHUB_REF#refs/heads/} + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${BRANCH} \ + -t ${{ env.IMAGE_NAME }}:cpu \ + -t ${{ env.IMAGE_NAME }}:latest \ + ${{ env.IMAGE_NAME }}:cpu-amd64 \ + ${{ env.IMAGE_NAME }}:cpu-arm64 + fi + + - name: Create and push GPU manifest + run: | + # Determine tags based on ref + if [[ "${{ github.ref }}" == refs/tags/* ]]; then + VERSION=${GITHUB_REF#refs/tags/v} + MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2) + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION}-gpu \ + -t ${{ env.IMAGE_NAME }}:${MAJOR_MINOR}-gpu \ + -t ${{ env.IMAGE_NAME }}:gpu \ + ${{ env.IMAGE_NAME }}:gpu-amd64 \ + ${{ env.IMAGE_NAME }}:gpu-arm64 + else + BRANCH=${GITHUB_REF#refs/heads/} + docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${BRANCH}-gpu \ + -t ${{ env.IMAGE_NAME }}:gpu \ + ${{ env.IMAGE_NAME }}:gpu-amd64 \ + ${{ env.IMAGE_NAME }}:gpu-arm64 + fi From 230ead33dd628ef0e74306141be280119450b49f Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 27 Nov 2025 17:41:18 -0500 Subject: [PATCH 24/32] removed gpu-arm64 build and added further conditionals for imporoving build times --- .github/workflows/docker-build.yml | 79 ++++++++++-------------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 6d5e0afa5..262941b6b 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -69,6 +69,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 provenance: false + sbom: false build-cpu-arm64: name: Build CPU ARM64 Image @@ -115,6 +116,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/arm64 provenance: false + sbom: false build-gpu-amd64: name: Build GPU AMD64 Image @@ -161,57 +163,13 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 provenance: false + sbom: false - build-gpu-arm64: - name: Build GPU ARM64 Image - runs-on: ubuntu-latest - # Skip if commit message contains [skip ci] or [ci skip] - if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Docker Hub - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch,suffix=-gpu-arm64 - type=ref,event=pr,suffix=-gpu-arm64 - type=semver,pattern={{version}},suffix=-gpu-arm64 - type=semver,pattern={{major}}.{{minor}},suffix=-gpu-arm64 - type=raw,value=gpu-arm64 - - name: Build and push GPU ARM64 image - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile.gpu - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/arm64 - provenance: false - - create-manifest: - name: Create Multi-Arch Manifests + create-cpu-manifest: + name: Create CPU Multi-Arch Manifest runs-on: ubuntu-latest - needs: [build-cpu-amd64, build-cpu-arm64, build-gpu-amd64, build-gpu-arm64] + needs: [build-cpu-amd64, build-cpu-arm64] if: ${{ github.event_name != 'pull_request' && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} permissions: contents: read @@ -245,21 +203,36 @@ jobs: ${{ env.IMAGE_NAME }}:cpu-arm64 fi - - name: Create and push GPU manifest + create-gpu-manifest: + name: Create GPU Manifest + runs-on: ubuntu-latest + needs: [build-gpu-amd64] + if: ${{ github.event_name != 'pull_request' && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }} + permissions: + contents: read + packages: write + + steps: + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Create and push GPU manifest (AMD64 only) run: | # Determine tags based on ref + # GPU images are AMD64 only due to storage constraints and limited ARM64 CUDA support if [[ "${{ github.ref }}" == refs/tags/* ]]; then VERSION=${GITHUB_REF#refs/tags/v} MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2) docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION}-gpu \ -t ${{ env.IMAGE_NAME }}:${MAJOR_MINOR}-gpu \ -t ${{ env.IMAGE_NAME }}:gpu \ - ${{ env.IMAGE_NAME }}:gpu-amd64 \ - ${{ env.IMAGE_NAME }}:gpu-arm64 + ${{ env.IMAGE_NAME }}:gpu-amd64 else BRANCH=${GITHUB_REF#refs/heads/} docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${BRANCH}-gpu \ -t ${{ env.IMAGE_NAME }}:gpu \ - ${{ env.IMAGE_NAME }}:gpu-amd64 \ - ${{ env.IMAGE_NAME }}:gpu-arm64 + ${{ env.IMAGE_NAME }}:gpu-amd64 fi From 250a89ddb4ac6744987e1b06aae530f85dbd1274 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Thu, 27 Nov 2025 17:46:50 -0500 Subject: [PATCH 25/32] removed pip and npm cacheing for smaller docker image --- Dockerfile | 15 +++++---------- Dockerfile.gpu | 15 +++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6c49aa698..2a69f30c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,7 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN --mount=type=cache,target=/root/.npm \ - npm ci --legacy-peer-deps --prefer-offline +RUN npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ @@ -25,31 +24,27 @@ RUN apt-get --allow-releaseinfo-change update && \ WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --upgrade pip setuptools wheel +RUN pip install --no-cache-dir --upgrade pip setuptools wheel # Copy requirements first for better layer caching COPY chainforge/requirements.txt chainforge/constraints.txt ./ # Install PyTorch CPU-only FIRST as it's the largest dependency # This separates the longest-running install into its own layer -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install \ +RUN pip install --no-cache-dir --prefix=/install \ --extra-index-url https://download.pytorch.org/whl/cpu \ torch torchvision torchaudio # Install remaining requirements with constraints # Using --find-links to help pip resolve faster -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install \ +RUN pip install --no-cache-dir --prefix=/install \ -r requirements.txt \ -c constraints.txt # Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install . +RUN pip install --no-cache-dir --prefix=/install . # Stage 3 - Final minimal runtime image FROM python:3.12-slim diff --git a/Dockerfile.gpu b/Dockerfile.gpu index 39a97a969..e8e70d1ad 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -5,8 +5,7 @@ WORKDIR /app # Copy package files and install dependencies (including dev for build) COPY chainforge/react-server/package*.json ./ -RUN --mount=type=cache,target=/root/.npm \ - npm ci --legacy-peer-deps --prefer-offline +RUN npm ci --legacy-peer-deps --prefer-offline # Copy source files and build COPY chainforge/react-server/ ./ @@ -25,31 +24,27 @@ RUN apt-get --allow-releaseinfo-change update && \ WORKDIR /build # Upgrade pip tools first (this layer is highly cacheable) -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --upgrade pip setuptools wheel +RUN pip install --no-cache-dir --upgrade pip setuptools wheel # Copy requirements first for better layer caching COPY chainforge/requirements.txt chainforge/constraints.txt ./ # Install PyTorch CPU-only FIRST as it's the largest dependency # This separates the longest-running install into its own layer -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install \ +RUN pip install --no-cache-dir --prefix=/install \ --extra-index-url https://download.pytorch.org/whl/cu121 \ torch torchvision torchaudio # Install remaining requirements with constraints # Using --find-links to help pip resolve faster -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install \ +RUN pip install --no-cache-dir --prefix=/install \ -r requirements.txt \ -c constraints.txt # Copy project files and build the package (smallest layer last) COPY setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --prefix=/install . +RUN pip install --no-cache-dir --prefix=/install . # Stage 3 - Final minimal runtime image FROM python:3.12-slim From 5bd32823379699f5ddb5e5524423a569a20d59f3 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Fri, 28 Nov 2025 17:21:02 -0500 Subject: [PATCH 26/32] making more space in GA runner for the NVIDIA builds --- .github/workflows/docker-build.yml | 33 +++++++++++ Dockerfile.gpu | 88 +++++++++++++----------------- 2 files changed, 70 insertions(+), 51 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 262941b6b..97b55128c 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -128,6 +128,39 @@ jobs: packages: write steps: + - name: Free up disk space + run: | + echo "Before cleanup:" + df -h + + # Remove unnecessary software to free up space + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + sudo rm -rf /opt/hostedtoolcache/CodeQL + sudo rm -rf /usr/local/share/boost + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + + # Remove large packages + sudo apt-get remove -y '^aspnetcore-.*' || true + sudo apt-get remove -y '^dotnet-.*' --fix-missing || true + sudo apt-get remove -y '^llvm-.*' --fix-missing || true + sudo apt-get remove -y 'php.*' --fix-missing || true + sudo apt-get remove -y '^mongodb-.*' --fix-missing || true + sudo apt-get remove -y '^mysql-.*' --fix-missing || true + sudo apt-get remove -y azure-cli google-chrome-stable firefox powershell mono-devel libgl1-mesa-dri --fix-missing || true + sudo apt-get remove -y google-cloud-sdk --fix-missing || true + sudo apt-get remove -y google-cloud-cli --fix-missing || true + + # Clean up + sudo apt-get autoremove -y + sudo apt-get clean + sudo docker image prune --all --force + sudo rm -rf /var/lib/apt/lists/* + + echo "After cleanup:" + df -h + - name: Checkout repository uses: actions/checkout@v4 diff --git a/Dockerfile.gpu b/Dockerfile.gpu index e8e70d1ad..26a1687c6 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -3,77 +3,63 @@ FROM node:20-slim AS frontend-builder WORKDIR /app -# Copy package files and install dependencies (including dev for build) -COPY chainforge/react-server/package*.json ./ -RUN npm ci --legacy-peer-deps --prefer-offline - -# Copy source files and build +# Copy everything and build in one layer to minimize size COPY chainforge/react-server/ ./ -RUN npm run build +RUN npm ci --legacy-peer-deps --prefer-offline --production=false && \ + npm run build && \ + rm -rf node_modules && \ + npm cache clean --force # Stage 2 - Build Python dependencies (GPU version with CUDA support) FROM python:3.12-slim AS python-builder -# Install only the build dependencies we need -RUN apt-get --allow-releaseinfo-change update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - git \ - && rm -rf /var/lib/apt/lists/* - WORKDIR /build -# Upgrade pip tools first (this layer is highly cacheable) -RUN pip install --no-cache-dir --upgrade pip setuptools wheel - -# Copy requirements first for better layer caching -COPY chainforge/requirements.txt chainforge/constraints.txt ./ - -# Install PyTorch CPU-only FIRST as it's the largest dependency -# This separates the longest-running install into its own layer -RUN pip install --no-cache-dir --prefix=/install \ - --extra-index-url https://download.pytorch.org/whl/cu121 \ - torch torchvision torchaudio - -# Install remaining requirements with constraints -# Using --find-links to help pip resolve faster -RUN pip install --no-cache-dir --prefix=/install \ - -r requirements.txt \ - -c constraints.txt - -# Copy project files and build the package (smallest layer last) -COPY setup.py README.md ./ +# Copy all requirements and source files +COPY chainforge/requirements.txt chainforge/constraints.txt setup.py README.md ./ COPY chainforge/ ./chainforge/ -RUN pip install --no-cache-dir --prefix=/install . + +# Do everything in one layer to minimize build context and layers +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends build-essential git && \ + pip install --no-cache-dir --upgrade pip setuptools wheel && \ + pip install --no-cache-dir --prefix=/install \ + --extra-index-url https://download.pytorch.org/whl/cu121 \ + torch torchvision torchaudio && \ + pip install --no-cache-dir --prefix=/install \ + -r requirements.txt \ + -c constraints.txt && \ + pip install --no-cache-dir --prefix=/install . && \ + apt-get purge -y --auto-remove build-essential && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /root/.cache # Stage 3 - Final minimal runtime image FROM python:3.12-slim -# Install only runtime dependencies (no build tools) -RUN apt-get --allow-releaseinfo-change update && \ - apt-get install -y --no-install-recommends \ - git \ - libgomp1 \ - && rm -rf /var/lib/apt/lists/* \ - && apt-get clean - WORKDIR /chainforge -# Copy Python packages from builder +# Copy Python packages and React build from builder stages COPY --from=python-builder /install /usr/local - -# Copy the built React app from the frontend-builder stage to the installed package location COPY --from=frontend-builder /app/build /usr/local/lib/python3.12/site-packages/chainforge/react-server/build -# Clean up any unnecessary files to reduce image size -RUN find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ +# Install runtime deps, clean up, and create user in one layer +RUN apt-get --allow-releaseinfo-change update && \ + apt-get install -y --no-install-recommends git libgomp1 && \ + rm -rf /var/lib/apt/lists/* && \ + apt-get clean && \ + find /usr/local -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true && \ find /usr/local -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \ + find /usr/local -type d -name "*.dist-info" -exec rm -rf {}/RECORD {} + 2>/dev/null || true && \ find /usr/local -name "*.pyc" -delete && \ find /usr/local -name "*.pyo" -delete && \ - find /usr/local -name "*.md" -delete 2>/dev/null || true - -# Run as non-root user for security -RUN useradd -m -u 1000 chainforge && \ + find /usr/local -name "*.a" -delete && \ + find /usr/local -name "*.md" -delete 2>/dev/null || true && \ + find /usr/local -name "*.txt" -delete 2>/dev/null || true && \ + rm -rf /usr/local/lib/python3.12/site-packages/*/tests && \ + rm -rf /usr/local/lib/python3.12/site-packages/*/test && \ + rm -rf /tmp/* /var/tmp/* && \ + useradd -m -u 1000 chainforge && \ mkdir -p /home/chainforge/.local/share/chainforge && \ chown -R chainforge:chainforge /chainforge /home/chainforge From e882c51d209e84b5456502e2c803cc200fd0fd68 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Fri, 28 Nov 2025 17:46:45 -0500 Subject: [PATCH 27/32] decluttering the GA build file and also reducing the clutter on docer hub by stream lining the docker image tags --- .github/workflows/docker-build.yml | 206 +++++++++++++++++------------ 1 file changed, 119 insertions(+), 87 deletions(-) diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 97b55128c..aa5077788 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -14,10 +14,10 @@ on: tags: - 'v*' -# # Concurrency: cancel in-progress runs when new one starts -# concurrency: -# group: ${{ github.workflow }}-${{ github.ref }} -# cancel-in-progress: true +# Concurrency: cancel in-progress runs when new one starts +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true env: REGISTRY: docker.io @@ -47,29 +47,33 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch,suffix=-amd64 - type=ref,event=pr,suffix=-amd64 - type=semver,pattern={{version}},suffix=-amd64 - type=semver,pattern={{major}}.{{minor}},suffix=-amd64 - type=raw,value=cpu-amd64 - - - name: Build and push CPU AMD64 image + - name: Build CPU AMD64 image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + push: false platforms: linux/amd64 provenance: false sbom: false + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + id: build-amd64 + + - name: Export digest + if: github.event_name != 'pull_request' + run: | + mkdir -p /tmp/digests + digest="${{ steps.build-amd64.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: digests-cpu-amd64 + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 build-cpu-arm64: name: Build CPU ARM64 Image @@ -94,29 +98,33 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch,suffix=-arm64 - type=ref,event=pr,suffix=-arm64 - type=semver,pattern={{version}},suffix=-arm64 - type=semver,pattern={{major}}.{{minor}},suffix=-arm64 - type=raw,value=cpu-arm64 - - - name: Build and push CPU ARM64 image + - name: Build CPU ARM64 image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + push: false platforms: linux/arm64 provenance: false sbom: false + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + id: build-arm64 + + - name: Export digest + if: github.event_name != 'pull_request' + run: | + mkdir -p /tmp/digests + digest="${{ steps.build-arm64.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: digests-cpu-arm64 + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 build-gpu-amd64: name: Build GPU AMD64 Image @@ -174,29 +182,33 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Extract metadata (tags, labels) - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch,suffix=-gpu-amd64 - type=ref,event=pr,suffix=-gpu-amd64 - type=semver,pattern={{version}},suffix=-gpu-amd64 - type=semver,pattern={{major}}.{{minor}},suffix=-gpu-amd64 - type=raw,value=gpu-amd64 - - - name: Build and push GPU AMD64 image + - name: Build GPU AMD64 image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.gpu - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + push: false platforms: linux/amd64 provenance: false sbom: false + outputs: type=image,name=${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }} + id: build-gpu + + - name: Export digest + if: github.event_name != 'pull_request' + run: | + mkdir -p /tmp/digests + digest="${{ steps.build-gpu.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: digests-gpu-amd64 + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 create-cpu-manifest: @@ -209,32 +221,41 @@ jobs: packages: write steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-cpu-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Create and push CPU manifest + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=cpu + type=raw,value=latest + + - name: Create and push multi-arch manifest + working-directory: /tmp/digests run: | - # Determine tags based on ref - if [[ "${{ github.ref }}" == refs/tags/* ]]; then - VERSION=${GITHUB_REF#refs/tags/v} - MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2) - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION} \ - -t ${{ env.IMAGE_NAME }}:${MAJOR_MINOR} \ - -t ${{ env.IMAGE_NAME }}:cpu \ - -t ${{ env.IMAGE_NAME }}:latest \ - ${{ env.IMAGE_NAME }}:cpu-amd64 \ - ${{ env.IMAGE_NAME }}:cpu-arm64 - else - BRANCH=${GITHUB_REF#refs/heads/} - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${BRANCH} \ - -t ${{ env.IMAGE_NAME }}:cpu \ - -t ${{ env.IMAGE_NAME }}:latest \ - ${{ env.IMAGE_NAME }}:cpu-amd64 \ - ${{ env.IMAGE_NAME }}:cpu-arm64 - fi + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *) + env: + DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} create-gpu-manifest: name: Create GPU Manifest @@ -246,26 +267,37 @@ jobs: packages: write steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-gpu-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Create and push GPU manifest (AMD64 only) + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch,suffix=-gpu + type=semver,pattern={{version}},suffix=-gpu + type=semver,pattern={{major}}.{{minor}},suffix=-gpu + type=raw,value=gpu + + - name: Create and push GPU manifest + working-directory: /tmp/digests run: | - # Determine tags based on ref - # GPU images are AMD64 only due to storage constraints and limited ARM64 CUDA support - if [[ "${{ github.ref }}" == refs/tags/* ]]; then - VERSION=${GITHUB_REF#refs/tags/v} - MAJOR_MINOR=$(echo $VERSION | cut -d. -f1,2) - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${VERSION}-gpu \ - -t ${{ env.IMAGE_NAME }}:${MAJOR_MINOR}-gpu \ - -t ${{ env.IMAGE_NAME }}:gpu \ - ${{ env.IMAGE_NAME }}:gpu-amd64 - else - BRANCH=${GITHUB_REF#refs/heads/} - docker buildx imagetools create -t ${{ env.IMAGE_NAME }}:${BRANCH}-gpu \ - -t ${{ env.IMAGE_NAME }}:gpu \ - ${{ env.IMAGE_NAME }}:gpu-amd64 - fi + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *) + env: + DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} From 1f03585ca465cfd0a6fc4e4a696b934319fc06b1 Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Fri, 28 Nov 2025 17:57:48 -0500 Subject: [PATCH 28/32] [skip ci] added docs --- DOCKER.md | 214 ++++++++++++++++++++++++++++++++--------- README.md | 44 +++++++-- docker-compose.gpu.yml | 2 +- docker-compose.yml | 4 +- 4 files changed, 204 insertions(+), 60 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 262cb7e3d..c031eb7c4 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -2,8 +2,8 @@ This document describes how to run ChainForge using Docker. ChainForge provides two Docker image variants: -- **CPU (latest)**: Optimized for CPU-only environments with dependency constraints -- **GPU**: Supports GPU acceleration without dependency constraints +- **CPU (latest)**: Multi-architecture (AMD64 + ARM64) optimized for CPU-only environments +- **GPU**: AMD64-only with CUDA support for GPU acceleration ## Prerequisites @@ -11,6 +11,12 @@ This document describes how to run ChainForge using Docker. ChainForge provides - Docker Compose (version 2.0 or later) - For GPU: NVIDIA Docker runtime (nvidia-docker2) +## Architecture Support + +**CPU Images**: Available for both AMD64 and ARM64 architectures. Docker automatically pulls the correct architecture for your system. + +**GPU Images**: AMD64 only (ARM64 GPU support is limited and CUDA packages are very large) + ## Quick Start ### CPU Version (Default) @@ -71,28 +77,30 @@ Access ChainForge at: http://localhost:8000 ## Image Variants ### CPU (latest) -- Uses `constraints.txt` for dependency version pinning -- Optimized for CPU-only environments -- Smaller image size -- Compatible with all platforms (amd64, arm64) -- Tagged as: `latest`, `cpu` +- **Architectures**: AMD64, ARM64 (multi-arch manifest) +- **Size**: Optimized and minimal (~800MB compressed) +- **Dependencies**: Uses `constraints.txt` for version pinning +- **PyTorch**: CPU-only build from https://download.pytorch.org/whl/cpu +- **Tags**: `latest`, `cpu`, branch names (e.g., `main`, `ragforge`), version tags (e.g., `v1.0`, `1.0`) ### GPU -- Does NOT use `constraints.txt` for maximum GPU compatibility -- Supports NVIDIA GPU acceleration -- Larger image size due to GPU-enabled dependencies -- Requires NVIDIA Docker runtime -- Tagged as: `gpu` +- **Architecture**: AMD64 only +- **Size**: Larger due to CUDA support (~2-3GB compressed) +- **Dependencies**: Uses `constraints.txt` for version pinning +- **PyTorch**: CUDA 12.1 build from https://download.pytorch.org/whl/cu121 +- **Tags**: `gpu`, branch names with `-gpu` suffix (e.g., `main-gpu`, `ragforge-gpu`), version tags with `-gpu` suffix (e.g., `v1.0-gpu`, `1.0-gpu`) +- **Requirements**: NVIDIA GPU with CUDA support, nvidia-docker runtime **When to use GPU variant:** -- You have NVIDIA GPUs available +- You have NVIDIA GPUs available (AMD64 architecture) - You need GPU acceleration for ML/AI workloads -- You want the latest versions of GPU-enabled packages +- You're running compute-intensive models locally **When to use CPU variant:** - Running on CPU-only machines +- Using ARM64 devices (Apple Silicon, Raspberry Pi, etc.) - Deploying to cloud platforms without GPU -- Want stable, version-pinned dependencies +- Smaller image size is preferred ## Managing Containers @@ -152,55 +160,167 @@ HUGGINGFACE_API_KEY=your_key_here ## Docker Image Structure -Multi-stage build optimized for size: - -1. **Stage 1**: Build React frontend with all dependencies -2. **Stage 2**: Build Python dependencies (with/without constraints) -3. **Stage 3**: Create minimal runtime image with only necessary files +Multi-stage build optimized for minimal size and fast builds: + +### Stage 1: Frontend Builder +- Starts from `node:20-slim` +- Installs npm dependencies and builds React frontend +- Cleans up node_modules and npm cache after build +- Only the `/build` directory is copied to final image + +### Stage 2: Python Builder +- Starts from `python:3.12-slim` +- Installs build dependencies (build-essential, git) +- Installs PyTorch (CPU or CUDA variant) +- Installs Python dependencies from `requirements.txt` with `constraints.txt` +- Installs ChainForge package +- Purges build tools and cleans caches + +### Stage 3: Runtime Image +- Minimal `python:3.12-slim` base +- Only runtime dependencies: git, libgomp1 +- Copies Python packages from builder +- Copies React build from frontend builder +- Aggressive cleanup of unnecessary files (tests, docs, cache, static libs) +- Runs as non-root user (chainforge, uid 1000) + +**Optimizations:** +- Multi-stage build keeps final image small +- No build tools in runtime image +- All RUN commands combined into single layers to minimize layer count +- Aggressive file cleanup reduces image size by ~30% ## Automated Builds (CI/CD) -Docker images are automatically built and pushed to Docker Hub via GitHub Actions when: +Docker images are automatically built and pushed to Docker Hub via GitHub Actions. + +### Build Triggers + +Builds run on: +- **Pull Requests**: Builds are tested but NOT pushed to Docker Hub +- **Branch Pushes**: `main`, `master`, `ragforge` - Built and pushed with branch-specific tags +- **Version Tags**: `v*` (e.g., `v1.0.0`) - Built and pushed with version tags -- A pull request is created (images are built but not pushed) -- Code is pushed to main/master branch -- A version tag is created (e.g., `v1.0.0`) +### Build Architecture -### GitHub Actions Workflow +The workflow uses a **parallel multi-architecture build strategy**: -The workflow builds both CPU and GPU variants: +1. **3 Parallel Build Jobs**: + - `build-cpu-amd64`: Builds CPU variant for AMD64 + - `build-cpu-arm64`: Builds CPU variant for ARM64 + - `build-gpu-amd64`: Builds GPU variant for AMD64 (with aggressive disk cleanup) + +2. **Manifest Creation Jobs**: + - `create-cpu-manifest`: Combines AMD64 + ARM64 into multi-arch CPU manifest + - `create-gpu-manifest`: Creates GPU manifest (AMD64 only) + +**Why separate builds?** +- **No QEMU emulation** - Native builds are 3-5x faster than cross-compilation +- **Parallel execution** - All architectures build simultaneously +- **Better caching** - Each architecture has independent build cache + +### Available Tags + +**CPU Images** (multi-arch: amd64 + arm64): +``` +gauransh/chainforge:latest +gauransh/chainforge:cpu +gauransh/chainforge:main +gauransh/chainforge:ragforge +gauransh/chainforge:v1.0.0 +gauransh/chainforge:1.0 +``` -**CPU Image Tags:** -- `latest` - Always points to the latest CPU build -- `cpu` - Explicit CPU tag -- `main` / `master` - Branch-specific tags -- `v1.0.0`, `v1.0` - Version tags (on release) +**GPU Images** (amd64 only): +``` +gauransh/chainforge:gpu +gauransh/chainforge:main-gpu +gauransh/chainforge:ragforge-gpu +gauransh/chainforge:v1.0.0-gpu +gauransh/chainforge:1.0-gpu +``` -**GPU Image Tags:** -- `gpu` - Latest GPU build -- `main-gpu` / `master-gpu` - Branch-specific GPU tags -- `v1.0.0-gpu`, `v1.0-gpu` - Version GPU tags (on release) +### Storage Optimizations -### Required GitHub Secrets +To prevent hitting GitHub Actions storage limits: -To enable automated image publishing, configure these secrets in your GitHub repository: +1. **No GitHub Actions cache** - Eliminated cache storage overhead +2. **No ARM64 GPU builds** - GPU only builds for AMD64 (50% storage reduction) +3. **Disabled provenance and SBOM** - Reduces metadata size +4. **Aggressive runner cleanup** - GPU builds free ~30-40GB before starting by removing: + - .NET SDK, Android tools, GHC, CodeQL + - LLVM, PHP, MongoDB, MySQL + - Chrome, Firefox, Azure CLI, Google Cloud SDK +5. **Minimal Dockerfile** - All operations combined into single layers -- `DOCKER_USERNAME` - Your Docker Hub username -- `DOCKER_PASSWORD` - Your Docker Hub password or access token +### Concurrency Control -Navigate to: `Settings > Secrets and variables > Actions > New repository secret` +The workflow uses concurrency groups to automatically cancel in-progress builds when a new commit is pushed to the same branch: -### Workflow Optimizations +```yaml +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +``` -The workflow includes several optimizations to prevent unnecessary builds: +### Skip CI -1. **Path Filters**: Only triggers when Docker-related files change (Dockerfiles, chainforge/, setup.py, etc.) -2. **Concurrency Control**: Automatically cancels in-progress builds when a new one starts -3. **Skip CI**: Add `[skip ci]` or `[ci skip]` to your commit message to skip the build +To skip Docker builds entirely, add `[skip ci]` or `[ci skip]` to your commit message: -Example: ```bash -git commit -m "Update README [skip ci]" +git commit -m "Update documentation [skip ci]" +git commit -m "Fix typo [ci skip]" +``` + +This prevents all build jobs from running, saving time and resources. + +### GitHub Secrets Required + +To enable automated image publishing, configure these secrets: + +- `DOCKER_USERNAME` - Docker Hub username +- `DOCKER_PASSWORD` - Docker Hub password or personal access token + +**Setup**: Repository Settings → Secrets and variables → Actions → New repository secret + +### Build Workflow Summary + +``` +┌─────────────────────────────────────────────────────────┐ +│ PR or Push Event │ +└─────────────────────────────────────────────────────────┘ + │ + ┌───────────┴───────────┐ + │ Concurrency Check │ + │ (Cancel old builds?) │ + └───────────┬───────────┘ + │ + ┌───────────────────┼───────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌──────────────┐ ┌──────────────┐ ┌──────────────┐ +│ CPU AMD64 │ │ CPU ARM64 │ │ GPU AMD64 │ +│ Build │ │ Build │ │ Build │ +│ │ │ │ │ (w/ cleanup) │ +└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ + │ │ │ + │ upload digest │ upload digest │ upload digest + │ │ │ + └────────┬─────────┴──────────────────┘ + │ + ┌─────────┴──────────┐ + │ │ + ▼ ▼ +┌─────────────┐ ┌─────────────┐ +│ CPU │ │ GPU │ +│ Manifest │ │ Manifest │ +│ (amd64+arm64)│ │ (amd64 only)│ +└─────────────┘ └─────────────┘ + │ │ + └─────────┬──────────┘ + │ + ▼ + Push to Docker Hub ``` ## Troubleshooting diff --git a/README.md b/README.md index c78c5a42f..8503b587c 100644 --- a/README.md +++ b/README.md @@ -50,19 +50,43 @@ You can set your API keys by clicking the Settings icon in the top-right corner. ## Run using Docker -You can use our [Dockerfile](/Dockerfile) to run `ChainForge` locally using `Docker Desktop`: +ChainForge provides pre-built Docker images for both CPU and GPU environments: -- Build the `Dockerfile`: - ```shell - docker build -t chainforge . - ``` +**Quick start with Docker Compose (recommended):** -- Run the image: - ```shell - docker run -p 8000:8000 chainforge - ``` +```bash +# CPU version (works on AMD64 and ARM64) +docker-compose up -d + +# GPU version (AMD64 only, requires NVIDIA Docker runtime) +docker-compose -f docker-compose.gpu.yml up -d +``` + +**Or use Docker CLI:** + +```bash +# Pull and run CPU version +docker pull gauransh/chainforge:latest +docker run -d -p 8000:8000 --name chainforge gauransh/chainforge:latest + +# Pull and run GPU version +docker pull gauransh/chainforge:gpu +docker run -d -p 8000:8000 --gpus all --name chainforge-gpu gauransh/chainforge:gpu +``` + +**Or build locally:** + +```bash +# Build CPU version +docker build -t chainforge . + +# Build GPU version +docker build -f Dockerfile.gpu -t chainforge:gpu . +``` + +Access ChainForge at http://localhost:8000 -Now you can open the browser of your choice and open `http://127.0.0.1:8000`. +For detailed Docker documentation including architecture support, environment variables, and CI/CD setup, see [DOCKER.md](DOCKER.md). # Supported providers diff --git a/docker-compose.gpu.yml b/docker-compose.gpu.yml index a61975fd3..8387ebda2 100644 --- a/docker-compose.gpu.yml +++ b/docker-compose.gpu.yml @@ -1,5 +1,5 @@ services: - chainforge: + chainforge-gpu: build: context: . dockerfile: Dockerfile.gpu diff --git a/docker-compose.yml b/docker-compose.yml index cc45ee811..46bd14444 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,8 +3,8 @@ services: build: context: . dockerfile: Dockerfile - image: gauransh/chainforge:cpu - container_name: chainforge-cpu + image: gauransh/chainforge:latest + container_name: chainforge ports: - "8000:8000" volumes: From e734aeeba9d9364eff21db2b92a64d137dbf796b Mon Sep 17 00:00:00 2001 From: gauranshkumar Date: Mon, 1 Dec 2025 20:05:57 -0500 Subject: [PATCH 29/32] adding an help tool --- chainforge/react-server/src/ChunkNode.tsx | 2 + .../react-server/src/CodeEvaluatorNode.tsx | 9 +++ chainforge/react-server/src/CommentNode.tsx | 8 ++- .../react-server/src/DocumentationButton.tsx | 65 +++++++++++++++++++ chainforge/react-server/src/InspectorNode.tsx | 2 + chainforge/react-server/src/ItemsNode.tsx | 10 +-- chainforge/react-server/src/JoinNode.tsx | 2 + chainforge/react-server/src/LLMEvalNode.tsx | 2 + chainforge/react-server/src/MediaNode.tsx | 2 + chainforge/react-server/src/MultiEvalNode.tsx | 4 ++ chainforge/react-server/src/PromptNode.tsx | 5 ++ chainforge/react-server/src/RerankNode.tsx | 2 + chainforge/react-server/src/RetrievalNode.tsx | 4 ++ chainforge/react-server/src/ScriptNode.tsx | 2 + .../react-server/src/SelectVarsNode.tsx | 4 ++ .../react-server/src/SimpleEvalNode.tsx | 4 ++ chainforge/react-server/src/SplitNode.tsx | 2 + .../react-server/src/TabularDataNode.tsx | 4 +- .../react-server/src/TextFieldsNode.tsx | 10 +-- chainforge/react-server/src/UploadNode.tsx | 2 + chainforge/react-server/src/VisNode.tsx | 2 + 21 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 chainforge/react-server/src/DocumentationButton.tsx diff --git a/chainforge/react-server/src/ChunkNode.tsx b/chainforge/react-server/src/ChunkNode.tsx index 59b2cb8ce..bf8fee1d5 100644 --- a/chainforge/react-server/src/ChunkNode.tsx +++ b/chainforge/react-server/src/ChunkNode.tsx @@ -17,6 +17,7 @@ import LLMResponseInspectorModal, { } from "./LLMResponseInspectorModal"; import InspectFooter from "./InspectFooter"; import { IconSearch } from "@tabler/icons-react"; +import DocumentationButton from "./DocumentationButton"; import ChunkMethodListContainer, { ChunkMethodSpec, @@ -271,6 +272,7 @@ const ChunkNode: React.FC = ({ data, id }) => { status={status} handleRunClick={runChunking} runButtonTooltip="Perform chunking on input text" + customButtons={[]} /> { const btns: React.ReactNode[] = []; + // Documentation button + btns.push( + , + ); + // If this is Python and we are running locally, the user has // two options ---whether to run code in sandbox with pyodide, or from Flask (unsafe): if (progLang === "python" && IS_RUNNING_LOCALLY) diff --git a/chainforge/react-server/src/CommentNode.tsx b/chainforge/react-server/src/CommentNode.tsx index 8971efe30..c192d2315 100644 --- a/chainforge/react-server/src/CommentNode.tsx +++ b/chainforge/react-server/src/CommentNode.tsx @@ -3,6 +3,7 @@ import useStore from "./store"; import NodeLabel from "./NodeLabelComponent"; import BaseNode from "./BaseNode"; import { Textarea } from "@mantine/core"; +import DocumentationButton from "./DocumentationButton"; export interface CommentNodeProps { data: { @@ -28,7 +29,12 @@ const CommentNode: React.FC = ({ data, id }) => { return ( - + ]} + />