Skip to main content

Docker Configuration

CORTEX uses Docker for containerization and local development.

Local Development

docker-compose.yml

# infra/docker/docker-compose.yml
version: '3.8'

services:
postgres:
image: postgres:16-alpine
container_name: cortex-postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: cortex
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

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

volumes:
postgres-data:
redis-data:

Commands

# Start services
docker-compose -f infra/docker/docker-compose.yml up -d

# View logs
docker-compose -f infra/docker/docker-compose.yml logs -f

# Stop services
docker-compose -f infra/docker/docker-compose.yml down

# Reset data
docker-compose -f infra/docker/docker-compose.yml down -v

Core Service Dockerfile

# apps/core/Dockerfile

# Build stage
FROM node:20-alpine AS builder

WORKDIR /app

# Install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate

# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/core/package.json ./apps/core/
COPY packages/shared-types/package.json ./packages/shared-types/

# Install dependencies
RUN pnpm install --frozen-lockfile

# Copy source
COPY apps/core ./apps/core
COPY packages/shared-types ./packages/shared-types

# Generate Prisma client
RUN cd apps/core && pnpm prisma generate

# Build
RUN pnpm --filter core build

# Production stage
FROM node:20-alpine AS production

WORKDIR /app

# Install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate

# Copy built files
COPY --from=builder /app/apps/core/dist ./dist
COPY --from=builder /app/apps/core/package.json ./
COPY --from=builder /app/apps/core/prisma ./prisma
COPY --from=builder /app/node_modules ./node_modules

# Set environment
ENV NODE_ENV=production
ENV PORT=8091

EXPOSE 8091

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8091/health || exit 1

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

Building Images

# Build core service
docker build -t cortex-core:latest -f apps/core/Dockerfile .

# Build with specific tag
docker build -t cortex-core:v1.0.0 -f apps/core/Dockerfile .

# Build for multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 \
-t cortex-core:latest -f apps/core/Dockerfile .

Running Containers

# Run with environment file
docker run -d \
--name cortex-core \
--env-file .env \
-p 8091:8091 \
cortex-core:latest

# Run with inline environment
docker run -d \
--name cortex-core \
-e DATABASE_URL="postgresql://..." \
-e JWT_SECRET="..." \
-p 8091:8091 \
cortex-core:latest

# View logs
docker logs -f cortex-core

# Enter container
docker exec -it cortex-core sh

Full Stack Docker Compose

# docker-compose.full.yml
version: '3.8'

services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: cortex
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

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

core:
build:
context: .
dockerfile: apps/core/Dockerfile
ports:
- "8091:8091"
environment:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/cortex
JWT_SECRET: development-jwt-secret-key-at-least-32-chars
JWT_REFRESH_SECRET: development-refresh-secret-at-least-32-chars
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started

web:
build:
context: .
dockerfile: apps/cortex-web/Dockerfile
ports:
- "3090:3000"
environment:
NEXT_PUBLIC_API_URL: http://localhost:8091
depends_on:
- core

volumes:
postgres-data:
redis-data:

Docker Best Practices

1. Multi-stage Builds

Separate build and runtime stages to minimize image size.

2. Non-root User

# Create non-root user
RUN addgroup -S app && adduser -S app -G app
USER app

3. Health Checks

Always include health checks for container orchestration.

4. Layer Caching

Order Dockerfile commands to maximize cache hits:

  1. System packages
  2. Package files (package.json)
  3. Install dependencies
  4. Copy source code
  5. Build

5. .dockerignore

node_modules
.git
.env*
*.md
coverage
dist