본문으로 건너뛰기

Build Wizard

Dockerfile을 작성해본 적이 없으신가요? 걱정하지 마세요! Build Wizard가 프로젝트를 분석해서 최적화된 Dockerfile을 자동으로 생성해 드립니다. 몇 번의 클릭만으로 컨테이너 빌드 준비를 완료할 수 있습니다.

Build Wizard의 장점
  • 자동 감지: 프로젝트 언어, 프레임워크, 패키지 매니저를 자동으로 파악합니다.
  • 최적화된 템플릿: 멀티스테이지 빌드, Non-root 사용자 등 베스트 프랙티스가 적용됩니다.
  • 모노레포 지원: 여러 서비스가 있는 프로젝트도 한 번에 처리합니다.
  • 즉시 사용 가능: 생성된 Dockerfile이 GitLab에 자동 커밋되어 바로 빌드할 수 있습니다.

빌드 환경 생성

언제 사용하나요?

  • 신규 프로젝트: Dockerfile 없이 시작한 프로젝트를 컨테이너화할 때 사용합니다.
  • 레거시 마이그레이션: 기존 프로젝트를 Docker 기반으로 전환할 때 사용합니다.
  • 모노레포 구성: 여러 서비스를 한 번에 컨테이너화할 때 사용합니다.
  • 빠른 프로토타이핑: 최적화된 템플릿으로 빠르게 빌드 환경을 구성할 때 사용합니다.
Dockerfile이 이미 있다면?

Dockerfile이 이미 있는 프로젝트는 Build Wizard를 거치지 않고 바로 빌드가 시작됩니다. 기존 Dockerfile을 교체하고 싶다면 Build Wizard에서 새로 생성할 수 있습니다.


지원 프레임워크

Node.js

  • Next.js (SSR, 포트 3000): React 풀스택 프레임워크 (App Router/Pages Router)
  • React (SPA, 포트 80): React SPA (CRA, Vite 포함)
  • Vue.js (SPA, 포트 80): Vue 2/3 애플리케이션
  • Angular (SPA, 포트 80): Angular CLI 프로젝트
  • NestJS (API, 포트 3000): TypeScript 백엔드 프레임워크
  • Express.js (API, 포트 3000): Node.js 웹 프레임워크

Python

  • FastAPI (API, 포트 8000): 고성능 비동기 API 프레임워크
  • Django (API, 포트 8000): Python 풀스택 프레임워크
  • Flask (API, 포트 5000): 경량 마이크로 프레임워크
  • Streamlit (SSR, 포트 8501): 데이터 앱/대시보드 프레임워크

Java

  • Spring Boot (API, 포트 8080): Java 엔터프라이즈 프레임워크
  • Quarkus (API, 포트 8080): 클라우드 네이티브 Java

기타 언어

  • Go (Compiled, 포트 8080): 패키지 매니저 go mod
  • Rust (Compiled, 포트 8080): 패키지 매니저 cargo
  • .NET/C# (Compiled, 포트 8080): 패키지 매니저 dotnet
  • Ruby (API, 포트 3000): 패키지 매니저 bundler
  • PHP (API, 포트 80): 패키지 매니저 composer
  • 정적 사이트 (Static, 포트 80): 별도 패키지 매니저 없음

빌드 타입 이해하기

Build Wizard는 프레임워크에 따라 적절한 빌드 타입을 자동으로 선택합니다.

  • SPA: 정적 사이트(Single Page Application)입니다. 최종 이미지는 Nginx + 빌드된 정적 파일로 구성됩니다.
  • SSR: 서버 사이드 렌더링입니다. 최종 이미지는 Node.js 런타임 + 애플리케이션으로 구성됩니다.
  • API: 백엔드 API 서버입니다. 최종 이미지는 런타임 + 애플리케이션 코드로 구성됩니다.
  • Compiled: 컴파일 언어(Go, Rust 등)입니다. 최종 이미지는 바이너리만 포함 (경량 이미지)됩니다.
  • Static: 순수 정적 파일입니다. 최종 이미지는 Nginx + HTML/CSS/JS로 구성됩니다.
빌드 타입이 중요한 이유

빌드 타입에 따라 Dockerfile 구조, 베이스 이미지, 실행 명령이 달라집니다. 예를 들어 SPA는 빌드 후 Nginx로 서빙하지만, SSR은 Node.js 서버가 직접 요청을 처리합니다.


Build Wizard 진행 흐름

Step 0: 프로젝트 분석 → Step 1: 빌드 설정 → Step 2: 파일 미리보기 → Step 3: GitLab 커밋
flowchart LR
A[Build Wizard 열기] --> B[프로젝트 타입 감지]
B --> C{모노레포?}
C -->|Yes| D[서비스 선택]
C -->|No| E[단일 설정]
D --> F[템플릿 생성]
E --> F
F --> G[파일 편집]
G --> H[GitLab 커밋]
H --> I[빌드 실행 가능]

Step 0: Build Wizard 열기

열기 방법

  1. [서비스 관리] 페이지로 이동합니다.
  2. 설정할 서비스 행에서 Build 단계를 클릭합니다.
  3. Build Wizard 모달이 자동으로 열립니다.

자동 열림 조건

  • Dockerfile 없음: Build Wizard 자동 열림
  • Dockerfile 있음: 빌드 바로 시작
  • docker-compose.yml만 있음: Build Wizard 열림 (Dockerfile 필요 알림)

모달 구성 요소

  • Steps 표시: 현재 진행 단계 표시 (0~3)
  • Git URL: 분석할 저장소 URL (자동 입력)
  • Branch: 대상 브랜치 (서비스 설정에서 가져옴)
  • 프로젝트 타입 감지 버튼: 클릭하여 분석 시작

Step 1: 프로젝트 타입 감지

1.1 감지 실행

프로젝트 타입 감지 버튼을 클릭하면 KIWI가 GitLab 저장소를 분석합니다.

1.2 분석 항목

  • 프로젝트 타입: 설정 파일 존재 여부로 감지합니다. (예: package.json → Node.js)
  • 프레임워크: 의존성 분석으로 감지합니다. (예: next 패키지 → Next.js)
  • 패키지 매니저: 락 파일로 확인합니다. (예: yarn.lock → Yarn)
  • TypeScript: tsconfig.json 존재 여부입니다. (Yes/No)
  • 빌드 타입: 프레임워크별로 결정됩니다. (예: Next.js → SSR)
  • 모노레포 여부: 서브 디렉토리 분석으로 감지합니다. (예: frontend/, backend/)

1.3 감지 결과 화면

단일 프로젝트인 경우

프로젝트 분석 완료!

프로젝트 타입: Node.js
프레임워크: Next.js
패키지 매니저: npm
빌드 타입: SSR (서버 사이드 렌더링)
TypeScript: Yes
기본 포트: 3000

모노레포인 경우

모노레포 감지됨: 3개의 서브 프로젝트 발견

┌────────────┬───────────┬─────────────┬──────────┐
│ 경로 │ 타입 │ 프레임워크 │ 선택 │
├────────────┼───────────┼─────────────┼──────────┤
│ frontend/ │ Node.js │ React │ ✓ │
│ backend/ │ Python │ FastAPI │ ✓ │
│ admin/ │ Node.js │ Vue.js │ ✓ │
└────────────┴───────────┴─────────────┴──────────┘

1.4 기존 파일 경고

이미 Dockerfile이나 docker-compose.yml이 있는 경우:

기존 빌드 파일 발견

이미 존재하는 파일: Dockerfile, docker-compose.yml 계속 진행하면 파일이 덮어쓰기됩니다.


Step 2: 빌드 설정

2.1 단일 프로젝트 설정

기본 설정

  • 프로젝트 타입: 감지된 언어입니다. 수정 가능합니다. (예: Node.js)
  • 서비스 이름: docker-compose에서 사용할 이름입니다. (예: my-app)
  • 포트 번호: 컨테이너가 노출할 포트입니다. (예: 3000)

언어 버전 설정

  • 버전: 언어 런타임 버전입니다. (예: Node.js 18, 20, 22)
  • 베이스 OS: 컨테이너 기반 OS입니다. (alpine, slim, bullseye)
버전 선택 가이드
  • alpine: 최소 이미지 크기 (보안 스캔 취약점 적음)
  • slim: Debian 기반 경량화 (호환성 좋음)
  • bullseye/bookworm: 풀 Debian (모든 패키지 사용 가능)

고급 옵션 (Collapse 섹션)

  • Health Check (기본 활성화): 컨테이너 상태 점검을 추가합니다. 운영 환경에서 필수입니다.
  • Non-root User (기본 활성화): 비root 사용자로 실행합니다. 보안상 권장됩니다.

2.2 모노레포 설정

서비스 선택 테이블

  • 선택: 빌드할 서비스 체크박스
  • 경로: 서브 프로젝트 디렉토리 경로
  • 프로젝트 타입: 감지된 언어
  • 프레임워크: 감지된 프레임워크
  • 버전: 선택 가능한 언어 버전
  • 베이스 OS: 선택 가능한 OS
  • 포트: 서비스별 포트 설정

서비스별 고급 옵션

각 서비스마다 개별적으로 설정 가능:

  • Health Check 활성화/비활성화
  • Non-root User 활성화/비활성화

2.3 템플릿 생성

템플릿 생성 버튼을 클릭하면 설정에 맞는 Dockerfile과 docker-compose.yml이 생성됩니다.


Step 3: 파일 미리보기 및 편집

3.1 Monaco Editor

생성된 파일들이 Monaco Editor (VS Code 기반)에서 표시됩니다.

  • 구문 하이라이팅: Dockerfile, YAML 문법 강조
  • 자동 완성: 키워드 자동 완성 지원
  • 오류 검사: 문법 오류 실시간 표시
  • 라인 번호: 줄 번호 표시

3.2 생성되는 파일

단일 프로젝트

  • Dockerfile (루트): 컨테이너 이미지 빌드
  • docker-compose.yml (루트): 로컬 개발 시 여러 컨테이너 실행 설정

모노레포

  • Dockerfile (각 서비스 디렉토리): 서비스별 이미지 빌드
  • docker-compose.yml (루트): 전체 서비스 실행 설정

3.3 Dockerfile 예시

Next.js (SSR)

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production=false
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine AS production
WORKDIR /app

# Non-root user 설정
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

USER nextjs
EXPOSE 3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1

CMD ["node", "server.js"]

React (SPA)

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1

CMD ["nginx", "-g", "daemon off;"]

FastAPI (Python)

FROM python:3.11-slim

WORKDIR /app

# Non-root user
RUN addgroup --system app && adduser --system --group app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN chown -R app:app /app
USER app

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=3s \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Spring Boot (Java)

# Build stage
FROM eclipse-temurin:17-jdk AS builder
WORKDIR /app
COPY . .
RUN ./gradlew bootJar --no-daemon

# Production stage
FROM eclipse-temurin:17-jre
WORKDIR /app

RUN addgroup --system spring && adduser --system --group spring

COPY --from=builder /app/build/libs/*.jar app.jar

RUN chown -R spring:spring /app
USER spring

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]

Go

# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# Production stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates

WORKDIR /app
RUN addgroup -S app && adduser -S app -G app

COPY --from=builder /app/main .

RUN chown -R app:app /app
USER app

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1

CMD ["./main"]

3.4 docker-compose.yml 예시

단일 서비스

version: '3.8'
services:
my-app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
restart: unless-stopped

모노레포 (다중 서비스)

version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
depends_on:
- backend
restart: unless-stopped

backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://db:5432/app
restart: unless-stopped

admin:
build:
context: ./admin
dockerfile: Dockerfile
ports:
- "3001:80"
restart: unless-stopped

3.5 파일 커스터마이징

필요에 따라 생성된 파일을 직접 수정할 수 있습니다.

일반적인 수정 사항:

  • 환경 변수 추가: ENV NODE_ENV=production
  • 포트 변경: EXPOSE 8080
  • 추가 패키지 설치: RUN apk add --no-cache curl
  • 빌드 명령어 변경: RUN npm run build:prod
  • 볼륨 마운트: docker-compose에 volumes 추가

Step 4: GitLab 커밋

4.1 커밋 실행

GitLab에 커밋 버튼을 클릭하면 생성된 파일들이 저장소에 자동 커밋됩니다.

4.2 커밋 정보

  • 커밋 메시지: chore: Add Dockerfile generated by KIWI Build Wizard
  • 브랜치: 서비스에 설정된 기본 브랜치
  • 작성자: KIWI System

4.3 생성되는 파일

  • 단일 프로젝트: Dockerfile, docker-compose.yml
  • 모노레포: frontend/Dockerfile, backend/Dockerfile, docker-compose.yml

4.4 커밋 완료

  1. "빌드 환경 파일이 GitLab에 커밋되었습니다!" 메시지 확인
  2. Build Wizard가 자동으로 닫힘
  3. 이제 Build 단계를 다시 클릭하면 빌드가 시작됩니다.

실제 사용 시나리오

시나리오 1: 신규 Next.js 프로젝트 컨테이너화

상황: create-next-app으로 생성한 프로젝트를 KIWI로 배포하고 싶습니다.

단계:

  1. [서비스 관리]에서 서비스 등록 (Git URL 입력)
  2. Build 클릭 → Build Wizard 자동 열림
  3. 프로젝트 타입 감지 클릭
  4. 감지 결과 확인: Next.js, npm, SSR 타입
  5. 버전 선택: Node.js 20, alpine
  6. 고급 옵션: Health Check ✓, Non-root ✓
  7. 템플릿 생성 클릭
  8. Dockerfile 내용 확인 (Next.js standalone 모드 최적화)
  9. GitLab에 커밋 클릭
  10. 빌드 실행 가능 상태!

시나리오 2: 모노레포 프로젝트 설정

상황: Frontend(React) + Backend(FastAPI) 구조의 모노레포를 배포합니다.

단계:

  1. 서비스 등록 시 모노레포 Git URL 입력
  2. Build 클릭 → Build Wizard 열림
  3. 프로젝트 타입 감지 클릭
  4. 모노레포 감지됨: 2개 서브 프로젝트
  5. 서비스 선택 테이블에서 설정:
    • frontend/: React, Node.js 20, alpine, 포트 3000
    • backend/: FastAPI, Python 3.11, slim, 포트 8000
  6. 템플릿 생성 클릭
  7. 각 서비스별 Dockerfile과 루트 docker-compose.yml 확인
  8. GitLab에 커밋 클릭
  9. 두 서비스 모두 빌드 가능!

시나리오 3: 레거시 Spring Boot 앱 마이그레이션

상황: 기존 Spring Boot 프로젝트를 컨테이너로 마이그레이션합니다.

단계:

  1. 서비스 등록
  2. Build 클릭 → Build Wizard 열림
  3. 프로젝트 타입 감지: Spring Boot, Gradle
  4. 설정 확인:
    • Java 버전: 17 (프로젝트의 sourceCompatibility 기준)
    • 베이스 OS: Eclipse Temurin JRE
  5. 고급 옵션: Health Check ✓ (Spring Actuator 사용)
  6. 템플릿 생성 클릭
  7. Dockerfile 검토 및 수정:
    • 필요시 Gradle 빌드 명령어 커스터마이징
    • Actuator health endpoint 경로 확인
  8. GitLab에 커밋 클릭

문제 해결

프로젝트 타입 감지 실패

  • "Unknown" 타입으로 감지: 표준 설정 파일이 없습니다. package.json, pom.xml, go.mod 등을 추가하세요.
  • 프레임워크 미감지: 의존성 분석에 실패했습니다. 수동으로 프레임워크를 선택하세요.
  • 분석 시간 초과: 저장소 크기가 큽니다. 특정 브랜치로 범위를 제한하세요.

GitLab 연결 오류

  • 401 Unauthorized: 토큰이 만료되었습니다. GitLab Access Token을 갱신하세요.
  • 403 Forbidden: 권한이 부족합니다. 토큰에 api, write_repository 권한을 확인하세요.
  • 404 Not Found: 저장소/브랜치가 없습니다. Git URL과 브랜치명을 확인하세요.

커밋 실패

  • "Protected branch": 브랜치가 보호되어 있습니다. 다른 브랜치를 사용하거나 보호를 해제하세요.
  • "Merge conflict": 파일 충돌이 발생했습니다. 기존 파일 삭제 후 재시도하세요.
  • "File too large": 대용량 파일이 있습니다. .gitignore에 제외 설정을 추가하세요.

빌드 파일 생성 오류

  • 잘못된 포트: 자동 감지 오류입니다. 수동으로 포트 번호를 지정하세요.
  • 빌드 명령어 오류: 비표준 스크립트입니다. Dockerfile에서 직접 수정하세요.
  • 의존성 설치 실패: 프라이빗 레지스트리 문제입니다. Dockerfile에 인증 설정을 추가하세요.

모노레포 관련 문제

  • 서브 프로젝트 미감지: 비표준 구조입니다. 각 서브 디렉토리에 설정 파일을 추가하세요.
  • 서비스 간 의존성: docker-compose 설정이 필요합니다. 수동으로 depends_on을 추가하세요.
  • 공유 코드 참조: 빌드 경로 설정 문제입니다. 프로젝트 루트의 Dockerfile 사용을 고려하세요.

베스트 프랙티스

Dockerfile 최적화

  1. 멀티스테이지 빌드 사용: 빌드 도구를 프로덕션 이미지에서 제외
  2. 레이어 캐싱 활용: 자주 변경되는 파일은 나중에 COPY
  3. alpine 기반 사용: 이미지 크기 최소화
  4. Non-root 사용자: 컨테이너 보안 강화
  5. Health Check 추가: K8s/Docker의 상태 관리 지원

보안 고려사항

  1. 시크릿은 Dockerfile에 하드코딩하지 않음
  2. .dockerignore로 민감한 파일 제외
  3. Non-root 사용자로 실행
  4. 베이스 이미지 정기 업데이트
  5. 멀티스테이지 빌드로 소스코드 제외

관련 가이드