[도커] 도커 데스크탑에서 Docker Compose로 React, Spring, MySQL 3티어 아키텍쳐 올리기

Woonil·3일 전
0

도커

목록 보기
1/1

동아리 홈페이지 프로젝트 리팩토링 중 혼자 유지보수를 진행하고 있던 터라 목업으로 백엔드 응답을 가정하고 진행했다. 하지만 수정사항이 올바르게 동작하는지 확신할 수가 없었다. 따라서 실제 운영 환경 위에서 앱이 제대로 동작하는지 확인하고 싶었다. 물론 프론트엔드, 백엔드, 데이터베이스 각각의 로컬 서버를 띄워 진행하는 방법도 존재한다. 하지만 매번 이런 작업을 수행하기에는 노력이 많이 든다. 따라서 Docker와 Docker Compose를 활용하여 이러한 작업을 수월하게 만들고자 한다 (참고로 실제로 온프렘 서버의 도커컴포즈로 운영되고 있다).

  • 프로젝트 폴더 구조
    우선 프로젝트 루트에 프론트엔드와 백엔드 프로젝트 폴더와 도커 컴포즈 파일을 위치시킨다. 프론트엔드, 백엔드 각각에서 별도로 도커 이미지를 생성할 것이므로 꼭 이 구조를 따를 필요는 없다. 다만, 이해를 돕기 위해 이러한 구조로 설명을 진행한다. 프론트엔드와 백엔드 각각은 본인의 Dockerfile을 참조하여 도커 이미지를 빌드한다.
	|- 프론트엔드
		-	Dockerfile
	|- 백엔드
		-	Dockerfile
	docker-compose.yml

개념

1. 도커이미지 빌드하기

프론트엔드 Dockerfile

프론트엔드 이미지에는 웹 서버인 nginx를 포함하며 빌드된 결과물 또한 nginx에 포함되어 이미지로 저장된다.

# react 앱 빌드
FROM node:alpine as builder

WORKDIR /usr/src/app

# COPY package.json yarn.lock .
COPY package.json yarn.lock ./

RUN yarn install

COPY ./ ./

RUN yarn build

# 2. nginx 빌드
FROM nginx
EXPOSE 80
COPY --from=builder /usr/src/app/dist /usr/share/nginx/html

# nginx 기본 설정 파일 삭제
RUN rm /etc/nginx/conf.d/default.conf

# custom 설정파일을 컨테이너 내부로 복사한다.
COPY ./nginx.conf /etc/nginx/nginx.conf

백엔드 Dockerfile

# 빌드 단계 - 별칭 builder
FROM gradle:7.6.1-jdk17-alpine as builder

WORKDIR /build

# 의존성 캐싱을 위해 gradle 파일 먼저 복사
COPY build.gradle settings.gradle /build/
RUN gradle build -x test --parallel --continue > /dev/null 2>&1 || true

# 소스 코드 복사
COPY . /build
RUN gradle clean build -x test --parallel

# 실행 단계 - 별칭 runner
FROM openjdk:17-alpine AS runner

WORKDIR /app

# JAR 파일 패턴으로 복사
COPY --from=builder /build/build/libs/*.jar ./파일명.jar

# Entry point 설정
ENTRYPOINT ["java", "-Dspring.profiles.active=${SPRING_PROFILE}", "-Duser.timezone=Asia/Seoul", "-jar", "파일명.jar"]

2. 도커 컴포즈 파일 작성하기

docker-compose.yml

version: "3"

services:
  # MySQL 컨테이너
  db:
    image: mysql:8.0
    container_name: db_container
    volumes:
    # 1) 도커 볼륨 사용
      - mysql_data:/var/lib/mysql
    # 2) 바인드 마운트 사용
    #   - ./db_data:/var/lib/mysql    # mysql 컨테이너 내부 /var/lib/mysql과 host의 db_data를 연결
    # expose는 컨테이너 내부 통신 포트를 엶을 의미
    expose:
      - "3306"
    # ports는 호스트 포트와 컨테이너 포트를 매핑
    # ports:
    #   - "3307:3306"
    restart: always
    command:
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci
    environment:
      - MYSQL_ROOT_HOST=%
      - MYSQL_ROOT_PASSWORD=비밀번호
      - MYSQL_DATABASE=데이터베이스명
      - TZ=Asia/Seoul
      
  # 백엔드 컨테이너
  backend:
    # 의존하는 DB 컨테이너
    depends_on:
      - db
    image: nestnet-server-dev:latest # 빌드한 백엔드 이미지
    container_name: backend_container
    # nginx에서 통신하는 백엔드 컨테이너의 포트가 8080으로 설정되었다고 전제
    expose:
      - "8080"
    restart: always
    environment:
      SPRING_PROFILE: prod
      spring-datasource-url:
      secret-key:
      mysql-pw:

  # 프론트엔드 컨테이너
  frontend:
    image: nestnet-client-dev:latest # 빌드한 프론트엔드 이미지
    container_name: frontend_container
    # 호스트의 80 포트와 컨테이너의 80 포트를 양방향 연결하여 외부에서 웹 애플리케이션을 접속할 수 있도록 설정
    ports:
      - "80:80"
    restart: always
# 도커 볼륨 사용
volumes:
  mysql_data:

3. 도커 컴포즈 파일 실행하기

docker compose (-p 컴포즈명) up (-d) 로 도커 컴포즈를 올린다. 이때, -p 옵션으로 컴포즈명을 지정하거나 -d(daemon) 옵션으로 백그라운드d에서 실행할 수 있다.

트러블 슈팅

Access denied for user 'root'@'localhost' (using password: NO)

백엔드 컨테이너가 무한반복 재시작된다.. docker logs 컨테이너명 이나 도커 데스크탑의 해당 컨테이너의 로그 항목에서 로그를 확인할 수 있는데, Access denied for user 'root'@'localhost' (using password: NO) 라는 로그가 찍힌걸 확인할 수 있었다. 결론만 말하면 이는 mysql에서 백엔드 컨테이너의 접근을 막는 것이다. 당연하게도 spring과 같은 백엔드 애플리케이션에서는 db에 접근을 해야하며 이를 위해서는 db 사용자로서 권한을 가지고 있어야 한다. 따라서 백엔드 컨테이너에 대한 계정을 등록하고, 해당 계정에 db 접근 권한을 주어야 한다.

  • 계정 등록
    create user 백엔드 컨테이너 ip@'%' identified by '비밀번호';
  • 권한 부여
    grant all privileges on 데이터베이스이름.* to 백엔드 컨테이너 ip@'%';
profile
프론트 개발과 클라우드 환경에 관심이 많습니다:)

0개의 댓글

관련 채용 정보