askill
docker-workflows

docker-workflowsSafety 95Repository

Build and deploy Docker images in the monorepo - multi-stage builds, platform targeting, GHCR integration, and container optimization. Use this skill when working with Docker.

0 stars
1.2k downloads
Updated 2/18/2026

Package Files

Loading files...
SKILL.md

Docker Workflows

This skill covers Docker workflows in the monorepo, including multi-stage builds, platform targeting, GitHub Container Registry (GHCR) integration, and container optimization.

Overview

The monorepo uses Docker for:

  • Building production images for deployment
  • Kubernetes job execution (caelundas)
  • Local development environments (Supabase)
  • CI/CD pipelines for testing and deployment

Docker Configuration

Project Structure

applications/caelundas/
  Dockerfile              # Multi-stage build
  .dockerignore          # Exclude node_modules, etc.
  docker-compose.yml     # Local development

Multi-Stage Build

Caelundas uses multi-stage builds for optimal image size:

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app

# Copy package files
COPY package*.json ./
COPY pnpm-lock.yaml ./

# Install dependencies
RUN npm install -g pnpm && pnpm install --frozen-lockfile

# Copy source
COPY . .

# Build application
RUN pnpm build

# Stage 2: Runtime
FROM node:20-alpine AS runner
WORKDIR /app

# Copy only production dependencies and built app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# Set production environment
ENV NODE_ENV=production

# Run application
CMD ["node", "dist/main.js"]

Benefits of Multi-Stage Builds

  • Smaller image size: Final image only includes runtime dependencies
  • Faster deployments: Less data to transfer
  • Security: Build tools not included in production image
  • Clear separation: Build vs runtime concerns

Platform Targeting

Why Platform Targeting Matters

Apple Silicon Macs (M1/M2) use arm64 architecture, but Kubernetes clusters often run amd64. Building images on Apple Silicon without platform targeting creates incompatible images.

Building for linux/amd64

# Single platform
docker build --platform linux/amd64 -t caelundas:latest .

# Multi-platform (if needed)
docker buildx build --platform linux/amd64,linux/arm64 -t caelundas:latest .

Nx Target Configuration

{
  "targets": {
    "docker-build": {
      "executor": "nx:run-commands",
      "options": {
        "command": "docker build --platform linux/amd64 -t ghcr.io/jimmypaolini/caelundas:latest .",
        "cwd": "applications/caelundas"
      }
    }
  }
}

Verification

Check image platform:

docker inspect ghcr.io/jimmypaolini/caelundas:latest | jq '.[0].Architecture'
# Should output: "amd64"

GitHub Container Registry (GHCR)

Authentication

# Login with personal access token
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin

# Or use GitHub CLI
gh auth token | docker login ghcr.io -u USERNAME --password-stdin

Image Tagging Convention

# Latest tag (main branch)
ghcr.io/jimmypaolini/caelundas:latest

# Version tag (semantic version)
ghcr.io/jimmypaolini/caelundas:v1.2.3

# Commit SHA tag (CI builds)
ghcr.io/jimmypaolini/caelundas:sha-abc1234

# Branch tag (feature branches)
ghcr.io/jimmypaolini/caelundas:feat-new-feature

Push Images

# Tag image
docker tag caelundas:latest ghcr.io/jimmypaolini/caelundas:latest

# Push to registry
docker push ghcr.io/jimmypaolini/caelundas:latest

Pull Images

# Pull from GHCR
docker pull ghcr.io/jimmypaolini/caelundas:latest

# Run locally
docker run ghcr.io/jimmypaolini/caelundas:latest

Docker Compose

Local Development

# docker-compose.yml
version: "3.8"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: builder # Use builder stage for hot reload
    volumes:
      - ./src:/app/src # Mount source for hot reload
      - ./output:/app/output # Mount output directory
    environment:
      - NODE_ENV=development
      - START_DATE=2024-01-01
      - END_DATE=2024-12-31
    command: pnpm develop

Running with Docker Compose

# Start services
docker-compose up

# Rebuild on changes
docker-compose up --build

# Run in background
docker-compose up -d

# Stop services
docker-compose down

# View logs
docker-compose logs -f app

Image Optimization

Reduce Image Size

  1. Use Alpine base images: node:20-alpine vs node:20 (~100MB vs ~900MB)
  2. Multi-stage builds: Only include runtime dependencies
  3. Layer caching: Copy package files before source
  4. Remove dev dependencies: pnpm install --prod
  5. Clean build artifacts: RUN rm -rf /tmp/* ~/.npm

Layer Caching Strategy

Order Dockerfile commands by frequency of change:

# Rarely changes → cache layer
COPY package*.json ./
RUN pnpm install

# Changes often → invalidates subsequent layers
COPY src ./src
RUN pnpm build

.dockerignore

Exclude unnecessary files to speed up builds:

# .dockerignore
node_modules
dist
.git
.github
*.log
.env
.DS_Store
coverage

Security Best Practices

1. Don't Include Secrets

Never bake secrets into images:

Don't:

ENV DATABASE_URL=postgresql://user:password@host/db

Do:

# Pass secrets at runtime
ENV DATABASE_URL=${DATABASE_URL}

2. Run as Non-Root User

Don't run containers as root:

# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# Switch to nodejs user
USER nodejs

3. Use Specific Image Tags

Avoid latest in production:

Don't:

FROM node:latest

Do:

FROM node:20.11-alpine3.19

4. Scan for Vulnerabilities

# Scan image with Docker Scout
docker scout cves ghcr.io/jimmypaolini/caelundas:latest

# Scan with Trivy
trivy image ghcr.io/jimmypaolini/caelundas:latest

CI/CD Integration

GitHub Actions Workflow

name: Docker Build

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: applications/caelundas
          platforms: linux/amd64
          push: true
          tags: |
            ghcr.io/jimmypaolini/caelundas:latest
            ghcr.io/jimmypaolini/caelundas:${{ github.sha }}

Nx Docker Targets

Build Target

# Build Docker image
nx run caelundas:docker-build

Defined in project.json:

{
  "docker-build": {
    "executor": "nx:run-commands",
    "options": {
      "command": "docker build --platform linux/amd64 -t ghcr.io/jimmypaolini/caelundas:latest .",
      "cwd": "applications/caelundas"
    }
  }
}

Push Target

# Push to GHCR
nx run caelundas:docker-push

Combined Target

# Build and push
nx run-many --target=docker-build --projects=caelundas
nx run-many --target=docker-push --projects=caelundas

Debugging Docker Builds

Build with Output

# See detailed build output
docker build --progress=plain .

Inspect Layers

# See layer sizes
docker history ghcr.io/jimmypaolini/caelundas:latest

# Inspect filesystem
docker run -it ghcr.io/jimmypaolini/caelundas:latest sh

Build Specific Stage

# Build only builder stage
docker build --target builder -t caelundas:builder .

Cache Busting

# Force rebuild without cache
docker build --no-cache .

Common Issues

Platform Mismatch

Error:

WARNING: The requested image's platform (linux/arm64) does not match
the detected host platform (linux/amd64)

Solution:

docker build --platform linux/amd64 .

Build Context Too Large

Error:

Sending build context to Docker daemon: 2.5GB

Solution: Add to .dockerignore:

node_modules
dist
.git

Layer Cache Miss

Issue: Builds are slow because layers aren't cached.

Solution: Order Dockerfile commands strategically:

# Copy package files first (changes less frequently)
COPY package*.json ./
RUN pnpm install

# Copy source code last (changes more frequently)
COPY src ./src

Related Documentation

Best Practices Summary

  1. Use multi-stage builds for smaller images
  2. Target linux/amd64 when deploying to K8s
  3. Push to GHCR with semantic tags
  4. Use Alpine base images for size reduction
  5. Don't include secrets in images
  6. Run as non-root user for security
  7. Scan for vulnerabilities regularly
  8. Order layers by frequency of change
  9. Use .dockerignore to reduce context size
  10. Tag with commit SHA for traceability

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/9/2026

An exceptionally thorough and actionable guide for Docker workflows within a monorepo. It covers the entire lifecycle from local development and multi-stage builds to security, optimization, and CI/CD integration.

95
100
85
98
100

Metadata

Licenseunknown
Version-
Updated2/18/2026
PublisherJimmyPaolini

Tags

ci-cddatabasegithubgithub-actionssecurity