Files
ollama37/docker/Makefile
Shang Chieh Tseng 4810471b33 Redesign Docker build system to two-stage architecture with builder/runtime separation
Redesigned the Docker build system from a single-stage monolithic design to a clean
two-stage architecture that separates build environment from compilation process while
maintaining library path compatibility.

## Architecture Changes

### Builder Image (docker/builder/Dockerfile)
- Provides base environment: CUDA 11.4, GCC 10, CMake 4, Go 1.25.3
- Built once, cached for subsequent builds (~90 min first time)
- Removed config file copying (cuda-11.4.sh, gcc-10.conf, go.sh)
- Added comprehensive comments explaining each build step
- Added git installation for runtime stage source cloning

### Runtime Image (docker/runtime/Dockerfile)
- Two-stage build using ollama37-builder as base for BOTH stages
- Stage 1 (compile): Clone source from GitHub → CMake configure → Build C/C++/CUDA → Build Go
- Stage 2 (runtime): Copy artifacts from stage 1 → Setup environment → Configure server
- Both stages use identical base image to ensure library path compatibility
- Removed -buildvcs=false flag (VCS info embedded from git clone)
- Comprehensive comments documenting library paths and design rationale

### Makefile (docker/Makefile)
- Simplified from 289 to 145 lines (-50% complexity)
- Removed: run, stop, logs, shell, test targets (use docker-compose instead)
- Removed: build orchestration targets (start-builder, copy-source, run-cmake, etc.)
- Removed: artifact copying (handled internally by multi-stage build)
- Focus: Build images only (build, build-builder, build-runtime, clean, help)
- All runtime operations delegated to docker-compose.yml

### Documentation (docker/README.md)
- Completely rewritten for new two-stage architecture
- Added "Build System Components" section with file structure
- Documented why both runtime stages use builder base (library path compatibility)
- Updated build commands to use Makefile
- Updated runtime commands to use docker-compose
- Added comprehensive troubleshooting section
- Added build time and image size tables
- Reference to archived single-stage design

## Key Design Decision

**Problem**: Compiled binaries have hardcoded library paths
**Solution**: Use ollama37-builder as base for BOTH compile and runtime stages
**Trade-off**: Larger image (~18GB) vs guaranteed library compatibility

## Benefits

-  Cleaner separation of concerns (builder env vs compilation vs runtime)
-  Builder image cached after first build (90 min → <1 min rebuilds)
-  Runtime rebuilds only take ~10 min (pulls latest code from GitHub)
-  No library path mismatches (identical base images)
-  No complex artifact extraction (multi-stage COPY)
-  Simpler Makefile focused on image building
-  Runtime management via docker-compose (industry standard)

## Files Changed

Modified:
- docker/builder/Dockerfile - Added comments, removed COPY config files
- docker/runtime/Dockerfile - Converted to two-stage build
- docker/Makefile - Simplified to focus on image building only
- docker/README.md - Comprehensive rewrite for new architecture

Deleted:
- docker/builder/README.md - No longer needed
- docker/builder/cuda-11.4.sh - Generated in Dockerfile
- docker/builder/gcc-10.conf - Generated in Dockerfile
- docker/builder/go.sh - Generated in Dockerfile

Archived:
- docker/Dockerfile → docker/Dockerfile.single-stage.archived

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 13:14:49 +08:00

145 lines
4.8 KiB
Makefile

# Makefile for Ollama37 Docker Build System
#
# This Makefile manages the two-stage Docker build process:
# 1. Builder image: Base environment with CUDA 11.4, GCC 10, CMake 4, Go 1.25.3
# 2. Runtime image: Two-stage build that compiles and packages Ollama
#
# The runtime Dockerfile handles:
# - Cloning source from GitHub
# - CMake configuration and C/C++/CUDA compilation
# - Go binary compilation
# - Packaging runtime environment
#
# Usage:
# make build - Build builder and runtime images (default)
# make build-builder - Build only the builder image
# make build-runtime - Build only the runtime image
# make clean - Remove all Docker images
# make help - Show help message
#
# To run the container, use docker-compose:
# docker-compose up -d
# docker-compose logs -f
# docker-compose down
# Configuration
BUILDER_IMAGE := ollama37-builder
BUILDER_TAG := latest
RUNTIME_IMAGE := ollama37
RUNTIME_TAG := latest
SOURCE_DIR := $(shell cd .. && pwd)
BUILDER_DOCKERFILE := $(SOURCE_DIR)/docker/builder/Dockerfile
RUNTIME_DOCKERFILE := $(SOURCE_DIR)/docker/runtime/Dockerfile
# Docker build context directories
BUILDER_CONTEXT := $(SOURCE_DIR)/docker/builder
RUNTIME_CONTEXT := $(SOURCE_DIR)
.PHONY: all build build-builder build-runtime ensure-builder clean help
# Default target
all: build
# Build both builder and runtime images
build: build-builder build-runtime
@echo ""
@echo "✓ All images built successfully!"
@echo " Builder: $(BUILDER_IMAGE):$(BUILDER_TAG)"
@echo " Runtime: $(RUNTIME_IMAGE):$(RUNTIME_TAG)"
@echo ""
@echo "To start the Ollama server:"
@echo " docker-compose up -d"
@echo ""
@echo "View logs:"
@echo " docker-compose logs -f"
@echo ""
@echo "Stop the server:"
@echo " docker-compose down"
# Build the builder base image
build-builder:
@echo "→ Building builder image..."
@echo " Image: $(BUILDER_IMAGE):$(BUILDER_TAG)"
@echo " Dockerfile: $(BUILDER_DOCKERFILE)"
@echo ""
@docker build \
-f $(BUILDER_DOCKERFILE) \
-t $(BUILDER_IMAGE):$(BUILDER_TAG) \
$(BUILDER_CONTEXT)
@echo ""
@echo "✓ Builder image built successfully!"
# Build the runtime image (requires builder image)
build-runtime: ensure-builder
@echo "→ Building runtime image..."
@echo " Image: $(RUNTIME_IMAGE):$(RUNTIME_TAG)"
@echo " Dockerfile: $(RUNTIME_DOCKERFILE)"
@echo ""
@echo " This will:"
@echo " - Clone ollama37 source from GitHub"
@echo " - Configure with CMake (CUDA 11 preset)"
@echo " - Compile C/C++/CUDA libraries"
@echo " - Build Go binary"
@echo " - Package runtime environment"
@echo ""
@docker build \
-f $(RUNTIME_DOCKERFILE) \
-t $(RUNTIME_IMAGE):$(RUNTIME_TAG) \
$(RUNTIME_CONTEXT)
@echo ""
@echo "✓ Runtime image built successfully!"
@echo ""
@echo "To start the Ollama server:"
@echo " docker-compose up -d"
# Ensure builder image exists (build if not present)
ensure-builder:
@if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^$(BUILDER_IMAGE):$(BUILDER_TAG)$$"; then \
echo "→ Builder image not found. Building $(BUILDER_IMAGE):$(BUILDER_TAG)..."; \
echo ""; \
$(MAKE) build-builder; \
echo ""; \
fi
# Remove all Docker images
clean:
@echo "→ Removing Docker images..."
@docker rmi $(RUNTIME_IMAGE):$(RUNTIME_TAG) 2>/dev/null || echo " No runtime image to remove"
@docker rmi $(BUILDER_IMAGE):$(BUILDER_TAG) 2>/dev/null || echo " No builder image to remove"
@echo ""
@echo "✓ Images removed"
@echo ""
@echo "Note: To remove containers and volumes, use:"
@echo " docker-compose down -v"
# Show help message
help:
@echo "Ollama37 Docker Build System"
@echo ""
@echo "Build Targets:"
@echo " make build - Build builder and runtime images (default)"
@echo " make build-builder - Build only the builder base image"
@echo " make build-runtime - Build only the runtime image"
@echo " make clean - Remove all Docker images"
@echo " make help - Show this help message"
@echo ""
@echo "Configuration:"
@echo " BUILDER_IMAGE: $(BUILDER_IMAGE):$(BUILDER_TAG)"
@echo " RUNTIME_IMAGE: $(RUNTIME_IMAGE):$(RUNTIME_TAG)"
@echo ""
@echo "Dockerfiles:"
@echo " Builder: $(BUILDER_DOCKERFILE)"
@echo " Runtime: $(RUNTIME_DOCKERFILE)"
@echo ""
@echo "Build Architecture:"
@echo " 1. Builder image: Base environment (CUDA 11.4, GCC 10, CMake 4, Go 1.25.3)"
@echo " 2. Runtime image: Two-stage build (compile + package)"
@echo " - Stage 1: Clone source, compile C/C++/CUDA/Go"
@echo " - Stage 2: Package runtime with compiled binaries"
@echo ""
@echo "Container Management (use docker-compose):"
@echo " docker-compose up -d - Start Ollama server"
@echo " docker-compose logs -f - View logs"
@echo " docker-compose down - Stop server"
@echo " docker-compose down -v - Stop and remove volumes"