brainy/examples/docker-deployment
2025-08-05 20:39:39 -07:00
..
docker-compose.yml refactor: simplify build system and improve model loading flexibility 2025-08-05 16:09:30 -07:00
Dockerfile fix: update Dockerfile and README to replace model extraction with download 2025-08-05 20:39:39 -07:00
example-app.js refactor: simplify build system and improve model loading flexibility 2025-08-05 16:09:30 -07:00
README.md refactor: simplify build system and improve model loading flexibility 2025-08-05 16:09:30 -07:00

Docker Deployment for Brainy

This guide shows how to deploy Brainy applications with embedded models in Docker containers, avoiding the need to download models at runtime.

Problem

When deploying Node.js applications to Docker containers, node_modules is often ignored in .dockerignore to reduce image size. However, this means the @soulcraft/brainy-models package (containing pre-trained models) won't be included in the container, forcing runtime model downloads from the internet.

Solution

Brainy now supports loading models from custom directories using:

  1. Environment variable: BRAINY_MODELS_PATH or MODELS_PATH
  2. Configuration option: customModelsPath in RobustModelLoader

Deployment Strategies

This approach copies models from node_modules to a custom location during the Docker build process.

# Multi-stage build to extract models
FROM node:24-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Extract models from node_modules
RUN mkdir -p /app/models && \
    if [ -d "./node_modules/@soulcraft/brainy-models" ]; then \
        cp -r ./node_modules/@soulcraft/brainy-models/models/* /app/models/; \
    fi

# Production stage
FROM node:24-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production --omit=optional
COPY . .
COPY --from=builder /app/models /app/models

# Set environment variable
ENV BRAINY_MODELS_PATH=/app/models

CMD ["node", "dist/your-app.js"]

Strategy 2: Mount Models as Volume

Mount pre-downloaded models as a Docker volume:

services:
  brainy-app:
    image: your-brainy-app
    environment:
      - BRAINY_MODELS_PATH=/models
    volumes:
      - ./models:/models:ro

Strategy 3: Init Container Pattern

Use an init container to download models before starting your application:

services:
  model-downloader:
    image: node:24-alpine
    volumes:
      - brainy-models:/models
    command: |
      sh -c "
        npm install @soulcraft/brainy-models
        cp -r node_modules/@soulcraft/brainy-models/models/* /models/
      "

  brainy-app:
    image: your-brainy-app
    environment:
      - BRAINY_MODELS_PATH=/models
    volumes:
      - brainy-models:/models:ro
    depends_on:
      - model-downloader

volumes:
  brainy-models:

Configuration Options

Environment Variables

# Primary environment variable
BRAINY_MODELS_PATH=/app/models

# Alternative variable name
MODELS_PATH=/app/models

Programmatic Configuration

import { BrainyData, RobustModelLoader } from '@soulcraft/brainy'

// Option 1: Configure via RobustModelLoader
const loader = new RobustModelLoader({
  customModelsPath: '/app/models'
})

// Option 2: Environment variable (automatic)
// Just set BRAINY_MODELS_PATH and it will be used automatically

Model Directory Structure

Brainy will search for models in the following subdirectories (in order):

/app/models/
├── universal-sentence-encoder/          # Direct path
├── models/universal-sentence-encoder/   # @soulcraft/brainy-models structure
├── tfhub/universal-sentence-encoder/    # TensorFlow Hub structure
├── use/                                 # Short name
└── model.json                          # Root directory

Cloud Run Deployment

For Google Cloud Run, use the embedded models strategy:

FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Copy models during build
RUN if [ -d "./node_modules/@soulcraft/brainy-models" ]; then \
        mkdir -p /app/models && \
        cp -r ./node_modules/@soulcraft/brainy-models/models/* /app/models/; \
    fi

ENV BRAINY_MODELS_PATH=/app/models
ENV PORT=8080
EXPOSE 8080

CMD ["node", "dist/server.js"]

Deploy with:

gcloud run deploy brainy-app \
  --source . \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --memory 2Gi \
  --cpu 1

AWS Lambda/ECS Deployment

Similar approach works for AWS services:

FROM public.ecr.aws/lambda/nodejs:24

# Copy models during build
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN mkdir -p /var/task/models && \
    cp -r ./node_modules/@soulcraft/brainy-models/models/* /var/task/models/

ENV BRAINY_MODELS_PATH=/var/task/models

CMD ["index.handler"]

Verification

Your application logs should show:

✅ Found model at custom path: /app/models/universal-sentence-encoder/model.json
✅ Successfully loaded model from custom directory
   Using custom model path for Docker/production deployment

Instead of:

⚠️ Local model not found. Falling back to remote model loading.

Benefits

  1. Faster startup: No model download time
  2. Offline deployment: Works without internet access
  3. Predictable performance: No network dependency
  4. Smaller runtime image: Can exclude dev dependencies
  5. Security: No external network calls required

Troubleshooting

Models not found

  1. Check the environment variable is set: echo $BRAINY_MODELS_PATH
  2. Verify models directory exists: ls -la /app/models
  3. Check model structure: find /app/models -name "model.json"

Memory issues

Models require approximately 500MB of RAM. Ensure your container has sufficient memory:

deploy:
  resources:
    limits:
      memory: 2G

Build failures

If @soulcraft/brainy-models is not available during build:

  1. Ensure it's in dependencies, not devDependencies
  2. Use npm ci --only=production instead of npm install
  3. Check the package is properly published and accessible