Series 11 · Docker · 2/3
DOCKER
FILE
BUILD
Dockerfile 작성법 · 멀티스테이지 빌드 · Spring Boot · React + Nginx
나만의 이미지를 만드는 레시피 파일
11a 개념·핵심 요소
11b Dockerfile 작성
11c docker-compose·실행
이 파일의 학습 목적
11b — Dockerfile 작성 · 멀티스테이지 빌드 · React + Nginx
Dockerfile은 내 앱을 Docker 이미지로 만드는 레시피 파일이다. 빌드 환경(~800MB)과 실행 환경(~200MB)을 분리하는 멀티스테이지 빌드로 최종 이미지 크기를 대폭 줄이고, React는 Nginx로 서빙하며 /api/ 프록시도 설정한다.
이 파일에서 배울 것
- ① Dockerfile 명령어 — FROM COPY RUN ENTRYPOINT
- ② Spring Boot Dockerfile — 멀티스테이지 빌드
- ③ React Dockerfile — node:18-alpine → nginx:alpine
- ④ nginx.conf — React Router + /api/ 프록시
- ⑤ application.properties — 환경변수 주입 패턴
프로젝트 코드 연결
- ·
board/Dockerfile — gradle:8.5-jdk21 → openjdk:21-slim
- ·
board-frontend/Dockerfile — node → nginx
- ·
nginx.conf — proxy_pass http://springboot:8080
- ·
${SPRING_DATASOURCE_URL:기본값} 패턴
시리즈 순서:
11a Docker 개념 →
11b ← 지금 여기
→ 11c docker-compose·실행
01 — Dockerfile이란?
나만의 Docker 이미지를 만드는 레시피 파일
📋
Dockerfile = 이미지 생성 레시피
Dockerfile
🍳 비유 — 요리 레시피
레시피(Dockerfile) → 요리 과정(빌드) → 완성된 요리(이미지)
"Java 설치 → 내 jar 파일 복사 → 실행" 과정을 자동화
→ docker build 명령어로 Dockerfile을 읽어 이미지 생성
Dockerfile — 주요 명령어
FROM
WORKDIR
COPY
RUN
EXPOSE
ENTRYPOINT
CMD
ENV
ARG
02 — Spring Boot Dockerfile
멀티스테이지 빌드 — 빌드(~800MB) → 실행(~200MB) 이미지 분리
☕
파일 위치
board/
├── src/
├── build.gradle
├── gradlew
└── Dockerfile ← 여기에 생성
1단계 — 빌드
gradle:8.5-jdk21
내 코드 복사
gradle build 실행
→ jar 파일 생성
~800MB (빌드 도구 포함)
→
2단계 — 실행
openjdk:21-slim
jar 파일만 복사
java -jar 실행
~200MB (실행에 필요한 것만)
Dockerfile — board/Dockerfile 완전 해설
FROM gradle:8.5-jdk21 AS build
WORKDIR /app
COPY . .
RUN gradle build -x test --no-daemon
FROM openjdk:21-slim
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
💡 멀티스테이지 빌드를 쓰는 이유
1단계 gradle:8.5-jdk21 = Gradle + Java 21 → 이미지 크기 약 800MB
2단계 openjdk:21-slim = Java 21만 → 이미지 크기 약 200MB
→ 빌드는 1단계에서, 실행은 2단계에서 → 최종 이미지 크기 75% 감소!
03 — React Dockerfile + Nginx
npm 빌드 → Nginx로 정적 파일 서빙 + /api/ 프록시
⚛️
파일 위치
board-frontend/
├── src/
├── public/
├── package.json
├── Dockerfile ← 여기에 생성
└── nginx.conf ← 여기에 생성
Dockerfile — board-frontend/Dockerfile 완전 해설
FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf — board-frontend/nginx.conf 완전 해설
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://springboot:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
💡 Nginx를 쓰는 이유 2가지
1. 성능: npm start는 개발 전용 서버 → 실제 배포엔 Nginx가 훨씬 빠르고 안정적
2. CORS 해결: /api/ 요청을 Nginx가 Spring Boot로 중계(프록시) → 브라우저는 같은 서버(Nginx)에 요청 → CORS 문제 없음
JavaScript — Docker 환경용 api.js 수정
const api = axios.create({
baseURL: 'http://localhost:8080',
});
const api = axios.create({
baseURL: '',
});
04 — application.properties 수정
환경변수로 설정 주입 — 로컬 IntelliJ와 Docker 환경 모두 대응
⚙️
로컬 / Docker 환경 통합 설정
properties — application.properties 수정
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:mariadb://localhost:3306/boarddb}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME:root}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD:1234}
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
jwt.secret=${JWT_SECRET:mySecretKeyForJWTTokenGenerationAndValidation2024}
jwt.expiration=86400000
admin.code=${ADMIN_CODE:ADMIN2024}
📌 핵심 — 하나의 파일로 로컬/Docker 모두 대응
로컬 IntelliJ 실행 → 기본값(localhost:3306) 사용 → 기존 방식 유지
Docker 실행 → docker-compose.yml의 environment 값이 주입 → mariadb:3306 접속