Communitygithub.com

docker-patterns

Docker 및 Docker Compose 패턴으로 로컬 개발, 강화된 CLI 설치 도구, 컨테이너 보안, 네트워킹, 볼륨, 다중 서비스 오케스트레이션을 다룹니다. Dockerfile 및 Compose 서비스를 만들거나 검토할 때, 여러 리눅스 배포판에서 설치 프로그램을 테스트할 때, 또는 정확한 네이티브 macOS 및 Windows 검증을 계획할 때 사용하세요.

docker-patterns란 무엇인가요?

이 스킬은 Docker와 Docker Compose를 사용한 컨테이너화된 개발을 위한 모범 사례를 제공합니다. 로컬 개발 환경 설정부터 프로덕션 배포까지 전 과정을 다루며, 멀티 스테이지 Dockerfile 구성, 오버라이드 파일을 통한 환경별 설정, 서비스 디스커버리 및 네트워크 격리, 볼륨 전략, 컨테이너 보안 강화, CLI 설치 도구 테스트를 위한 격리된 컨테이너 기반 검증 방법론을 포함합니다. 특히 강화된 CLI 설치 도구 테스트 부분에서는 실제 Linux 컨테이너를 사용한 배포판별 테스트, 읽기 전용 마운트, tmpfs 작업 공간, 비루트 실행, 네트워크 격리 등 엄격한 격리 계약을 적용하여 호스트 환경에 영향을 주지 않고 설치 프로그램의 동작을 검증하는 방법을 상세히 설명합니다. 네트워킹과 볼륨, 보안 설정에 대한 구체적인 Docker Compose 예제와 안티 패턴을 함께 제공하여 실무에서 바로 활용할 수 있습니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/docker-patterns

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Docker 패턴

컨테이너화된 개발을 위한 Docker 및 Docker Compose 모범 사례입니다.

로컬 개발용 Docker Compose

표준 웹 앱 스택

# docker-compose.yml
services:
  app:
    build:
      context: .
      target: dev                     # 멀티 스테이지 Dockerfile의 dev 스테이지 사용
    ports:
      - "3000:3000"
    volumes:
      - .:/app                        # 핫 리로드를 위한 바인드 마운트
      - /app/node_modules             # 익명 볼륨 -- 컨테이너 의존성 보존
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db:5432/app_dev
      - REDIS_URL=redis://redis:6379/0
      - NODE_ENV=development
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    command: npm run dev

  db:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app_dev
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

  mailpit:                            # 로컬 이메일 테스트
    image: axllent/mailpit
    ports:
      - "8025:8025"                   # 웹 UI
      - "1025:1025"                   # SMTP

volumes:
  pgdata:
  redisdata:

개발 vs 프로덕션 Dockerfile

# 스테이지: 의존성
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# 스테이지: dev (핫 리로드, 디버그 도구)
FROM node:22-alpine AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

# 스테이지: 빌드
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build && npm prune --production

# 스테이지: 프로덕션 (최소 이미지)
FROM node:22-alpine AS production
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001
USER appuser
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
COPY --from=build --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=build --chown=appuser:appgroup /app/package.json ./
ENV NODE_ENV=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]

오버라이드 파일

# docker-compose.override.yml (자동 로드, 개발 전용 설정)
services:
  app:
    environment:
      - DEBUG=app:*
      - LOG_LEVEL=debug
    ports:
      - "9229:9229"                   # Node.js 디버거

# docker-compose.prod.yml (프로덕션용 명시적 설정)
services:
  app:
    build:
      target: production
    restart: always
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
# 개발 (자동으로 오버라이드 로드)
docker compose up

# 프로덕션
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

네트워킹

서비스 디스커버리

동일한 Compose 네트워크의 서비스는 서비스 이름으로 확인됩니다:

# "app" 컨테이너에서:
postgres://postgres:postgres@db:5432/app_dev    # "db"가 db 컨테이너로 확인됨
redis://redis:6379/0                             # "redis"가 redis 컨테이너로 확인됨

사용자 정의 네트워크

services:
  frontend:
    networks:
      - frontend-net

  api:
    networks:
      - frontend-net
      - backend-net

  db:
    networks:
      - backend-net              # frontend가 아닌 api에서만 접근 가능

networks:
  frontend-net:
  backend-net:

필요한 것만 노출

services:
  db:
    ports:
      - "127.0.0.1:5432:5432"   # 호스트에서만 접근 가능, 네트워크에서는 불가
    # 프로덕션에서는 포트를 완전히 생략 -- Docker 네트워크 내에서만 접근 가능

볼륨 전략

volumes:
  # 명명된 볼륨: 컨테이너 재시작 후에도 유지, Docker가 관리
  pgdata:

  # 바인드 마운트: 호스트 디렉토리를 컨테이너에 매핑 (개발용)
  # - ./src:/app/src

  # 익명 볼륨: 바인드 마운트 오버라이드에서 컨테이너 생성 콘텐츠 보존
  # - /app/node_modules

일반적인 패턴

services:
  app:
    volumes:
      - .:/app                   # 소스 코드 (핫 리로드를 위한 바인드 마운트)
      - /app/node_modules        # 컨테이너의 node_modules를 호스트로부터 보호
      - /app/.next               # 빌드 캐시 보호

  db:
    volumes:
      - pgdata:/var/lib/postgresql/data          # 영구 데이터
      - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql  # 초기화 스크립트

컨테이너 보안

Dockerfile 강화

# 1. 특정 태그 사용 (:latest 사용 금지)
FROM node:22.12-alpine3.20

# 2. 비루트로 실행
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
USER app

# 3. 기능 제거 (compose에서)
# 4. 가능한 경우 읽기 전용 루트 파일시스템
# 5. 이미지 레이어에 비밀 정보 없음

Compose 보안

services:
  app:
    security_opt:
      - no-new-privileges:true
    read_only: true
    tmpfs:
      - /tmp
      - /app/.cache
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE          # 1024 미만 포트에 바인딩하는 경우에만

비밀 관리

# 좋음: 환경 변수 사용 (런타임에 주입)
services:
  app:
    env_file:
      - .env                     # .env를 git에 커밋하지 마세요
    environment:
      - API_KEY                  # 호스트 환경에서 상속

# 좋음: Docker 시크릿 (Swarm 모드)
secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  db:
    secrets:
      - db_password

# 나쁨: 이미지에 하드코딩
# ENV API_KEY=sk-proj-xxxxx      # 절대 이렇게 하지 마세요

강화된 CLI 설치 도구 테스트 환경

컨테이너를 사용하여 일회용 프로젝트 복사본에 대해 설치 프로그램 동작을 테스트하고, 테스트가 원본 체크아웃을 변경하지 못하게 합니다.

플랫폼 경계 존중

  • Debian 및 Ubuntu와 같은 Linux 배포판에는 실제 컨테이너를 실행합니다.
  • macOS는 Docker가 Linux 커널을 공유하므로 Docker 컨테이너로 실행할 수 없습니다. 동일한 셸 프리 테스트 진입점을 macOS에서 네이티브로 실행합니다.
  • Windows 컨테이너는 Windows Docker 엔진이 필요합니다. 플랫폼 독립적인 로직은 네이티브 Windows CI 러너에서 실행하고, Windows 컨테이너는 Windows 호스트용으로 예약합니다.
  • 호스트별 경로, 명령 shim, 따옴표, 파일 시스템 동작을 위해 네이티브 Ubuntu/macOS/Windows CI 매트릭스를 유지합니다.

Linux 컨테이너가 macOS 또는 Windows 동작을 검증한다고 주장하지 마세요.

격리 계약 시행

  • 불변 다이제스트로 기본 이미지를 고정하고 설치된 CLI 버전을 고정합니다.
  • 배포판 계정 이름이 다른 경우 비루트 숫자 UID/GID로 실행합니다.
  • 저장소와 소스 프로젝트를 읽기 전용으로 마운트합니다.
  • 변형 전에 소스 프로젝트를 쓰기 가능한 tmpfs 작업 공간으로 복사합니다.
  • /workspace를 noexec, UID/GID 1000, mode=0700으로 마운트하여 컨테이너 사용자만 프로젝트 데이터를 검사할 수 있도록 합니다.
  • npm 및 npx의 실행 파일 캐시를 NPM_CONFIG_CACHE=/tmp/npm-cache로 실행 가능한 /tmp 마운트에 유지합니다. 기본 크기는 2GiB이며 ECC_TMPFS_SIZE로 조정할 수 있습니다. ECC_WORKSPACE_SIZE는 개인 작업 공간 마운트를 별도로 제어합니다.
  • read_only: true, no-new-privileges:true, cap_drop: [ALL], 유한한 pids_limit을 설정합니다.
  • 기본 실제 CLI 서비스를 network_mode: none으로 유지합니다. 인증된 공급자 세션을 위해 명시적으로 이름이 지정된 옵트인 서비스를 통해서만 네트워크 액세스를 추가하고, 우발적인 환경 기반 기본값이 되지 않도록 합니다.
  • 도구가 필요한 쓰기 가능한 임시 경로만 생성합니다.
  • 기본적으로 호스트 자격 증명을 컨테이너에 전달하지 않습니다.
  • 기본적으로 dry run을 수행하고 dry-run, install, plugin, shell 모드만 명시적으로 허용합니다.
  • 크로스 플랫폼 러너에는 인수 배열 또는 spawnSync(..., { shell: false })를 사용합니다. 프로젝트 경로를 셸 명령에 절대 보간하지 마세요.

ECC 플러그인 설정 테스트 환경 실행

참조 구현으로 docker/plugin-setup/compose.yaml을 사용합니다. 다음을 제공합니다:

  • fixture-tests: 집중된 설치 매니페스트, 대상 및 실행기 제품군용.
  • real-cli: 고정된 Debian 기반 일반 Linux 이미지용.
  • real-cli-ubuntu: 고정된 Ubuntu 이미지용.

빌드 전에 Compose 모델을 검증합니다:

docker compose -f docker/plugin-setup/compose.yaml config --quiet

두 실제 Linux 이미지를 빌드합니다:

docker compose -f docker/plugin-setup/compose.yaml \
  build real-cli real-cli-ubuntu

각 이미지에서 안전한 기본 흐름을 실행합니다:

docker compose -p ecc-plugin-debian-test \
  -f docker/plugin-setup/compose.yaml \
  run --rm -T real-cli dry-run

docker compose -p ecc-plugin-ubuntu-test \
  -f docker/plugin-setup/compose.yaml \
  run --rm -T real-cli-ubuntu dry-run

dry run은 현재 공개 명령 계약을 실행합니다:

ecc install --profile core --target claude-project --dry-run --json

해당 명령이 실행되기 전에 컨테이너는 npm pack --ignore-scripts를 사용하여 읽기 전용 체크아웃에서 로컬로 패키지된 npm 아티팩트를 생성합니다. /tmp 아래에서 자체 생성된 tarball을 추출하고, ecc-universal 패키지 이름, 필수 설치 매니페스트, 제한된 package.json bin.ecc 매핑을 검증한 다음, 추출된 ecc 실행 파일을 호출합니다. 런타임은 network_mode: none을 유지하고, 패키지 라이프사이클 스크립트를 실행하지 않으며, 호스트 node_modules에 의존하지 않습니다. 정확한 고정 프로덕션 의존성은 이미 이미지에 있습니다.

테스트 환경은 빈 계획, claude-project가 아닌 대상, /workspace/project/.claude 외부의 모든 작업, 또는 대상 디렉토리를 생성하는 dry run을 거부합니다. install은 격리된 적용을 두 번 수행하고, 관리되는 설치 상태를 확인하고, 설치된 대상을 나열하고, doctor를 실행합니다.

명명된 세션 시작, 열기, 재연결 및 정리

--rm 없이 분리된 컨테이너를 시작하여 터미널을 떠나도 세션이 제거되지 않도록 합니다:

docker compose -p ecc-plugin-session \
  -f docker/plugin-setup/compose.yaml \
  run --detach --name ecc-plugin-shell real-cli shell

컨테이너는 읽기 전용 fixture를 안정적인 개인 디렉토리 /workspace/project로 복사합니다. 실행 중인지 확인한 다음 터미널 오프너 v1 데이터 계약의 Docker 측을 출력합니다:

docker inspect --format '{{.State.Running}}' ecc-plugin-shell
node docker/plugin-setup/interactive-plan.js \
  --container ecc-plugin-shell \
  --workdir /workspace/project \
  --json \
  -- bash

JSON 결과에는 정확히 executable과 argv 경계( contractVersion: 1 포함)가 있습니다: 실행 파일은 docker이고, argv는 exec, -it, -w로 시작합니다. 별도의 터미널 오프너 스킬이 설치되면 해당 데이터를 전달합니다. 이 Docker 테스트 환경은 의도적으로 터미널 어댑터를 가져오거나, 셸 명령을 보간하거나, 호스트 GUI 프로세스를 관리하지 않습니다. 그때까지는 현재 호스트 터미널에서 동일한 PTY를 직접 엽니다:

docker exec -it -w /workspace/project ecc-plugin-shell bash

분리된 컨테이너를 중지하지 않고 셸을 종료합니다. 동일한 docker exec -it 명령으로 다시 연결합니다. 완료되면 정확히 명명된 컨테이너와 Compose 프로젝트 리소스를 제거합니다:

docker rm --force ecc-plugin-shell
docker compose -p ecc-plugin-session \
  -f docker/plugin-setup/compose.yaml \
  down --remove-orphans

호스트 자격 증명은 기본적으로 없으며 자격 증명 디렉토리는 절대 마운트되지 않습니다. 기본 서비스에는 네트워크 액세스도 없습니다. 인증된 공급자 세션에 실제로 네트워크가 필요한 경우 먼저 real-cli를 빌드한 다음 docker compose --profile networked run real-cli-networked shell로 명시적으로 옵트인합니다. 해당 일회성 세션 내에서 인증하는 것을 선호합니다. CI 실행이 호스트 환경 자격 증명을 상속해야 하는 경우 호출 시 명시적인 Compose --env NAME 플래그로 옵트인하고, 값이 검사 가능하며 컨테이너 수명 동안 유출될 수 있음을 이해하고, 정확히 명명된 컨테이너를 즉시 제거합니다.

호스트에서 동일한 집중 제품군을 네이티브로 실행합니다:

npm run test:plugin-setup-platform

이미지를 신뢰하기 전에 생성된 ID와 환경을 검사합니다:

docker image inspect ecc-plugin-setup:debian ecc-plugin-setup:ubuntu

관련 없는 볼륨이나 이미지를 삭제하지 않고 각 명명된 테스트 프로젝트를 정리합니다:

docker compose -p ecc-plugin-debian-test \
  -f docker/plugin-setup/compose.yaml down --remove-orphans
docker compose -p ecc-plugin-ubuntu-test \
  -f docker/plugin-setup/compose.yaml down --remove-orphans

.dockerignore

node_modules
.git
.env
.env.*
dist
coverage
*.log
.next
.cache
docker-compose*.yml
Dockerfile*
README.md
tests/

디버깅

일반적인 명령어

# 로그 보기
docker compose logs -f app           # 앱 로그 팔로우
docker compose logs --tail=50 db     # db에서 마지막 50줄

# 실행 중인 컨테이너에서 명령 실행
docker compose exec app sh           # 앱 셸 진입
docker compose exec db psql -U postgres  # postgres 연결

# 검사
docker compose ps                     # 실행 중인 서비스
docker compose top                    # 각 컨테이너의 프로세스
docker stats                          # 리소스 사용량

# 재빌드
docker compose up --build             # 이미지 재빌드
docker compose build --no-cache app   # 전체 재빌드 강제

# 정리
docker compose down                   # 컨테이너 중지 및 제거
docker compose down -v                # 볼륨도 제거 (파괴적)
docker system prune                   # 사용하지 않는 이미지/컨테이너 제거

네트워크 문제 디버깅

# 컨테이너 내부의 DNS 확인 확인
docker compose exec app nslookup db

# 연결 확인
docker compose exec app wget -qO- http://api:3000/health

# 네트워크 검사
docker network ls
docker network inspect <project>_default

안티 패턴

# 나쁨: 최신 태그 사용 (`:latest`는 예측 불가능)
image: node:latest

# 나쁨: 루트로 실행
USER root

# 나쁨: 비밀번호 하드코딩
ENV DB_PASSWORD=supersecret

# 나쁨: healthcheck 없음
# 컨테이너가 준비되었는지 알 수 없음

# 나쁨: 모든 포트를 0.0.0.0에 노출
ports:
  - "5432:5432"  # 네트워크의 모든 사람이 접근 가능

# 나쁨: depends_on을 조건 없이 사용
depends_on:
  - db
# db가 준비되기 전에 앱이 시작될 수 있음

# 나쁨: 재시작 정책 없음
# 컨테이너가 중단되면 다시 시작되지 않음

# 나쁨: 이미지 크기 최적화 없음
# 불필요한 패키지, 소스 맵, 캐시를 프로덕션 이미지에 포함

모범 사례 요약

  1. 특정 이미지 태그 사용: never :latest, always pin to a specific version.
  2. 멀티 스테이지 빌드: 개발 도구를 프로덕션 이미지에서 분리.
  3. 비루트 실행: USER 지시문으로 컨테이너 사용자 생성.
  4. healthcheck 정의: depends_on.condition: service_healthy와 함께 사용.
  5. 최소한의 포트 노출: 127.0.0.1:을 사용하여 로컬 호스트로 제한.
  6. 환경 변수 사용: 이미지 레이어에 시크릿을 하드코딩하지 마세요.
  7. .dockerignore 사용: 불필요한 파일을 빌드 컨텍스트에서 제외.
  8. 리소스 제한 설정: cpu, memory, pids_limit을 정의.
  9. 읽기 전용 파일시스템: 가능한 경우 read_only: true.
  10. 재현 가능한 빌드: package-lock.json 또는 이에 상응하는 파일 커밋.

추가 자료

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

관련 스킬