generated from ttipo/project-base
238d0ba838
웹메일 1단계를 개발 환경에서 띄우고 운영에 올리기 위한 인프라 구성이다. - 메일 엔진 Stalwart(v0.16.27)와 개발용 Mailpit 을 compose profile `mail` 로 추가한다. 초기 설정은 mail/scripts/setup.mjs 가 맡는다 — 여러 번 실행해도 안전하고, 운영에서는 사전 검사가 실패하면 아무것도 바꾸지 않고 멈춘다 - 화면과 API 를 한 주소로 배포한다: 프론트 nginx 가 /api 를 백엔드로 넘기고, 본문 한도·시간 제한·헤더 전달을 env 와 맞춘다. nginx 가 직접 내는 오류도 표준 실패 형식이다 - 인터넷을 향한 nginx 는 edge 네트워크로 백엔드에만 닿고, DB·메일 엔진은 app-network 에 둔다 (메일 엔진의 신뢰 대역도 app-network 뿐) - Node 24.22.1·npm 11.6.2·nginx 1.30.6 을 Dockerfile 과 CI 에 한 값으로 고정한다 - 개발 호스트 포트는 127.0.0.1 로 한정하고, data/ 는 클론 때부터 사용자 소유가 되게 .gitkeep 을 추적한다 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
60 lines
3.3 KiB
Docker
60 lines
3.3 KiB
Docker
# lock(package-lock.json)을 쓰고 검사하는 npm 은 한 버전으로 고정한다.
|
|
# npm 은 버전마다 lock 의 중첩 항목을 다르게 정리해서, 섞어 쓰면 lock 이 매번 바뀐다.
|
|
# 바꿀 때는 backend/Dockerfile · .github/workflows/ci.yml 의 NPM_VERSION · docker 스킬 문서를 함께 고친다.
|
|
ARG NPM_VERSION=11.6.2
|
|
|
|
# 빌드는 Node 24 LTS — 패치까지 고정한다 (backend/Dockerfile · ci.yml 의 NODE_VERSION 과 같은 값).
|
|
# 갱신 규칙과 함께 고치는 곳은 docker 스킬 문서 "Node 버전" 참조.
|
|
ARG NODE_VERSION=24.22.1
|
|
|
|
FROM node:${NODE_VERSION}-alpine3.24 AS build-stage
|
|
ARG NPM_VERSION
|
|
WORKDIR /app
|
|
|
|
# 전역 설치는 root 권한이 필요하므로 USER 전환 전에 수행
|
|
RUN npm install -g npm@${NPM_VERSION}
|
|
|
|
# 개발 환경(docker-compose.dev.yml)은 이 스테이지에서 vite dev 서버를 구동하므로 비-root 로 전환한다.
|
|
# /app 소유권을 넘겨야 익명 볼륨(node_modules)이 node 소유로 생성되어 vite 캐시(.vite) 쓰기가 가능하다.
|
|
RUN chown node:node /app
|
|
USER node
|
|
|
|
COPY --chown=node:node package*.json ./
|
|
RUN npm ci
|
|
|
|
COPY --chown=node:node . .
|
|
|
|
ARG BUILD_MODE=production
|
|
# 같은 주소 배포 — 브라우저는 화면과 같은 주소의 /api 를 부르고 nginx 가 백엔드로 넘긴다 (compose 도 /api 를 준다)
|
|
ARG VITE_API_BASE_URL=/api
|
|
ENV VITE_API_BASE_URL=$VITE_API_BASE_URL
|
|
|
|
RUN npm run build-only -- --mode ${BUILD_MODE}
|
|
|
|
# 비-root 전용 nginx 이미지 (보안 규칙: 컨테이너 root 실행 금지)
|
|
# 1024 미만 포트는 바인드할 수 없으므로 8080 을 사용한다 — nginx.conf 의 listen 과 일치해야 한다.
|
|
# 버전까지 고정한다 — nginx.conf 가 add_header_inherit(1.29.3 이상)를 쓰므로, 떠 있는 태그(stable-alpine)의
|
|
# 옛 이미지가 남은 호스트에서는 기동에 실패한다. 갱신 규칙·함께 고치는 곳은 docker 스킬 문서 "이미지 버전 고정".
|
|
#
|
|
# nginx 설정만 담은 단계 — 화면 빌드와 떼어 두어, CI 가 vite 빌드 없이 설정을 검사할 수 있다
|
|
# (docker build --target nginx-config frontend → nginx -t). 운영 이미지는 이 단계 위에 화면만 얹는다.
|
|
FROM nginxinc/nginx-unprivileged:1.30.6-alpine3.24 AS nginx-config
|
|
|
|
# nginx.conf 는 템플릿이다 — 컨테이너가 뜰 때 entrypoint 가 ${NGINX_*} 만 채워 /etc/nginx/conf.d/default.conf 를 만든다.
|
|
# NGINX_ENVSUBST_FILTER : NGINX_ 로 시작하는 변수만 바꾼다 (nginx 의 $uri·$request_id 등을 건드리지 않게)
|
|
# NGINX_ENTRYPOINT_LOCAL_RESOLVERS : /etc/resolv.conf 의 DNS(도커 내장 127.0.0.11)를 NGINX_LOCAL_RESOLVERS 로 내보낸다
|
|
ENV NGINX_ENVSUBST_FILTER=^NGINX_ \
|
|
NGINX_ENTRYPOINT_LOCAL_RESOLVERS=1
|
|
COPY nginx.conf /etc/nginx/templates/default.conf.template
|
|
# 템플릿 값 계산 (루트 env 의 첨부·업로드 한도 → nginx 본문 한도). 실행 권한이 있어야 entrypoint 가 source 한다
|
|
COPY --chmod=755 nginx-env.envsh /docker-entrypoint.d/16-nginx-env.envsh
|
|
|
|
# 운영 이미지 — compose 는 target 없이 빌드하므로 이 단계가 파일의 마지막이어야 한다
|
|
FROM nginx-config AS production-stage
|
|
COPY --from=build-stage /app/dist /usr/share/nginx/html
|
|
|
|
# 이미지 기본 사용자(nginx, uid 101)로 구동 — root 로 되돌리지 말 것
|
|
USER nginx
|
|
|
|
EXPOSE 8080
|
|
CMD ["nginx", "-g", "daemon off;"] |