基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/puk0806/gugbab-claude --skill docker-deployment命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
DDD(Domain-Driven Design) 아키텍처 핵심 패턴 - 유비쿼터스 언어, 서브도메인, 바운디드 컨텍스트, Aggregate, Entity/VO, 도메인 서비스/이벤트, 레이어드 아키텍처
대규모 React/Next.js 프로젝트를 layer-first(types/·utils/·hooks/·api/·components/ 밑에 도메인이 반복되는 구조)에서 domain-first(feature/도메인 우선) 구조로 전환하는 설계 기준과 절차. Feature-Sliced Design 2.1 정본(layers 6종·slices·segments·import 규칙·@x 크로스임포트·public API), FSD를 쓰지 않는 경량 대안(features + shared 2~3계층 + ESLint import/no-restricted-paths), Next.js App Router 공존 전략(route group `()`·private folder `_`·colocation), Turborepo/Nx 모노레포에서 폴더↔패키지 승격 기준, colocation과 배럴 파일 성능 트레이드오프, 도메인 경계 역추출(import 그래프·change coupling·용어 클러스터), 전환 실패 패턴(shared 비대화·entities 남용·순환 의존·도메인=라우트 착각·조기 추상화). 도메인 개념 자체(바운디드 컨텍스트·유비쿼터스 언어)는 `architecture/ddd` 스킬을 참조한다.
소스 파일 수천 개 규모 프론트엔드 코드베이스를 멈추지 않고 점진 재구조화하는 실행 전략 - Strangler Fig / Branch by Abstraction / Parallel Change, ts-morph·jscodeshift codemod, PR 분할·검증 게이트·되돌리기, 테스트 없는 코드의 안전망, 작업 순서 설계와 위반 수 기반 진행 추적
| name | docker-deployment |
| description | Docker 컨테이너화 및 배포 패턴 - 멀티스테이지 빌드, 이미지 최적화, Compose, 보안, Vercel/Railway 배포 |
| disable-model-invocation | true |
소스: https://docs.docker.com/build/building/best-practices/ | https://docs.docker.com/build/building/multi-stage/ | https://docs.docker.com/guides/nodejs/containerize/ | https://docs.docker.com/guides/rust/build-images/ 검증일: 2026-04-20
주의: 이 문서는 Docker Engine v29.x, Docker Compose v5.x 기준으로 작성되었습니다. Docker Engine v25 미만은 EOL 상태이므로 반드시 업그레이드하세요.
멀티스테이지 빌드는 여러 FROM 문으로 빌드 환경과 런타임 환경을 분리한다. 최종 이미지에는 실행에 필요한 파일만 포함되어 크기와 공격 표면이 줄어든다.
# 스테이지에 이름을 붙여 가독성 확보
FROM golang:1.25 AS build
WORKDIR /src
COPY . .
RUN go build -o /bin/app ./main.go
# 최종 스테이지: 바이너리만 복사
FROM scratch
COPY --from=build /bin/app /bin/app
CMD ["/bin/app"]
FROM image AS name — 숫자 인덱스 대신 이름 사용COPY --from=build /path /path — 필요한 아티팩트만 복사COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.confdocker build --target build -t myapp .ARG NODE_VERSION=22-alpine
FROM node:${NODE_VERSION} AS base
WORKDIR /app
# 보안: non-root 사용자 생성
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 -G nodejs
# --- 의존성 설치 ---
FROM base AS deps
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev
# --- 빌드 ---
FROM base AS build
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
RUN npm run build
# --- 프로덕션 ---
FROM base AS production
ENV NODE_ENV=production
COPY --from=deps --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=build --chown=nodejs:nodejs /app/dist ./dist
COPY --from=deps --chown=nodejs:nodejs /app/package*.json ./
USER nodejs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD ["node", "-e", "require('http').get('http://localhost:3000/health', (r) => r.statusCode === 200 ? process.exit(0) : process.exit(1))"]
CMD ["node", "dist/server.js"]
Next.js의 output: "standalone" 모드를 활용하면 자체 포함 서버를 생성할 수 있다.
// next.config.ts
const nextConfig: NextConfig = {
output: "standalone",
};
ARG NODE_VERSION=22-alpine
FROM node:${NODE_VERSION} AS base
WORKDIR /app
# --- 의존성 ---
FROM base AS deps
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
# --- 빌드 ---
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# --- 프로덕션 ---
FROM base AS production
ENV NODE_ENV=production
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001 -G nodejs
# standalone 출력물 복사
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=build --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
Rust는 컴파일 언어이므로 빌드 스테이지에서 바이너리를 생성하고, 최종 스테이지에는 바이너리만 복사한다.
ARG RUST_VERSION=1.86
ARG APP_NAME=myapp
# --- 빌드 스테이지 ---
FROM rust:${RUST_VERSION}-alpine AS build
ARG APP_NAME
WORKDIR /app
# musl 빌드 의존성 설치
RUN apk add --no-cache clang lld musl-dev
# 의존성 캐시 마운트로 빌드 속도 향상
RUN --mount=type=bind,source=src,target=src \
--mount=type=bind,source=Cargo.toml,target=Cargo.toml \
--mount=type=bind,source=Cargo.lock,target=Cargo.lock \
--mount=type=cache,target=/app/target/ \
--mount=type=cache,target=/usr/local/cargo/git/db \
--mount=type=cache,target=/usr/local/cargo/registry/ \
cargo build --locked --release && \
cp ./target/release/$APP_NAME /bin/server
# --- 런타임 스테이지 ---
FROM alpine:3.21 AS runtime
# non-root 사용자
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY --from=build /bin/server /bin/server
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD ["wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/health"]
CMD ["/bin/server"]
| 마운트 대상 | 용도 |
|---|---|
/usr/local/cargo/registry/ | 다운로드된 크레이트 캐시 |
/usr/local/cargo/git/db | Git 의존성 캐시 |
/app/target/ | 컴파일된 의존성 캐시 |
주의: CI 환경에서는
--mount=type=cache가 유지되지 않는다. CI에서는cache-from/cache-to레지스트리 캐시 전략을 사용한다.
# compose.yaml
services:
app:
build:
context: .
target: development
ports:
- "3000:3000"
- "9229:9229" # 디버깅
volumes:
- .:/app # 소스 바인드 마운트 (핫 리로드)
- /app/node_modules # 익명 볼륨으로 보호
environment:
- NODE_ENV=development
depends_on:
db:
condition: service_healthy
db:
image: postgres:17-alpine
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev -d myapp"]
interval: 10s
timeout: 5s
retries:
# compose.production.yaml
services:
app:
build:
context: .
target: production
ports:
- "3000:3000"
restart: always
# 소스 볼륨 바인드 제거 — 코드는 이미지 내부에만 존재
volumes: []
environment:
- NODE_ENV=production
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
db:
restart: always
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
실행 방법:
# 개발
docker compose up
# 프로덕션 (오버라이드 합성)
docker compose -f compose.yaml -f compose.production.yaml up -d
# 프로덕션 서비스 업데이트 (의존 서비스 재시작 방지)
docker compose build app
docker compose up --no-deps -d app
node_modules
.git
.gitignore
*.md
.env*
.next
dist
target
Dockerfile*
compose*.yaml
.dockerignore
package.json / Cargo.toml + Cargo.lock을 소스 코드보다 먼저 COPY — 의존성이 변경되지 않으면 캐시 재사용# 권장: 하나의 RUN으로 합침
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
--mount=type=cache로 패키지 매니저 캐시 유지| 베이스 이미지 | 크기 | 적합한 경우 |
|---|---|---|
alpine | ~6MB | 최소 크기 필요 시 (musl libc 주의) |
node:22-alpine | ~50MB | Node.js 앱 |
rust:1.86-alpine | ~300MB | Rust 빌드 스테이지 |
scratch | 0MB | 정적 바이너리 (Go, Rust musl) |
debian:bookworm-slim | ~30MB | glibc 필요 시 |
FROM alpine:3.21@sha256:a8560b36e8...
주의: 다이제스트 고정은 자동 보안 패치를 받지 못하는 트레이드오프가 있다. Docker Scout으로 다이제스트를 최신 상태로 유지하는 것을 권장한다.
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --start-interval=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
| 옵션 | 기본값 | 설명 |
|---|---|---|
--interval | 30s | 검사 간격 |
--timeout | 30s | 타임아웃 |
--start-period | 0s | 컨테이너 시작 후 유예 기간 |
--start-interval | 5s | 시작 기간 중 검사 간격 |
--retries | 3 | unhealthy 판정까지 연속 실패 횟수 |
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 3s
start_period: 10s
retries: 3
| 코드 | 상태 |
|---|---|
| 0 | healthy |
| 1 | unhealthy |
주의: Dockerfile에 HEALTHCHECK가 여러 개 있으면 마지막 것만 적용된다. 스테이지당 하나만 정의한다.
상세 레퍼런스 (예제·고급 패턴·흔한 실수) →
references/REFERENCE.md