Web Project/shop

Docker 배포 후 로컬 개발 환경 다시 구축

hmmmmmmmmmmmm 2025. 9. 27. 22:18

CI/CD 파이프라인을 통해 Spring Boot/React 애플리케이션을 도커화하고 배포했지만

이후 추가 기능 구현 계획으로 다시 로컬 환경에서 개발하기

 

1. 운영 환경과 개발 환경의 분리

기존의 운영용 docker-compose.yml과 별개로 개발 전용 docker-compose.dev.yml 파일을 생성하여 환경을 분리하기

 

2. 개발 워크플로우를 위한 Docker Compose 설정

1) Volume Mounts: 로컬 호스트의 소스코드 디렉터리를 실행 중인 컨테이너 내부의 작업 디렉터리와 실시간으로 동기화 하기

2) Build Stage Targeting: Multi-stage build로 구성된 Dockerfile에서, 최종 운영 이미지가 아닌 개발 도구가 포함된 중간 단계의 builder 스테이지를 최종 이미지로 사용하도록 지정하기

3) Entrypoint/Command Overriding: Dockerfile에 정의된 운영용 실행 명령어를 무시하고, mvn spring-boot:run이나 npm start 같은 개발 서버 실행 명령어로 덮어쓰기

 

docker-compose.dev.yml

services:
  db:
    image: mysql:8.0
    ports:
      - "3307:3306"
    container_name: shop-mysql-db-dev
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: shop
      TZ: Asia/Seoul
    volumes:
      - db-data:/var/lib/mysql
    healthcheck:
      # ... (DB Healthcheck 설정)

  backend:
    build:
      context: ./backend
      target: builder # JRE가 아닌 Maven/JDK가 포함된 builder 스테이지 사용
    container_name: shop-backend-app-dev
    restart: always
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:8080"
      - "5005:5005" # 원격 디버깅 포트
    volumes:
      - ./backend:/app # 로컬 소스코드와 컨테이너 동기화
    entrypoint: mvn spring-boot:run -Dspring-boot.run.jvmArguments=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

  frontend:
    build:
      context: ./frontend
      target: builder # Nginx가 아닌 Node.js가 포함된 builder 스테이지 사용
    container_name: shop-frontend-web-dev
    restart: always
    depends_on:
      - backend
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app # 로컬 소스코드와 컨테이너 동기화
      - /app/node_modules # node_modules 충돌 방지
    command: ["npm", "start"] # React 개발 서버 실행
    stdin_open: true
    tty: true

volumes:
  db-data:

 

 

3. 트러블슈팅

위와 같이 설정을 마친 후 docker-compose -f docker-compose.dev.yml up --build 명령어로 실행하는 과정에서 에러 해결

 

1) Frontend → Backend 통신 두절 (ECONNREFUSED)

현상: 브라우저는 500 Internal Server Error, 프론트엔드 터미널에는 Proxy error: ... (ECONNREFUSED)가 발생

 

분석: ECONNREFUSED는 연결 거부를 의미한다. 프론트엔드의 프록시 서버가 백엔드(http://backend:8080)로 요청을 전달하려 했으나, 해당 포트에서 리스닝 중인 프로세스가 없어 연결이 거부되었다. 백엔드 컨테이너가 시작되지 못했음을 의미한다.

 

백엔드 컨테이너 로그 확인 결과, Schema-validation: missing table [cart_items] 에러로 인해 Spring Boot 애플리케이션이 시작되지 못하고 있었다. 이는 spring.jpa.hibernate.ddl-auto=validate 설정이 코드의 Entity와 실제 DB 스키마의 일치 여부를 검사하고, 불일치 시 앱을 종료시킨다

 

해결: application.properties 파일에 spring.jpa.hibernate.ddl-auto=update 설정을 추가하여, 앱 시작 시 Entity 기준으로 DB 스키마를 자동으로 생성/업데이트하도록 변경했다

 

 

4. 결론

배포된 애플리케이션을 다시 로컬 개발 환경으로 가져오는 과정은 단순히 docker-compose up 명령어로 끝나지 않았다.

운영 환경과 개발 환경의 근본적인 차이를 이해하고, 그에 맞춰 네트워크(Proxy), 보안(CORS, Security Rules), 애플리케이션 설정(ddl-auto, JWT Provider)을 모두 수정해야 했다.

Docker, Spring Security, React Proxy 등 각 기술 요소의 동작 원리를 깊게 이해해야 할 필요성을 느낀다.