generated from ttipo/project-base
f60654bed6
운영 스택을 따로 띄워 확인하다 드러난 것들을 막는다. - 업로드 디렉터리가 root 소유로 생기면 사진 업로드가 전부 500 인데 헬스체크(/)는 healthy 였다 → 운영 헬스체크를 /api/health(DB) + 업로드 쓰기 권한으로, 이미지에 node 소유 디렉터리를 만들어 둔다 - 빌드 컨텍스트에 호스트(Windows) node_modules 와 backend/.env.* 가 들어가고 있었다 → .dockerignore - CI e2e 는 스위트마다 빈 DB 에 마이그레이션을 동시에 돌려 충돌하고 재연결 타이밍으로만 통과했다 → --runInBand - dev 헬스체크는 쿼리 로그가 쌓이지 않게 / 로 둔다 - 첫 배포 준비(env 두 파일·proxy 네트워크·업로드 디렉터리·백업·셸 APP_ENV 주의)를 docker 스킬에 적는다 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
1.5 KiB
Docker
44 lines
1.5 KiB
Docker
FROM node:20-alpine AS builder
|
|
WORKDIR /app
|
|
|
|
# 호스트의 npm 11 이 작성한 package-lock.json 형식과 호환되도록 npm 을 11 로 업그레이드
|
|
# (전역 설치는 root 권한이 필요하므로 USER 전환 전에 수행)
|
|
RUN npm install -g npm@11
|
|
|
|
# 개발 환경(docker-compose.dev.yml)은 이 스테이지를 그대로 구동하므로 비-root 로 전환한다.
|
|
# /app 소유권을 넘겨야 익명 볼륨(node_modules)도 node 소유로 생성되어 캐시 쓰기가 가능하다.
|
|
RUN chown node:node /app
|
|
USER node
|
|
|
|
# 재현 가능한 빌드를 위해 npm ci 사용 (lockfile 기반)
|
|
COPY --chown=node:node package*.json ./
|
|
RUN npm ci
|
|
|
|
COPY --chown=node:node . .
|
|
RUN npm run build
|
|
|
|
FROM node:20-alpine AS production
|
|
WORKDIR /app
|
|
|
|
ENV NODE_ENV=production
|
|
|
|
# 운영 stage 도 동일 npm 버전 사용
|
|
RUN npm install -g npm@11
|
|
|
|
# 운영용 의존성만 설치
|
|
COPY package*.json ./
|
|
RUN npm ci --omit=dev && npm cache clean --force
|
|
|
|
COPY --from=builder /app/dist ./dist
|
|
|
|
# 업로드 저장 위치(compose 의 UPLOAD_DIR) — node 가 쓸 수 있게 소유권을 넘겨 둔다.
|
|
# named volume 은 이 소유권을 이어받는다. 호스트 경로(bind mount)는 호스트 디렉터리 소유권을 따르므로
|
|
# 운영 서버에서 미리 uid 1000 소유로 만들어 둔다 (.env.production.example 의 UPLOAD_DATA_DIR 참조)
|
|
RUN mkdir -p /app/uploads && chown node:node /app/uploads
|
|
|
|
EXPOSE 3000
|
|
|
|
# 비-root 실행 (보안 규칙)
|
|
USER node
|
|
|
|
CMD ["node", "dist/main"] |