🐳 Docker Setup: Container Configuration Generator

SkillCloud & infra

Use this skill when the user says 'Docker', 'Dockerfile', 'docker-compose', 'containerize', 'docker-setup', or needs to containerize an application with optimized Docker images and compose configurations. Do NOT use for serverless or static site deployments.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the 🐳 Docker Setup: Container Configuration Generator skill

What this skill tells your AI

The instructions your AI receives, as published by cwinvestments/memstack in skills/deployment/docker-setup/SKILL.md and read by ahel’s review.

Analyze a project and generate optimized Dockerfiles, docker-compose configs, and deployment-ready container setups with health checks and volume management.

Activation

When this skill activates, output:

🐳 Docker Setup: Containerizing your project...

ContextStatus
User says "Docker", "Dockerfile", "docker-compose"ACTIVE
User wants to containerize their applicationACTIVE
User mentions multi-stage builds, Docker optimization, or .dockerignoreACTIVE
User wants CI/CD with Docker (pipeline focus)DORMANT: see ci-cd-pipeline
User wants server provisioning with Docker installedDORMANT: see hetzner-setup
User wants Kubernetes orchestrationDORMANT: beyond current scope

Protocol

Step 1: Gather Inputs

Ask the user for:

  • Project type: Node.js, Python, Go, Rust, static site?
  • Purpose: Local development, production deployment, or both?
  • Services needed: Database (PostgreSQL, MySQL), cache (Redis), queue (RabbitMQ)?
  • Build artifacts: Does the project compile to a binary or run interpreted?
  • Environment: Where will containers run? (local, VPS, cloud container service)

Step 2: Analyze Project & Generate Dockerfile

Detect project type from files and generate an optimized multi-stage Dockerfile:

Node.js (multi-stage):

# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production

# Security: run as non-root
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 appuser

COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./

USER appuser
EXPOSE 3000

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

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

Python (multi-stage):

# Stage 1: Build
FROM python:3.12-slim AS builder
WORKDIR /app
RUN pip install --no-cache-dir --upgrade pip
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Stage 2: Production
FROM python:3.12-slim AS runner
WORKDIR /app

# Security: run as non-root
RUN groupadd --gid 1001 appgroup && \
    useradd --uid 1001 --gid appgroup --shell /bin/false appuser

COPY --from=builder /install /usr/local
COPY --chown=appuser:appgroup . .

USER appuser
EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1

CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Go (minimal final image):

# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server .

# Stage 2: Production (scratch, smallest possible image)
FROM scratch AS runner
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD ["/server", "healthcheck"]

ENTRYPOINT ["/server"]

Next.js (standalone output):

FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 appuser

COPY --from=builder --chown=appuser:appgroup /app/.next/standalone ./
COPY --from=builder --chown=appuser:appgroup /app/.next/static ./.next/static
COPY --from=builder --chown=appuser:appgroup /app/public ./public

USER appuser
EXPOSE 3000

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

CMD ["node", "server.js"]

Step 3: Generate .dockerignore

# Dependencies
node_modules/
.pnp
.pnp.js

# Build output (built inside container)
dist/
build/
.next/
out/

# Environment files (secrets)
.env
.env.local
.env.*.local

# Version control
.git
.gitignore

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Docker (prevent recursive copy)
Dockerfile
docker-compose*.yml
.dockerignore

# Testing & development
coverage/
*.test.js
*.spec.js
__tests__/
.nyc_output/

# Documentation
README.md
CHANGELOG.md
docs/

# CI/CD
.github/
.gitlab-ci.yml

Step 4: Generate docker-compose.yml

Development compose (app + database + cache):

# docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: builder  # Use builder stage for dev (with dev dependencies)
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/app_dev
      - REDIS_URL=redis://redis:6379
    volumes:
      - .:/app
      - /app/node_modules  # Prevent overwriting container node_modules
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    ports:
      - '5432:5432'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app_dev
    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
    ports:
      - '6379:6379'
    volumes:
      - redis_data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 5s
      retries: 5
    command: redis-server --appendonly yes

volumes:
  postgres_data:
  redis_data:

Production compose:

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

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      target: runner  # Production stage
    ports:
      - '3000:3000'
    env_file:
      - .env.production
    depends_on:
      db:
        condition: service_healthy
    restart: always
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '1.0'
        reservations:
          memory: 256M
          cpus: '0.5'

  db:
    image: postgres:16-alpine
    env_file:
      - .env.production
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER}']
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always
    deploy:
      resources:
        limits:
          memory: 1G

volumes:
  postgres_data:
    driver: local

Step 5: Environment Variable Handling

── ENVIRONMENT STRATEGY ───────────────────

Development (.env, local only, gitignored):
  DATABASE_URL=postgresql://postgres:postgres@db:5432/app_dev
  REDIS_URL=redis://redis:6379
  API_KEY=dev_key_not_real
  NODE_ENV=development

Production (.env.production, on server, never in repo):
  DATABASE_URL=postgresql://user:STRONG_PASS@db:5432/app_prod
  REDIS_URL=redis://:STRONG_PASS@redis:6379
  API_KEY=prod_real_key
  NODE_ENV=production

Docker env var priority (highest to lowest):

  1. docker run -e VAR=value (command line)
  2. environment: in docker-compose.yml
  3. env_file: in docker-compose.yml
  4. ENV in Dockerfile (build-time defaults only)

Secrets handling:

  • Never put secrets in Dockerfile ENV (visible in image layers)
  • Use env_file for production (file on server, not in repo)
  • For CI/CD: inject via docker run -e from pipeline secrets
  • Consider Docker Secrets for Swarm/production deployments

Step 6: Health Check Configuration

Design health checks for each service:

── HEALTH CHECKS ──────────────────────────

App:
  Endpoint: GET /health
  Response: { "status": "ok", "db": "connected", "redis": "connected" }
  Interval: 30s
  Timeout: 3s
  Start period: 10s (allow app to boot)
  Retries: 3

PostgreSQL:
  Command: pg_isready -U postgres
  Interval: 10s
  Timeout: 5s
  Retries: 5

Redis:
  Command: redis-cli ping
  Interval: 10s
  Timeout: 5s
  Retries: 5

Application health endpoint implementation:

// GET /health
app.get('/health', async (req, res) => {
  const checks = {
    status: 'ok',
    uptime: process.uptime(),
    timestamp: new Date().toISOString(),
  };

  try {
    await db.query('SELECT 1');
    checks.db = 'connected';
  } catch {
    checks.db = 'disconnected';
    checks.status = 'degraded';
  }

  try {
    await redis.ping();
    checks.redis = 'connected';
  } catch {
    checks.redis = 'disconnected';
    checks.status = 'degraded';
  }

  const statusCode = checks.status === 'ok' ? 200 : 503;
  res.status(statusCode).json(checks);
});

Step 7: Image Optimization

Optimization techniques applied:

TechniqueImpactApplied In
Multi-stage build50-80% smaller imageSeparate build/run stages
Alpine base~5MB vs ~100MB basenode:20-alpine vs node:20
Non-root userSecurity hardeningUSER appuser in final stage
Layer cachingFaster rebuildsCopy package.json before source
.dockerignoreSmaller build contextExclude node_modules, .git, docs
Minimal final stageOnly runtime filesNo dev deps, no source in prod
Combined RUNFewer layersChain apt commands with &&

Image size comparison:

ApproachTypical SizeNotes
node:20 (no optimization)~1 GBFull Debian + dev tools
node:20-slim~200 MBSlim Debian
node:20-alpine (multi-stage)~80-150 MBAlpine + app only
Go with scratch~5-20 MBBinary only, no OS
Python slim (multi-stage)~100-200 MBSlim + deps only

Check image size:

docker images | grep app
# Or detailed layer analysis:
docker history app:latest

Step 8: Networking

Development networking:

# docker-compose.yml, services on same default network
# Access between services by service name:
# app β†’ db:5432, app β†’ redis:6379

Production networking:

# Explicit network for isolation
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

services:
  app:
    networks: [frontend, backend]  # Talks to proxy AND database
  db:
    networks: [backend]            # Only accessible from app
  redis:
    networks: [backend]            # Only accessible from app
  nginx:
    networks: [frontend]           # Only talks to app
    ports: ['80:80', '443:443']    # Exposed to internet

Port exposure rules:

  • Development: Expose DB/Redis ports for local tools (DBeaver, RedisInsight)
  • Production: Only expose HTTP/HTTPS through reverse proxy
  • Never expose database ports in production compose
  • Use 127.0.0.1:5432:5432 instead of 5432:5432 to restrict to localhost

Step 9: Volume Management

── VOLUMES ────────────────────────────────

Persistent data (named volumes):
  postgres_data    β†’ /var/lib/postgresql/data   (DB files)
  redis_data       β†’ /data                      (Redis AOF/RDB)
  uploads          β†’ /app/uploads               (User uploads)

Development bind mounts:
  .:/app           β†’ Live code reloading
  /app/node_modules β†’ Prevent host overwriting container deps

Backup volumes:
  docker run --rm -v postgres_data:/data -v $(pwd):/backup \
    alpine tar czf /backup/postgres_backup.tar.gz /data

Volume backup script:

#!/bin/bash
# Backup all named volumes
DATE=$(date +%F)
BACKUP_DIR="/opt/backups/docker"
mkdir -p "$BACKUP_DIR"

for VOLUME in $(docker volume ls -q); do
  docker run --rm \
    -v "$VOLUME":/source:ro \
    -v "$BACKUP_DIR":/backup \
    alpine tar czf "/backup/${VOLUME}_${DATE}.tar.gz" -C /source .
done

# Cleanup backups older than 14 days
find "$BACKUP_DIR" -type f -mtime +14 -delete

Step 10: Output

Present the complete Docker setup:

━━━ DOCKER SETUP ━━━━━━━━━━━━━━━━━━━━━━━━━
Project: [name]
Type: [language/framework]
Services: [app, db, redis, etc.]

── DOCKERFILE ─────────────────────────────
[complete multi-stage Dockerfile]
Final image size: ~[X] MB

── .DOCKERIGNORE ──────────────────────────
[complete .dockerignore]

── DOCKER-COMPOSE (Development) ───────────
[docker-compose.yml with dev services]
Start: docker compose up -d
Logs: docker compose logs -f app
Stop: docker compose down

── DOCKER-COMPOSE (Production) ────────────
[docker-compose.prod.yml]
Start: docker compose -f docker-compose.prod.yml up -d

── ENVIRONMENT ────────────────────────────
[env var strategy per environment]

── HEALTH CHECKS ──────────────────────────
[per-service health check config]

── NETWORKING ─────────────────────────────
[network topology for dev and prod]

── VOLUMES ────────────────────────────────
[persistent data + backup strategy]

── USEFUL COMMANDS ────────────────────────
Build:    docker compose build
Start:    docker compose up -d
Logs:     docker compose logs -f
Shell:    docker compose exec app sh
Rebuild:  docker compose up -d --build
Clean:    docker system prune -f

Inputs

  • Project type and language
  • Required services (database, cache, queue)
  • Development vs production needs
  • Deployment target
  • Existing Dockerfile (if any)

Outputs

  • Optimized multi-stage Dockerfile (Node.js, Python, Go, or Next.js)
  • .dockerignore with comprehensive exclusions
  • docker-compose.yml for development (app + services)
  • docker-compose.prod.yml for production (with resource limits)
  • Environment variable strategy per environment
  • Health check configuration for all services
  • Image optimization summary with size comparison
  • Network topology (dev: open, prod: isolated)
  • Volume management with backup script
  • Quick-reference command cheat sheet

Level History

  • Lv.1: Base: Multi-stage Dockerfiles (Node.js, Python, Go, Next.js), docker-compose for dev and prod, .dockerignore, environment variable strategy, health checks, image optimization (Alpine, layer caching, non-root user), network isolation, volume management with backups. (Origin: MemStack v3.2, Mar 2026)

Signals

GitHub stars
421
Forks
44
Last commit
Sep 2026

ahel review

  • S4info
    community integration β€” published by cwinvestments, not docker

Automated review, not a security audit. Ruleset v1.

Advanced
Catalog kind
skill
Gateway key
memstack-deployment-docker-setup
Source
github.com/cwinvestments/memstack