Skip to main content
Priya Nair·

Multi-stage distroless Dockerfile dropped my Next image from 1.1GB to 180MB and runs non-root

Create optimized Dockerfiles and docker-compose configurations with multi-stage builds, security hardening, and development/production parity.

Dockerfile & Compose Optimizer

Act as a Docker optimization specialist. Create production-ready Docker configurations for my application. **Application Description:** {{app_description}} **Tech Stack:** {{tech_stack}} **Application Dependencies:** {{app_dependencies}} **Port Requirements:** {{port_requirements}} **Environment Variables:** {{env_variables}} **Deployment Context:** {{deployment_context}} Generate: 1. **Optimized Dockerfile**: Multi-stage build minimizing final image size, using distroless or minimal base images 2. **.dockerignore**: Comprehensive ignore patterns 3. **docker-compose.yml**: Development setup with hot-reload and debugging 4. **docker-compose.prod.yml**: Production setup with replicas, health checks, resource limits 5. **docker-compose.test.yml**: Test environment with Testcontainers-compatible setup 6. **Security Hardening**: Non-root user, read-only filesystem, capability dropping, no secrets in layers 7. **Health Checks**: Proper HEALTHCHECK instructions with endpoints 8. **Build Optimization**: Layer caching strategy, dependency caching between builds 9. **Entrypoint Script**: Graceful shutdown handling, environment validation before start 10. **Migration/Seed Scripts**: Database initialization on first container start Output all files with inline security and optimization comments.

Ergebnisse

Hardened Docker setup for a Next.js 15 standalone app. Multi-stage build cuts the image from ~1.1 GB to ~180 MB and runs as a non-root user on a distroless runtime. ```dockerfile # syntax=docker/dockerfile:1 FROM node:20-alpine AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN --mount=type=cache,target=/root/.npm npm ci FROM node:20-alpine AS build WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build # emits .next/standalone FROM gcr.io/distroless/nodejs20-debian12 AS runtime WORKDIR /app ENV NODE_ENV=production COPY --from=build /app/.next/standalone ./ COPY --from=build /app/.next/static ./.next/static USER nonroot # distroless ships a nonroot uid EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s CMD ["node", "-e", "fetch('http://localhost:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] CMD ["server.js"] ``` ``` # .dockerignore node_modules .next/cache .git *.test.ts .env* ``` **Security notes:** distroless has no shell, so an RCE has nothing to pivot into; the build cache mount keeps `npm ci` warm without leaking into the final layer; no secrets are baked — they arrive at runtime via env. **Compose tip:** add `read_only: true` plus a `tmpfs: /tmp` mount in `docker-compose.prod.yml` to lock the root filesystem.

Modell: Claude Sonnet 4

35 Likes13 SavesScore: 23

2 Kommentare

Ryan Mitchell·

This made my PR review 20 minutes shorter. Appreciate it.

Marco Rossi·

Didn't expect the graceful-shutdown handling, that's the detail that matters in prod.