529 lines
12 KiB
Markdown
529 lines
12 KiB
Markdown
|
|
# Docker Deployment Guide
|
||
|
|
|
||
|
|
Brainy provides **zero-configuration Docker deployment** with automatic model embedding. Deploy to any cloud provider with fast startup times and no runtime model downloads.
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
**1. Install models package:**
|
||
|
|
```bash
|
||
|
|
npm install @soulcraft/brainy-models
|
||
|
|
```
|
||
|
|
|
||
|
|
**2. Add to Dockerfile:**
|
||
|
|
```dockerfile
|
||
|
|
RUN npm run extract-models # ← Automatic model extraction
|
||
|
|
COPY --from=builder /app/models ./models # ← Include models in image
|
||
|
|
```
|
||
|
|
|
||
|
|
**3. Deploy anywhere:**
|
||
|
|
```bash
|
||
|
|
gcloud run deploy --source . # Google Cloud
|
||
|
|
aws ecs create-service ... # AWS
|
||
|
|
az container create ... # Azure
|
||
|
|
```
|
||
|
|
|
||
|
|
**That's it!** No configuration, environment variables, or custom setup needed.
|
||
|
|
|
||
|
|
## How It Works
|
||
|
|
|
||
|
|
### Build Time
|
||
|
|
1. `npm run extract-models` automatically finds `@soulcraft/brainy-models`
|
||
|
|
2. Extracts models to `./models` directory
|
||
|
|
3. Creates marker file for runtime detection
|
||
|
|
4. Models are embedded in Docker image
|
||
|
|
|
||
|
|
### Runtime
|
||
|
|
1. Brainy auto-detects extracted models in `./models`
|
||
|
|
2. Loads models locally without network calls
|
||
|
|
3. **7x faster startup** compared to downloading models
|
||
|
|
4. Works offline and in restricted networks
|
||
|
|
|
||
|
|
### Priority Order
|
||
|
|
Brainy uses this fallback hierarchy:
|
||
|
|
1. **Auto-extracted models** (`./models` directory) ← **Fastest**
|
||
|
|
2. `BRAINY_MODELS_PATH` environment variable
|
||
|
|
3. `@soulcraft/brainy-models` package
|
||
|
|
4. Remote URL download ← **Slowest**
|
||
|
|
|
||
|
|
## Universal Dockerfile Template
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Universal Brainy Dockerfile - Works on all cloud providers
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
|
||
|
|
WORKDIR /app
|
||
|
|
|
||
|
|
# Install dependencies including models
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
|
||
|
|
# Copy source and extract models
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models # ← Zero-config model extraction
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
# Production stage
|
||
|
|
FROM node:24-alpine AS production
|
||
|
|
|
||
|
|
WORKDIR /app
|
||
|
|
|
||
|
|
# Install production dependencies only
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci --only=production --omit=optional && npm cache clean --force
|
||
|
|
|
||
|
|
# Copy application and auto-extracted models
|
||
|
|
COPY --from=builder /app/dist ./dist
|
||
|
|
COPY --from=builder /app/models ./models # ← Models included automatically
|
||
|
|
|
||
|
|
# Security: non-root user
|
||
|
|
RUN addgroup -g 1001 -S nodejs && adduser -S brainy -u 1001
|
||
|
|
RUN chown -R brainy:nodejs /app
|
||
|
|
USER brainy
|
||
|
|
|
||
|
|
# Environment
|
||
|
|
ENV NODE_ENV=production
|
||
|
|
|
||
|
|
# Health check for all cloud providers
|
||
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||
|
|
CMD node -e "console.log('Health check passed')" || exit 1
|
||
|
|
|
||
|
|
# Start application
|
||
|
|
CMD ["node", "dist/server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
## Cloud Provider Examples
|
||
|
|
|
||
|
|
### Google Cloud Run
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
FROM node:24-alpine AS production
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci --only=production --omit=optional
|
||
|
|
COPY --from=builder /app/dist ./dist
|
||
|
|
COPY --from=builder /app/models ./models
|
||
|
|
ENV PORT=8080
|
||
|
|
EXPOSE 8080
|
||
|
|
CMD ["node", "dist/server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
Deploy:
|
||
|
|
```bash
|
||
|
|
gcloud run deploy brainy-app \
|
||
|
|
--source . \
|
||
|
|
--platform managed \
|
||
|
|
--region us-central1 \
|
||
|
|
--memory 2Gi \
|
||
|
|
--cpu 1
|
||
|
|
```
|
||
|
|
|
||
|
|
### AWS Lambda
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
FROM public.ecr.aws/lambda/nodejs:24
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models
|
||
|
|
CMD ["index.handler"]
|
||
|
|
```
|
||
|
|
|
||
|
|
Deploy:
|
||
|
|
```bash
|
||
|
|
# Build and push to ECR
|
||
|
|
docker build -t brainy-lambda .
|
||
|
|
docker tag brainy-lambda:latest $ECR_URI:latest
|
||
|
|
docker push $ECR_URI:latest
|
||
|
|
|
||
|
|
# Create/update function
|
||
|
|
aws lambda create-function \
|
||
|
|
--function-name brainy-function \
|
||
|
|
--package-type Image \
|
||
|
|
--code ImageUri=$ECR_URI:latest \
|
||
|
|
--timeout 60 \
|
||
|
|
--memory-size 2048
|
||
|
|
```
|
||
|
|
|
||
|
|
### AWS ECS/Fargate
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
FROM node:24-alpine AS production
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci --only=production --omit=optional
|
||
|
|
COPY --from=builder /app/dist ./dist
|
||
|
|
COPY --from=builder /app/models ./models
|
||
|
|
ENV PORT=3000
|
||
|
|
EXPOSE 3000
|
||
|
|
CMD ["node", "dist/server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
ECS Task Definition:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"family": "brainy-task",
|
||
|
|
"cpu": "1024",
|
||
|
|
"memory": "2048",
|
||
|
|
"requiresCompatibilities": ["FARGATE"],
|
||
|
|
"networkMode": "awsvpc",
|
||
|
|
"containerDefinitions": [{
|
||
|
|
"name": "brainy-container",
|
||
|
|
"image": "your-ecr-repo/brainy:latest",
|
||
|
|
"memory": 2048,
|
||
|
|
"portMappings": [{"containerPort": 3000}],
|
||
|
|
"logConfiguration": {
|
||
|
|
"logDriver": "awslogs",
|
||
|
|
"options": {
|
||
|
|
"awslogs-group": "/ecs/brainy-task",
|
||
|
|
"awslogs-region": "us-east-1",
|
||
|
|
"awslogs-stream-prefix": "ecs"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Azure Container Instances
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
FROM node:24-alpine AS production
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci --only=production --omit=optional
|
||
|
|
COPY --from=builder /app/dist ./dist
|
||
|
|
COPY --from=builder /app/models ./models
|
||
|
|
ENV PORT=80
|
||
|
|
EXPOSE 80
|
||
|
|
CMD ["node", "dist/server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
Deploy:
|
||
|
|
```bash
|
||
|
|
# Build and push to Azure Container Registry
|
||
|
|
az acr build --registry myregistry --image brainy:latest .
|
||
|
|
|
||
|
|
# Deploy to Container Instances
|
||
|
|
az container create \
|
||
|
|
--resource-group myResourceGroup \
|
||
|
|
--name brainy-container \
|
||
|
|
--image myregistry.azurecr.io/brainy:latest \
|
||
|
|
--cpu 1 \
|
||
|
|
--memory 2 \
|
||
|
|
--ports 80 \
|
||
|
|
--environment-variables NODE_ENV=production
|
||
|
|
```
|
||
|
|
|
||
|
|
### Cloudflare Workers
|
||
|
|
|
||
|
|
Due to size constraints, Cloudflare Workers use R2 storage:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// wrangler.toml
|
||
|
|
[[r2_buckets]]
|
||
|
|
binding = "BRAINY_MODELS_BUCKET"
|
||
|
|
bucket_name = "brainy-models"
|
||
|
|
|
||
|
|
// worker.js
|
||
|
|
export default {
|
||
|
|
async fetch(request, env) {
|
||
|
|
const brainy = new BrainyData({
|
||
|
|
storageAdapter: new CloudflareR2Storage(env.BRAINY_MODELS_BUCKET),
|
||
|
|
customModelsPath: 'r2://brainy-models/models'
|
||
|
|
})
|
||
|
|
|
||
|
|
await brainy.init()
|
||
|
|
// Your logic here
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Comparison
|
||
|
|
|
||
|
|
| Deployment Method | Cold Start Time | Memory Usage | Network Calls | Reliability |
|
||
|
|
|-------------------|----------------|--------------|---------------|-------------|
|
||
|
|
| **Auto-extracted models** | ~2 seconds | +500MB | 0 | 99.9% |
|
||
|
|
| **Environment variable** | ~2 seconds | +500MB | 0 | 99.9% |
|
||
|
|
| **@soulcraft/brainy-models** | ~3 seconds | +500MB | 0 | 99.8% |
|
||
|
|
| **Remote download** | ~15 seconds | +200MB | Multiple | 95% |
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
### Success Messages (What You Want to See)
|
||
|
|
|
||
|
|
```
|
||
|
|
[Brainy Model Extractor] 🔍 Checking for @soulcraft/brainy-models...
|
||
|
|
[Brainy Model Extractor] ✅ Found @soulcraft/brainy-models package
|
||
|
|
[Brainy Model Extractor] 📦 Creating models directory...
|
||
|
|
[Brainy Model Extractor] 📋 Copying models from: /app/node_modules/@soulcraft/brainy-models/models
|
||
|
|
[Brainy Model Extractor] ✅ Models extracted successfully!
|
||
|
|
[Brainy Model Extractor] 🎉 Model extraction completed successfully!
|
||
|
|
```
|
||
|
|
|
||
|
|
At runtime:
|
||
|
|
```
|
||
|
|
🎯 Auto-detected extracted models at: /app/models
|
||
|
|
✅ Successfully loaded model from custom directory
|
||
|
|
Using custom model path for Docker/production deployment
|
||
|
|
```
|
||
|
|
|
||
|
|
### Fallback Messages (When Models Not Found)
|
||
|
|
|
||
|
|
```
|
||
|
|
⚠️ Local model not found. Falling back to remote model loading.
|
||
|
|
For best performance and reliability:
|
||
|
|
1. Install @soulcraft/brainy-models: npm install @soulcraft/brainy-models
|
||
|
|
2. Or set BRAINY_MODELS_PATH environment variable for Docker deployments
|
||
|
|
3. Or use customModelsPath option in RobustModelLoader
|
||
|
|
```
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Models Not Found
|
||
|
|
|
||
|
|
**Symptoms:**
|
||
|
|
- Warning: "Local model not found. Falling back to remote model loading"
|
||
|
|
- Slow startup times (15+ seconds)
|
||
|
|
- Network timeouts in restricted environments
|
||
|
|
|
||
|
|
**Solutions:**
|
||
|
|
1. **Check package.json**: Ensure `@soulcraft/brainy-models` is in `dependencies` (not `devDependencies`)
|
||
|
|
2. **Check Dockerfile**: Verify `RUN npm run extract-models` is present
|
||
|
|
3. **Check Docker build**: Look for extraction success messages
|
||
|
|
4. **Inspect image**: `docker run -it your-image ls -la /app/models`
|
||
|
|
|
||
|
|
### Memory Issues
|
||
|
|
|
||
|
|
**Symptoms:**
|
||
|
|
- Container OOM (Out of Memory) kills
|
||
|
|
- Slow performance
|
||
|
|
- Failed deployments
|
||
|
|
|
||
|
|
**Solutions:**
|
||
|
|
- **Cloud Run**: `--memory 2Gi`
|
||
|
|
- **Lambda**: `--memory-size 2048`
|
||
|
|
- **ECS**: Set memory in task definition to 2048
|
||
|
|
- **Azure**: `--memory 2`
|
||
|
|
|
||
|
|
### Build Failures
|
||
|
|
|
||
|
|
**Symptoms:**
|
||
|
|
- `npm run extract-models` fails
|
||
|
|
- "Cannot find module" errors
|
||
|
|
- Build timeouts
|
||
|
|
|
||
|
|
**Solutions:**
|
||
|
|
1. Use Node.js 24+ base image
|
||
|
|
2. Ensure sufficient disk space during build
|
||
|
|
3. Check that `@soulcraft/brainy-models` installs correctly
|
||
|
|
4. Verify npm scripts are present in package.json
|
||
|
|
|
||
|
|
### Environment Detection Issues
|
||
|
|
|
||
|
|
**Symptoms:**
|
||
|
|
- Models not auto-detected
|
||
|
|
- Wrong storage adapter chosen
|
||
|
|
|
||
|
|
**Debug commands:**
|
||
|
|
```bash
|
||
|
|
# Check if models directory exists
|
||
|
|
docker run -it your-image ls -la /app/models
|
||
|
|
|
||
|
|
# Check marker file
|
||
|
|
docker run -it your-image cat /app/models/.brainy-models-extracted
|
||
|
|
|
||
|
|
# Test model loading
|
||
|
|
docker run -it your-image node -e "
|
||
|
|
import('./dist/unified.js').then(brainy => {
|
||
|
|
const db = new brainy.BrainyData({skipEmbeddings: true});
|
||
|
|
console.log('Brainy loaded successfully');
|
||
|
|
})
|
||
|
|
"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Advanced Configuration
|
||
|
|
|
||
|
|
### Custom Models Path
|
||
|
|
|
||
|
|
If you need to override the auto-detection:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
const brainy = new BrainyData({
|
||
|
|
customModelsPath: '/custom/path/to/models'
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
Or use environment variable:
|
||
|
|
```dockerfile
|
||
|
|
ENV BRAINY_MODELS_PATH=/custom/path/to/models
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multiple Model Versions
|
||
|
|
|
||
|
|
Support multiple model versions in the same image:
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Extract different model versions
|
||
|
|
RUN npm run extract-models
|
||
|
|
RUN mkdir -p ./models/v1 ./models/v2
|
||
|
|
RUN cp -r ./models/universal-sentence-encoder ./models/v1/
|
||
|
|
# Copy v2 models to ./models/v2/
|
||
|
|
```
|
||
|
|
|
||
|
|
### Custom Extraction Script
|
||
|
|
|
||
|
|
Create your own extraction logic:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// custom-extract.js
|
||
|
|
import { extractModels } from './node_modules/@soulcraft/brainy/scripts/extract-models.js'
|
||
|
|
|
||
|
|
// Custom extraction with additional processing
|
||
|
|
await extractModels()
|
||
|
|
|
||
|
|
// Add custom models or processing
|
||
|
|
// ...
|
||
|
|
```
|
||
|
|
|
||
|
|
## Security Considerations
|
||
|
|
|
||
|
|
### Best Practices
|
||
|
|
|
||
|
|
1. **Use non-root user**: Always run containers as non-root
|
||
|
|
2. **Minimal base image**: Use Alpine Linux for smaller attack surface
|
||
|
|
3. **No secrets in models**: Models are public, but ensure no credentials
|
||
|
|
4. **Read-only filesystem**: Mount models directory as read-only if possible
|
||
|
|
|
||
|
|
### Network Security
|
||
|
|
|
||
|
|
- **No external calls**: Models load locally, reducing network exposure
|
||
|
|
- **Offline capability**: Works in air-gapped environments
|
||
|
|
- **Consistent versions**: No risk of model tampering during download
|
||
|
|
|
||
|
|
## CI/CD Integration
|
||
|
|
|
||
|
|
### GitHub Actions
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
name: Build and Deploy Brainy App
|
||
|
|
|
||
|
|
on:
|
||
|
|
push:
|
||
|
|
branches: [main]
|
||
|
|
|
||
|
|
jobs:
|
||
|
|
build-and-deploy:
|
||
|
|
runs-on: ubuntu-latest
|
||
|
|
|
||
|
|
steps:
|
||
|
|
- uses: actions/checkout@v4
|
||
|
|
|
||
|
|
- name: Set up Docker Buildx
|
||
|
|
uses: docker/setup-buildx-action@v3
|
||
|
|
|
||
|
|
- name: Build Docker image
|
||
|
|
run: |
|
||
|
|
docker build -t brainy-app .
|
||
|
|
# Models are automatically extracted during build
|
||
|
|
|
||
|
|
- name: Deploy to Cloud Run
|
||
|
|
run: |
|
||
|
|
gcloud run deploy brainy-app \
|
||
|
|
--image brainy-app \
|
||
|
|
--platform managed \
|
||
|
|
--memory 2Gi
|
||
|
|
```
|
||
|
|
|
||
|
|
### GitLab CI
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
stages:
|
||
|
|
- build
|
||
|
|
- deploy
|
||
|
|
|
||
|
|
build:
|
||
|
|
stage: build
|
||
|
|
script:
|
||
|
|
- docker build -t brainy-app .
|
||
|
|
# Models extracted automatically
|
||
|
|
|
||
|
|
deploy:
|
||
|
|
stage: deploy
|
||
|
|
script:
|
||
|
|
- aws ecs update-service --service brainy-service
|
||
|
|
```
|
||
|
|
|
||
|
|
## Multi-Stage Optimization
|
||
|
|
|
||
|
|
### Minimize Image Size
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
COPY . .
|
||
|
|
RUN npm run extract-models
|
||
|
|
RUN npm run build
|
||
|
|
# Clean up unnecessary files
|
||
|
|
RUN rm -rf node_modules/@soulcraft/brainy-models/docs \
|
||
|
|
node_modules/@soulcraft/brainy-models/examples \
|
||
|
|
node_modules/@soulcraft/brainy-models/.git*
|
||
|
|
|
||
|
|
FROM node:24-alpine AS production
|
||
|
|
WORKDIR /app
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci --only=production --omit=optional && npm cache clean --force
|
||
|
|
COPY --from=builder /app/dist ./dist
|
||
|
|
COPY --from=builder /app/models ./models # Only essential model files
|
||
|
|
RUN addgroup -g 1001 -S nodejs && adduser -S brainy -u 1001
|
||
|
|
RUN chown -R brainy:nodejs /app
|
||
|
|
USER brainy
|
||
|
|
CMD ["node", "dist/server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Layer Caching Optimization
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Optimize for layer caching
|
||
|
|
FROM node:24-alpine AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
|
||
|
|
# Cache dependencies layer
|
||
|
|
COPY package*.json ./
|
||
|
|
RUN npm ci
|
||
|
|
|
||
|
|
# Cache extraction layer (only changes when models update)
|
||
|
|
RUN npm run extract-models
|
||
|
|
|
||
|
|
# Application layer (changes frequently)
|
||
|
|
COPY . .
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
# Production optimizations...
|
||
|
|
```
|
||
|
|
|
||
|
|
This comprehensive guide covers everything needed for successful Docker deployments across all cloud providers while maintaining the zero-configuration approach!
|