docker-patterns
로컬 개발, 컨테이너 보안, 네트워킹, 볼륨 전략, 멀티 서비스 오케스트레이션을 위한 Docker 및 Docker Compose 패턴.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
로컬 개발, 컨테이너 보안, 네트워킹, 볼륨 전략, 멀티 서비스 오케스트레이션을 위한 Docker 및 Docker Compose 패턴.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
새 Spring Boot 서비스를 api-gateway + auth-api 에코시스템에 연결한다. auth-api 클라이언트 등록 → Gateway 라우팅 추가 → 서비스에 econo-passport 연동 → 동작 확인까지 한 번에 처리. 다음 상황에서 반드시 이 스킬을 사용한다: - "새 서비스 Gateway에 연결해줘", "새 서비스 auth 연동" - "서비스 등록해줘", "Gateway 뒤에 붙여줘" - "/register-service" 직접 호출 - 새 Spring Boot 서비스가 추가되고 인증이 필요할 때 ARGUMENTS: 서비스명, 서비스 경로(선택), 업스트림 URL(선택) 예: "EEOS-BE /Users/mando/study/eeos/EEOS-BE/eeos"
이 스킬은 사용자가 "PR 생성해줘", "PR 만들어줘", "pull request 생성", "pr 올려줘", "/git-pr" 등을 요청할 때 호출된다. 현재 브랜치의 커밋을 원격으로 push하고, `.github/PULL_REQUEST_TEMPLATE.md`를 채워 GitHub Pull Request를 생성한다.
신규 기능을 개발할 때 정책 문서 → 코드 → 테스트 순서로 작성한다. ADR은 기술적 결정에만 사용하고, 기능 정책은 docs/features/ 에 작성한다. 다음 상황에서 반드시 이 스킬을 사용한다: - "기능 추가해줘", "기획부터 해봐", "설계해봐" - 새로운 API 엔드포인트 또는 도메인 규칙이 생길 때 - "/new-feature" 직접 호출 ARGUMENTS: 기능 이름 또는 요구사항 (없으면 대화에서 추출)
Architecture Decision Record(ADR)를 작성한다. 기술적 결정사항, 설계 선택, 트레이드오프를 문서화하여 나중에 "왜 이렇게 했지?"를 알 수 있게 한다. 다음 상황에서 반드시 이 스킬을 사용한다: - "ADR 써줘", "결정사항 문서화해줘", "이 결정 기록해줘" - 기술 방향 선택 후 ("A 대신 B 쓰기로 했어") - 설계 논의가 끝났을 때 - 나중에 이 결정이 왜 내려졌는지 설명이 필요할 것 같을 때 - "/adr" 직접 호출 ARGUMENTS: 결정 내용 또는 결정 번호 (없으면 대화에서 추출)
AI 에이전트의 액션 스페이스, 도구 정의, 관측(Observation) 포맷을 설계·최적화해 작업 완수율을 높일 때 사용한다.
브랜치 전략, 커밋 컨벤션, 머지 vs 리베이스, 충돌 해결, 협업 개발 모범 사례를 포함하는 Git 워크플로 패턴. 모든 규모의 팀에 적용 가능하다.
Based on SOC occupation classification
| name | docker-patterns |
| description | 로컬 개발, 컨테이너 보안, 네트워킹, 볼륨 전략, 멀티 서비스 오케스트레이션을 위한 Docker 및 Docker Compose 패턴. |
| origin | ECC |
컨테이너 기반 개발을 위한 Docker 및 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:
# 스테이지: 의존성 설치
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
# 개발 (override 자동 로드)
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 # api에서만 접근 가능, frontend에서는 불가
networks:
frontend-net:
backend-net:
services:
db:
ports:
- "127.0.0.1:5432:5432" # 호스트에서만 접근 가능, 외부 네트워크에서는 불가
# 운영에서는 ports를 아예 생략 -- Docker 네트워크 내부에서만 접근 가능
volumes:
# 명명 볼륨(named volume): 컨테이너 재시작 간 영속, 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 # 초기화 스크립트
# 1. 명시적 태그 사용 (절대 :latest 금지)
FROM node:22.12-alpine3.20
# 2. non-root로 실행
RUN addgroup -g 1001 -S app && adduser -S app -u 1001
USER app
# 3. capability 제거 (compose에서)
# 4. 가능하면 read-only 루트 파일시스템
# 5. 이미지 레이어에 시크릿 포함 금지
services:
app:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /app/.cache
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # 1024 미만 포트 바인딩이 필요할 때만
# GOOD: 환경 변수 사용 (런타임에 주입)
services:
app:
env_file:
- .env # .env 파일은 절대 git에 커밋하지 않는다
environment:
- API_KEY # 호스트 환경에서 상속
# GOOD: Docker secrets (Swarm 모드)
secrets:
db_password:
file: ./secrets/db_password.txt
services:
db:
secrets:
- db_password
# BAD: 이미지에 하드코딩
# ENV API_KEY=sk-proj-xxxxx # 절대 금지
node_modules
.git
.env
.env.*
dist
coverage
*.log
.next
.cache
docker-compose*.yml
Dockerfile*
README.md
tests/
# 로그 보기
docker compose logs -f app # app 로그 follow
docker compose logs --tail=50 db # db의 마지막 50줄
# 실행 중인 컨테이너에서 명령 실행
docker compose exec app sh # app 셸 접속
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
# BAD: 오케스트레이션 없이 운영에서 docker compose 사용
# 운영용 멀티 컨테이너 워크로드는 Kubernetes, ECS, Docker Swarm을 사용한다
# BAD: 볼륨 없이 컨테이너 안에 데이터 저장
# 컨테이너는 휘발성 -- 볼륨이 없으면 재시작 시 모든 데이터 손실
# BAD: root로 실행
# 항상 non-root 사용자를 만들고 사용한다
# BAD: :latest 태그 사용
# 재현 가능한 빌드를 위해 명시적 버전을 고정한다
# BAD: 모든 서비스를 하나의 거대한 컨테이너에
# 관심사를 분리한다: 컨테이너 하나당 프로세스 하나
# BAD: docker-compose.yml에 시크릿 저장
# .env 파일(gitignore)이나 Docker secrets를 사용한다