FE 컨테이너화와 BE 컨테이너화

SIMWOOHYUN·2025년 6월 2일
post-thumbnail

FE 컨테이너화와 BE 컨테이너화 기술 블로그


개요

현대 웹 애플리케이션은 주로 Frontend(이하 FE)와 Backend(이하 BE)로 분리되어 개발됩니다. 컨테이너화(Containerization)는 애플리케이션을 가볍고 이식성 높은 단위로 패키징하여 어디서든 동일한 환경에서 실행될 수 있도록 해 주는 기술입니다. 본 블로그에서는 FE 컨테이너화와 BE 컨테이너화의 개념, 구현 방법, 고려 사항을 상세히 다루겠습니다.


목차

  1. 컨테이너화(Containerization)란?
  2. FE 컨테이너화
    • 2.1. 개념 및 장점
    • 2.2. Dockerfile 예시 (React 기반)
    • 2.3. 실무 적용 팁
  3. BE 컨테이너화
    • 3.1. 개념 및 장점
    • 3.2. Dockerfile 예시 (Node.js 기반)
    • 3.3. 실무 적용 팁
  4. FE vs BE 컨테이너화 비교
  5. CI/CD 파이프라인에서의 컨테이너 활용
  6. 결론

1. 컨테이너화(Containerization)란?

  • 정의: 컨테이너화는 애플리케이션과 그 실행에 필요한 라이브러리, 설정 등을 하나의 패키지(컨테이너 이미지)로 묶어 배포 및 실행하는 기법입니다.
  • 장점
    • 일관된 실행 환경: 로컬, 테스트, 프로덕션 환경 간 동일한 컨테이너 이미지를 사용하여 환경 불일치 문제를 최소화
    • 경량성: VM(Virtual Machine) 대비 오버헤드가 적으며 빠른 기동 속도
    • 이식성: 어느 곳에서나 동일하게 동작하므로 클라우드, 사내 서버, 개인 PC 등 이식성이 뛰어남
    • 스케일링 용이: 마이크로서비스 아키텍처 기반으로 컨테이너 인스턴스를 빠르게 늘리고 줄일 수 있음

2. FE 컨테이너화

2.1. 개념 및 장점

  • 개념: FE 컨테이너화는 React, Vue, Angular 등의 SPA(Single Page Application) 혹은 정적 사이트 생성기(Next.js, Gatsby 등)를 통해 생성된 정적 파일(HTML/CSS/JS)을 Nginx, Caddy, Apache 등의 경량 웹 서버 위에서 서빙하도록 컨테이너화하는 과정입니다.
  • 주요 장점
    • 정적 + CDN 결합: 빌드 결과물을 컨테이너 이미지로 패키징하여 CDN 배포 전용 파이프라인으로 손쉽게 연결
    • 버전 관리: 이미지 태그(tag)를 통해 특정 빌드 버전을 명확하게 관리 가능
    • 보안 및 성능: 경량 웹 서버(Nginx 등)를 함께 구성하여 정적 파일 서빙 최적화
    • 인프라 독립성: 로컬 개발 환경, 스테이징, 프로덕션 환경 모두 동일하게 동작

2.2. Dockerfile 예시 (React 기반)

아래는 React 애플리케이션을 Nginx로 서빙하기 위한 간단한 Dockerfile 예시입니다.

# 1. 빌드 스테이지
FROM node:18-alpine AS build

# 작업 디렉토리 설정
WORKDIR /app

# 의존성 복사 및 설치
COPY package.json package-lock.json ./
RUN npm ci --silent

# 소스 코드 복사
COPY . .

# 빌드 실행 (production용)
RUN npm run build

# 2. 실제 실행 스테이지 (정적 서버 구성)
FROM nginx:1.23-alpine

# 기존 default.conf 제거 (옵션)
RUN rm /etc/nginx/conf.d/default.conf

# 커스텀 Nginx 설정 복사 (예: /etc/nginx/conf.d/app.conf)
COPY nginx.conf /etc/nginx/conf.d/app.conf

# 빌드 결과물을 Nginx가 서빙할 경로로 복사
COPY --from=build /app/build /usr/share/nginx/html

# 컨테이너 실행 시 Nginx 데몬이 포그라운드로 실행되도록 설정
CMD ["nginx", "-g", "daemon off;"]
  • 설명
    1. 빌드 스테이지(build)
      • node:18-alpine 이미지를 사용하여 프로젝트 의존성을 설치하고 npm run build를 실행.
      • 빌드 결과물은 /app/build 디렉토리에 생성됨.
    2. 실행 스테이지(runtime)
      • nginx:1.23-alpine 이미지를 기반으로 custom Nginx 설정(nginx.conf)을 적용.
      • 앞서 빌드 스테이지에서 생성된 정적 파일을 Nginx의 기본 서빙 경로(/usr/share/nginx/html)로 복사.
      • 최종 컨테이너는 Nginx가 빌드된 정적 파일을 HTTP로 서빙.

2.3. 실무 적용 팁

  • 멀티 스테이지 빌드: 위 예시처럼 빌드 환경과 실행 환경을 분리하면 컨테이너 이미지 용량을 크게 줄일 수 있음.
  • 커스텀 Nginx 설정
    • gzip 압축 설정
    • 캐시 만료 헤더 설정
    • HTTPS 및 리다이렉션 설정
  • 환경 변수 주입
    • 빌드 시점(npm run build)에 REACT_APP_* 형태의 환경 변수를 주입하거나, 런타임에 envsubst 등을 이용해 템플릿 처리
  • CI/CD와 연계
    • GitHub Actions, GitLab CI, Jenkins 등에서 docker builddocker push → Kubernetes/서버 배포 플로우 구성
  • 보안 점검
    • Nginx 버전 정기 업데이트
    • 불필요한 디렉토리, 파일 제거
    • 컨테이너 내 유저 권한을 nginx 또는 www-data 등 비루트 사용자로 설정

3. BE 컨테이너화

3.1. 개념 및 장점

  • 개념: BE 컨테이너화는 Node.js, Spring Boot, Django 등 API 서버 또는 애플리케이션 서버를 컨테이너 이미지로 패키징하여 동작시키는 과정입니다.
  • 주요 장점
    • 라이브러리/런타임 일관성: BE 애플리케이션이 의존하는 특정 버전의 런타임(Node.js, Java, Python 등)을 컨테이너에 묶어 일관성 보장
    • 스케일 아웃: 동일한 컨테이너 이미지를 여러 인스턴스로 띄워 부하 분산(Load Balancing) 및 오토스케일링 가능
    • 배포 자동화: CI 파이프라인에서 테스트 → 빌드 → 배포까지 자동화, 롤백 전략 구현 용이
    • 인프라 격리: 서로 다른 BE 서비스(마이크로서비스)가 독립된 컨테이너에서 실행되어 라이브러리 충돌 최소화

3.2. Dockerfile 예시 (Node.js 기반)

아래는 Express 기반의 간단한 Node.js BE 애플리케이션을 컨테이너화하기 위한 Dockerfile 예시입니다.

# 1. 베이스 이미지 설정
FROM node:18-alpine

# 애플리케이션 전용 디렉토리 생성 및 작업 디렉토리 설정
WORKDIR /usr/src/app

# 의존성 설치를 위한 패키지 복사
COPY package.json package-lock.json ./

# 프로덕션 의존성만 설치 (옵션: devDependencies 제외)
RUN npm ci --only=production

# 소스 코드 복사
COPY . .

# 환경 변수 설정 (예: 포트, 실행 모드 등)
ENV NODE_ENV=production
ENV PORT=3000

# 컨테이너가 바인딩할 포트
EXPOSE 3000

# 애플리케이션 시작 명령
CMD ["node", "server.js"]
  • 설명
    1. 베이스 이미지: node:18-alpine을 사용하여 경량화 및 빠른 빌드 지원.
    2. 의존성 설치: npm ci --only=production으로 프로덕션용 의존성만 설치.
    3. 소스 복사: 애플리케이션 소스 코드 복사.
    4. 환경 변수: NODE_ENV, PORT 등 런타임에 필요한 환경 변수 설정.
    5. 포트 EXPOSE: 컨테이너 실행 시 Node.js 서버가 바인딩할 포트 지정.
    6. 실행 명령: server.js를 통해 Express 서버 기동.

3.3. 실무 적용 팁

  • 빌드 캐시 활용: package.jsonpackage-lock.json을 먼저 복사하고 npm ci를 실행하면, 코드 변경 시 의존성이 변경되지 않았다면 Docker 빌드 캐시 활용 가능.
  • 환경 변수 분리
    • .env 파일을 직접 복사하지 말고, 도커 실행 시 -e 옵션 또는 docker-compose.yml에서 env_file을 활용.
    • 민감 정보(시크릿, API 키 등)는 도커 시크릿(Docker Secrets) 혹은 Kubernetes 시크릿으로 관리.
  • 헬스체크(Healthcheck)
    • 컨테이너의 상태 모니터링을 위해 HEALTHCHECK 지시어를 사용하여 주기적으로 /health 엔드포인트 요청 등으로 상태 확인.
  • 로깅 & 모니터링
    • STDOUT/STDERR로 로그를 출력하도록 구성하면, 중앙화된 로깅 솔루션(ELK 스택, Grafana Loki 등)과 쉽게 연동.
  • 멀티 스테이지 빌드(옵션)
    • Java(Spring Boot)와 같은 경우 maven 또는 gradle 빌드 스테이지를 별도로 두고, 실행 시 jre 이미지를 사용하는 식으로 이미지 경량화 가능.

4. FE vs BE 컨테이너화 비교

구분FE 컨테이너화BE 컨테이너화
목적정적 자산(HTML/CSS/JS)을 서빙API 서버 또는 애플리케이션 서버 실행
기반 기술 스택React, Vue, Angular 등 + Nginx, Caddy 등Node.js, Java(Spring Boot), Python(Django/Flask) 등
이미지 크기대체로 경량 (정적 빌드 결과물 + 웹 서버)의존성(런타임, 라이브러리) 포함 → 상대적으로 더 무거움
빌드 단계- Node.js 기반 빌드 스테이지
- Nginx 실행 스테이지
- 단일 스테이지 또는 멀티 스테이지(빌드 & 런타임 분리)
환경 변수 주입 시점- 빌드 시점(npm run build)
- 런타임(envsubst)
- 런타임(docker run -e, env_file, 시크릿 관리)
서빙 방식정적 파일 서빙(Nginx)HTTP API 엔드포인트 노출(Express, Spring Controller 등)
볼륨/클러스터링일반적으로 볼륨이 필요 없음(정적 파일만 포함)데이터베이스, 파일 스토리지 등 외부 서비스와 연동 필요
스케일링정적 컨텐츠 캐시 → CDN 활용오토스케일링 필요(로드밸런서 → 여러 컨테이너 인스턴스)
보안 고려 사항- HTTPS 설정
- 콘텐츠 보안 헤더 설정
- 인증/인가
- 시크릿 관리
- CORS 설정 등

5. CI/CD 파이프라인에서의 컨테이너 활용

  • FE 파이프라인 예시 (GitHub Actions 기반)

    1. Checkout 코드

      - name: Checkout code
        uses: actions/checkout@v3
    2. Node.js 설정 & 의존성 설치

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm ci
    3. 빌드 & 이미지 생성

      - name: Build React App
        run: npm run build
      
      - name: Build Docker Image
        run: |
          docker build -t myrepo/frontend:${{ github.sha }} .
    4. Docker Registry 푸시

      - name: Log in to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Push Docker Image
        run: |
          docker push myrepo/frontend:${{ github.sha }}
    5. 배포 (예: Kubernetes, ECS 등)

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/frontend-deployment \
            frontend=myrepo/frontend:${{ github.sha }}
  • BE 파이프라인 예시 (GitLab CI 기반)

    stages:
      - build
      - test
      - dockerize
      - deploy
    
    build:
      stage: build
      image: node:18-alpine
      script:
        - npm ci
        - npm run lint
        - npm test
    
    dockerize:
      stage: dockerize
      image: docker:stable
      services:
        - docker:dind
      script:
        - docker build -t registry.example.com/mygroup/backend:$CI_COMMIT_SHORT_SHA .
        - docker push registry.example.com/mygroup/backend:$CI_COMMIT_SHORT_SHA
    
    deploy:
      stage: deploy
      image: bitnami/kubectl:latest
      script:
        - kubectl set image deployment/backend-deployment backend=registry.example.com/mygroup/backend:$CI_COMMIT_SHORT_SHA

6. 결론

  • FE 컨테이너화와 BE 컨테이너화는 목적과 구현 방식에서 차이가 있지만, 공통적으로 일관된 실행 환경, 이식성, 스케일링 유연성 등 컨테이너화의 이점을 누릴 수 있습니다.
  • FE 컨테이너화는 주로 정적 자산을 웹 서버(Nginx 등)로 서빙할 때 적용하며, 멀티 스테이지 빌드를 통해 이미지 용량을 최소화할 수 있습니다。
  • BE 컨테이너화는 애플리케이션 서버 자체를 컨테이너로 감싸 런타임-라이브러리 종속성을 해결하고, 헬스체크, 환경 변수, 시크릿 관리 등을 통해 안정적인 운영을 보장합니다。
  • CI/CD 파이프라인에서 컨테이너 이미지를 자동으로 빌드, 테스트、배포하도록 구성하면 개발→배포 주기(빌드 파이프라인)를 단축하고 롤백 전략을 구현하기가 쉬워집니다。
  • 최종적으로、컨테이너화는 마이크로서비스、서버리스、클라우드 네이티브 아키텍처 전환을 위한 필수 요소이므로、FE와 BE 모두에서 컨테이너 기반 워크플로우를 설계/적용해 나가기를 추천드립니다。

0개의 댓글