armature-framework 0.2.2

A modern, type-safe HTTP framework for Rust inspired by Angular and NestJS. Features dependency injection, decorators, middleware, authentication (JWT/OAuth2/SAML), validation, OpenAPI/Swagger, caching, job queues, and observability.
# Docker Guide

This guide covers containerizing Armature applications with Docker for consistent, portable deployments.

## Table of Contents

- [Overview]#overview
- [Basic Dockerfile]#basic-dockerfile
- [Multi-Stage Build]#multi-stage-build
- [Docker Compose]#docker-compose
- [Best Practices]#best-practices
- [Common Patterns]#common-patterns

## Overview

Docker provides consistent deployment environments for Armature applications. Benefits include:

- **Consistent environments** across development, staging, and production
- **Easy scaling** with container orchestration
- **Isolation** from host system
- **Reproducible builds** with multi-stage Dockerfiles

## Basic Dockerfile

```dockerfile
FROM rust:1.75-slim-bookworm as builder

WORKDIR /app
COPY . .

RUN cargo build --release

FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/my-api /usr/local/bin/

EXPOSE 3000

CMD ["my-api"]
```

## Multi-Stage Build

Optimized Dockerfile with caching for faster builds:

```dockerfile
# Stage 1: Build dependencies
FROM rust:1.75-slim-bookworm as deps

WORKDIR /app

# Install build dependencies
RUN apt-get update && apt-get install -y pkg-config libssl-dev && rm -rf /var/lib/apt/lists/*

# Create a dummy project to cache dependencies
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release && rm -rf src

# Stage 2: Build application
FROM deps as builder

COPY src ./src
RUN touch src/main.rs && cargo build --release

# Stage 3: Runtime
FROM debian:bookworm-slim

RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN useradd -r -s /bin/false appuser

WORKDIR /app
COPY --from=builder /app/target/release/my-api /app/

# Set ownership
RUN chown -R appuser:appuser /app

USER appuser

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

CMD ["./my-api"]
```

## Docker Compose

### Development Setup

```yaml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src
    environment:
      - RUST_LOG=debug
      - DATABASE_URL=postgres://user:pass@db:5432/app
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:
```

### Production Setup with Ferron

```yaml
version: '3.8'

services:
  ferron:
    image: ferronweb/ferron:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./ferron.conf:/etc/ferron/ferron.conf:ro
      - certs:/var/lib/ferron/certs
    depends_on:
      - app

  app:
    build:
      context: .
      dockerfile: Dockerfile
    expose:
      - "3000"
    environment:
      - RUST_LOG=info
      - DATABASE_URL=postgres://user:pass@db:5432/app
      - REDIS_URL=redis://redis:6379
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1'
          memory: 512M
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  certs:
  pgdata:
  redisdata:
```

## Best Practices

### 1. Use Multi-Stage Builds

Separate build and runtime stages for smaller images:

```dockerfile
# Build stage
FROM rust:1.75 as builder
# ... build steps

# Runtime stage
FROM debian:bookworm-slim
# ... only runtime files
```

### 2. Run as Non-Root User

```dockerfile
RUN useradd -r -s /bin/false appuser
USER appuser
```

### 3. Add Health Checks

```dockerfile
HEALTHCHECK --interval=30s --timeout=5s \
    CMD curl -f http://localhost:3000/health || exit 1
```

### 4. Use .dockerignore

```dockerignore
target/
.git/
.env
*.md
tests/
docs/
```

### 5. Set Resource Limits

```yaml
deploy:
  resources:
    limits:
      cpus: '1'
      memory: 512M
    reservations:
      cpus: '0.25'
      memory: 256M
```

### 6. Use Slim Base Images

Prefer `debian:bookworm-slim` or `alpine` over full images.

### 7. Cache Dependencies

Copy `Cargo.toml` and `Cargo.lock` first, then build deps before copying source.

## Common Patterns

### Development Hot Reload

```dockerfile
# Dockerfile.dev
FROM rust:1.75

RUN cargo install cargo-watch

WORKDIR /app
COPY Cargo.toml Cargo.lock ./

CMD ["cargo", "watch", "-x", "run"]
```

### With Static Assets

```dockerfile
# Build frontend
FROM node:20 as frontend
WORKDIR /web
COPY web/package*.json ./
RUN npm ci
COPY web/ ./
RUN npm run build

# Build backend
FROM rust:1.75 as backend
WORKDIR /app
COPY . .
RUN cargo build --release

# Runtime
FROM debian:bookworm-slim
COPY --from=backend /app/target/release/my-api /app/
COPY --from=frontend /web/dist /app/static/
CMD ["/app/my-api"]
```

### With Ferron Sidecar

```dockerfile
# ferron.Dockerfile
FROM ferronweb/ferron:latest
COPY ferron.conf /etc/ferron/ferron.conf
CMD ["ferron", "-c", "/etc/ferron/ferron.conf"]
```

## Summary

- Use **multi-stage builds** for smaller images
- Run as **non-root user** for security
- Add **health checks** for orchestration
- Use **Docker Compose** for local development
- Set **resource limits** in production
- Separate **development and production** Dockerfiles