# Docker Guide

Comprehensive guide for working with Docker in the manacore-monorepo.

## Table of Contents

- [Overview](#overview)
- [Docker Templates](#docker-templates)
- [Building Images](#building-images)
- [Running Containers](#running-containers)
- [Docker Compose](#docker-compose)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)

## Overview

The monorepo uses Docker for:

- **Development**: Local service orchestration
- **CI/CD**: Automated builds and tests
- **Production**: Deployment and scaling

### Image Strategy

All images use:

- **Multi-stage builds**: Smaller production images
- **Alpine Linux**: Minimal base images
- **Non-root users**: Enhanced security
- **Health checks**: Automatic monitoring
- **Layer caching**: Faster builds

## Docker Templates

Templates are located in `docker/templates/`. Use these as starting points for new services.

### NestJS Backend Template

**File**: `docker/templates/Dockerfile.nestjs`

**Usage**:

```dockerfile
# Copy template
cp docker/templates/Dockerfile.nestjs apps/myproject/apps/backend/Dockerfile

# Customize for your service
```

**Build Arguments**:

- `SERVICE_PATH`: Path to service (e.g., `apps/chat/apps/backend`)
- `PORT`: Service port (default: 3000)
- `HEALTH_PATH`: Health check endpoint (default: `/health`)

**Example**:

```bash
docker build \
  --build-arg SERVICE_PATH=apps/chat/apps/backend \
  --build-arg PORT=3002 \
  --build-arg HEALTH_PATH=/api/health \
  -t chat-backend:latest \
  -f docker/templates/Dockerfile.nestjs \
  .
```

### SvelteKit Web Template

**File**: `docker/templates/Dockerfile.sveltekit`

**Features**:

- SSR support
- Environment variable injection
- Static asset optimization
- Health endpoint

**Usage**:

```bash
docker build \
  --build-arg SERVICE_PATH=apps/chat/apps/web \
  --build-arg PORT=3000 \
  -t chat-web:latest \
  -f docker/templates/Dockerfile.sveltekit \
  .
```

### Astro Landing Page Template

**File**: `docker/templates/Dockerfile.astro`

**Features**:

- Static site serving with Nginx
- Gzip compression
- Security headers
- Asset caching

**Nginx Configuration**: `docker/nginx/astro.conf`

**Usage**:

```bash
docker build \
  --build-arg SERVICE_PATH=apps/chat/apps/landing \
  -t chat-landing:latest \
  -f docker/templates/Dockerfile.astro \
  .
```

## Building Images

### Local Development Builds

```bash
# Build single service
docker build -t service-name:dev -f apps/project/apps/service/Dockerfile .

# Build with cache
docker build --cache-from service-name:latest -t service-name:dev .

# Build without cache
docker build --no-cache -t service-name:dev .
```

### Production Builds

```bash
# Build for production
docker build \
  --build-arg NODE_ENV=production \
  -t service-name:latest \
  -f Dockerfile .

# Build for multiple platforms
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t service-name:latest \
  .
```

### Using Build Script

```bash
# Build all services
./scripts/deploy/build-and-push.sh all latest

# Build specific service
./scripts/deploy/build-and-push.sh chat-backend v1.0.0

# Build without pushing
DOCKER_PUSH=false ./scripts/deploy/build-and-push.sh chat-backend dev
```

## Running Containers

### Run Single Container

```bash
# Run with environment file
docker run -d \
  --name chat-backend \
  --env-file .env.production \
  -p 3002:3002 \
  chat-backend:latest

# Run with environment variables
docker run -d \
  --name chat-backend \
  -e NODE_ENV=production \
  -e PORT=3002 \
  -p 3002:3002 \
  chat-backend:latest

# Run with volume mount
docker run -d \
  --name chat-backend \
  -v $(pwd)/logs:/app/logs \
  -p 3002:3002 \
  chat-backend:latest
```

### Interactive Debugging

```bash
# Run with shell
docker run -it --rm chat-backend:latest /bin/sh

# Execute command in running container
docker exec -it chat-backend sh

# View logs
docker logs -f chat-backend

# View last 100 lines
docker logs --tail=100 chat-backend
```

### Health Checks

```bash
# Check container health
docker inspect --format='{{.State.Health.Status}}' chat-backend

# View health check logs
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' chat-backend
```

## Docker Compose

### Development Environment

**File**: `docker-compose.dev.yml`

Start services for local development:

```bash
# Start all services
pnpm run docker:up

# Start with specific profile
pnpm run docker:up:auth
pnpm run docker:up:chat

# View logs
pnpm run docker:logs

# Stop all services
pnpm run docker:down
```

### Staging Environment

**File**: `docker-compose.staging.yml`

```bash
# Deploy to staging
docker compose -f docker-compose.staging.yml up -d

# Scale service
docker compose -f docker-compose.staging.yml up -d --scale chat-backend=3

# View status
docker compose -f docker-compose.staging.yml ps

# View logs
docker compose -f docker-compose.staging.yml logs -f chat-backend
```

### Production Environment

**File**: `docker-compose.production.yml`

```bash
# Deploy to production
docker compose -f docker-compose.production.yml up -d

# Rolling update
docker compose -f docker-compose.production.yml up -d --no-deps service-name

# Zero-downtime deployment
docker compose up -d --scale service=2 service
sleep 30
docker compose up -d --scale service=1 service
```

### Common Commands

```bash
# Start services
docker compose up -d

# Stop services
docker compose stop

# Restart service
docker compose restart service-name

# View logs
docker compose logs -f

# Execute command
docker compose exec service-name sh

# Remove all containers
docker compose down

# Remove containers and volumes
docker compose down -v
```

## Best Practices

### 1. Optimize Layer Caching

Order Dockerfile commands from least to most frequently changing:

```dockerfile
# Good
COPY package.json pnpm-lock.yaml ./
RUN pnpm install
COPY . .

# Bad (cache invalidated on every code change)
COPY . .
RUN pnpm install
```

### 2. Use .dockerignore

Create `.dockerignore` to exclude unnecessary files:

```
node_modules
dist
.git
.env
*.log
```

### 3. Multi-Stage Builds

Always use multi-stage builds for smaller images:

```dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN pnpm install && pnpm build

# Production stage
FROM node:20-alpine AS production
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/main.js"]
```

### 4. Security Best Practices

```dockerfile
# Use non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nestjs -u 1001
USER nestjs

# Don't include secrets
# Use environment variables or Docker secrets

# Scan images for vulnerabilities
docker scan image-name:latest
```

### 5. Health Checks

Always include health checks:

```dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
```

### 6. Resource Limits

Set resource limits in docker-compose:

```yaml
services:
  backend:
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
```

### 7. Logging

Configure logging drivers:

```yaml
services:
  backend:
    logging:
      driver: 'json-file'
      options:
        max-size: '10m'
        max-file: '3'
```

### 8. Environment Variables

Use environment files:

```bash
# .env.production
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://...
```

```yaml
services:
  backend:
    env_file:
      - .env.production
```

## Troubleshooting

### Container Won't Start

**Issue**: Container exits immediately

**Debug**:

```bash
# View container logs
docker logs container-name

# Check exit code
docker inspect --format='{{.State.ExitCode}}' container-name

# Run interactively
docker run -it --rm image-name sh
```

### Out of Disk Space

**Issue**: Docker runs out of disk space

**Solution**:

```bash
# Check disk usage
docker system df

# Remove unused containers
docker container prune

# Remove unused images
docker image prune -a

# Remove everything unused
docker system prune -a --volumes

# Remove specific resources
docker rm $(docker ps -aq)
docker rmi $(docker images -q)
```

### Build Fails

**Issue**: Docker build fails

**Debug**:

```bash
# Build with verbose output
docker build --progress=plain --no-cache -t image-name .

# Check build context
docker build --dry-run .

# Build specific stage
docker build --target builder -t image-name .
```

### Network Issues

**Issue**: Containers can't communicate

**Debug**:

```bash
# List networks
docker network ls

# Inspect network
docker network inspect bridge

# Test connectivity
docker exec container1 ping container2

# Check DNS
docker exec container1 nslookup container2
```

### Performance Issues

**Issue**: Container runs slowly

**Debug**:

```bash
# Check resource usage
docker stats

# Check container processes
docker top container-name

# Analyze image layers
docker history image-name
```

### Permission Issues

**Issue**: Permission denied errors

**Solution**:

```bash
# Check file ownership
docker exec container-name ls -la /app

# Fix ownership in Dockerfile
RUN chown -R nodejs:nodejs /app
USER nodejs
```

### Environment Variables Not Working

**Issue**: Env vars not available in container

**Debug**:

```bash
# Check environment
docker exec container-name env

# Verify env file
cat .env.production

# Test with explicit vars
docker run -e VAR=value image-name
```

## Advanced Topics

### Docker BuildKit

Enable for better builds:

```bash
# Enable BuildKit
export DOCKER_BUILDKIT=1

# Build with BuildKit
docker build .

# Use buildx for multi-platform
docker buildx build --platform linux/amd64,linux/arm64 .
```

### Docker Secrets

For sensitive data:

```bash
# Create secret
echo "secret-value" | docker secret create my_secret -

# Use in service
docker service create \
  --secret my_secret \
  --name my-service \
  image-name
```

### Docker Volumes

Persist data:

```bash
# Create volume
docker volume create my-data

# Use volume
docker run -v my-data:/app/data image-name

# Backup volume
docker run --rm -v my-data:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz /data
```

### Custom Networks

Isolate services:

```bash
# Create network
docker network create --driver bridge my-network

# Run container on network
docker run --network my-network image-name

# Connect existing container
docker network connect my-network container-name
```

## Resources

- [Docker Documentation](https://docs.docker.com)
- [Docker Best Practices](https://docs.docker.com/develop/dev-best-practices/)
- [Dockerfile Reference](https://docs.docker.com/engine/reference/builder/)
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
