Docker로 만드는 React + Nest + MySQL + Nginx 프로젝트: YAML 공유 및 문법 설명

te-ing·2024년 5월 22일
0

지난 사이드 프로젝트에서 yml파일 하나로 React 클라이언트와 Nest 서버, MySQL 데이터베이스를 띄우려 했다. chatGPT 주도 개발로 만드려 했지만, 계속해서 발생하는 오류로 울며 겨자먹기로 도커를 공부하면서 만들었다. 비슷한 처지에 놓인 사람들에게 작게나마 도움을 드리기 위해 기술스택과 환경, 애먹었던 부분을 정리해서 남기려 한다.

개발환경

개발환경은 MacOS(sonoma), 클라언이언트 React(Vite), 서버 Nest, 데이터베이스 MySQL, 그리고 AWS EC2 환경에서 Nginx의 리버스 프록시 기능을 사용해 클라이언트와 서버의 도메인을 통일시키려 했다.

일단 yml파일과 DockerFile을 공유하고 설명 하자면,

docker-compose.yml

version: '3'
services:
  client:
    container_name: musigaero-client
    build:
      context: ./client
      dockerfile: Dockerfile-client
    env_file:
      - .env
    ports:
        - 80:80
        - 443:443
    volumes:
        - "./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template"
        - "$LOCAL_FULLCHAIN_LOCATION:$NGINX_FULLCHAIN_LOCATION"
        - "$LOCAL_PRIVKEY_LOCATION:$NGINX_PRIVKEY_LOCATION"
    restart: unless-stopped
      
      
  server:
    container_name: musigaero-server
    build:
      context: .
      dockerfile: server/Dockerfile-server
    env_file:
      - .env
    command: npm run start:prod
    ports:
        - $SERVER_API_PORT:$SERVER_API_PORT
    volumes:
        - "$LOCAL_FULLCHAIN_LOCATION:$SERVER_FULLCHAIN_LOCATION"
        - "$LOCAL_PRIVKEY_LOCATION:$SERVER_PRIVKEY_LOCATION"
    depends_on:
      - db
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 500M

  db:
    container_name: musigaero-mysql
    image: mysql:8.0.29
    volumes:
      - './database/mysql/data:/var/lib/mysql'
      - './database/mysql/securefile:/data/securefile'
    env_file:
      - .env
    ports:
      - $MYSQL_SERVER_PORT:$MYSQL_CONNECT_PORT
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci

YAML(YML) 에서 사용된 속성 소개

yml

yml과 yaml은 같은 확장자로 얌엘로 많이들 읽는다. XML, JSON과 같이 포맷에 대한 규칙으로, 가독성과 편의성을 높인 대신 파싱하는 과정에서 상대적으로 자원이 더 많이 소모된다.

version

version: ‘3’은 compose file format에 대한 버전으로, 각 버전마다 사용되는 엔진이나 명령어, 기능등이 다르다. 깊게 다루지 않기 때문에 많이 사용되는 것 같은 ‘3’버전을 사용했다.

container_name

container_name: musigaero-client은 컨테이너 이름으로, 컨테이너를 구분할 수 있으며 필수값은 아니다. 다만 docker 명령어 사용 시 자주 사용하게 되니, 작성하면 좋다.

build

docker compose 명령어 사용 시, Dockerfile은 yml파일이 있는 위치를 기반으로 경로를 설정한다. 필자는 client라는 폴더에 Dockerfile-client이라는 파일명으로 Dockerfile을 넣어놨기 때문에 context: ./client dockerfile: Dockerfile-client와 같이 작성하였다.

env_file

env파일의 경로를 설정할 수 있다. yml 파일에서는 $변수명과 같이 환경변수를 작성할 수 있으며,

env 파일 내용의 예시를 보여드리면 LOCAL_FULLCHAIN_LOCATION=/temp/fullchain.pem 와 같이 작성하면 $LOCAL_FULLCHAIN_LOCATION과 같이 yml 파일에서 사용할 수 있으며, Dockerfile 내에서도 동일하게 사용할 수 있다.

ports

기본적으로 도커는 컨테이너에 172.17.0.x 라는 가상 IP를 순차적으로 할당받기 때문에 호스트와 컨테이너의 포트를 맵핑시켜 컨테이너에 접근하여야 한다.

쉽게 설명하자면,

우리는 리액트에 로컬로 접속할때 보통 localhost:3000으로 접속한다. 이는 로컬호스트의 3000번 포트로 접속하는 것이며, 로컬호스트 IP인 127.0.0.1:3000로 접속하는 것과 같다.

musigaero-client에서 react를 3000번 포트로 만들었다면, musigaero-client 라는 컨테이너는 172.17.0.2라는 IP를 할당받아 172.17.0.2:3000으로 접근할 수 있다.

하지만 172.17.0.2는 도커에서 NAT 기능으로 만들어낸 사설IP이기 때문에 외부에서 접근할 수 없다. 때문에 3000:3000으로 ports를 설정하고 로컬에서 컨테이너를 띄우면 localhost:3000으로 musigaero-client에 접근할 수 있게 된다.

80:3000으로 구현했다면 localhost:80으로 musigaero-client에 접근할 수 있다. 예시에서 80:80으로 되어있는 이유는 nginx를 사용해서 포트를 우회한 것이기 때문에 헷갈려하지 말자.

volumes

volumes은 Docker를 실행하는 곳과 Docker 컨테이너 끼리의 공유공간을 말한다고 보면 쉽다.

  • "./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template" 와 같이 작성했다면 nginx 폴더의 nginx.conf.template 파일이 도커 컨테이너의 /etc/nginx폴더에도 nginx.conf.template이 생긴다.

  • './database/mysql/data:/var/lib/mysql' 처럼 작성한다면 도커 컨테이너의 /var/lib/mysql 내에 작성되는 파일이 로컬의 ./database/mysql/data에도 작성되기 때문에 일종의 데이터베이스 백업역할을 할수 있다.

restart

도커컨테이너의 재시작을 언제 할 지 설정할 수 있다. unless-stopped는 중지했을 때를 제외하고 재시작이기 중지되었을 때를 제외하면 계속해서 재시작된다. always로 설정했다면 도커컨테이너가 어떤 오류로 중지되었을 때 계속해서 재시작하게 된다.

depends_on

도커 서비스의 실행순서를 지정할 수 있다. Nest는 데이터베이스가 생성된 후에 실행되어야 하기 때문에 server 서비스가 db 서비스 이후에 실행되도록 설정하였다.

deploy

배포환경에 대한 설정으로, musigaero-server에는 리소스와 리소스 제한에 대한 설정을 넣어놓았다. 주로 한 컨테이너가 너무 많은 리소스를 독차지하는 것을 막기 위해 사용한다.
cpus: '0.50', memory: 500M와 같이 작성했다면 cpu는 최대 절반만, 메모리는 500메가만 사용하도록 제한한 것이다.

command

컨테이너가 생성된 뒤 실행되는 커맨드이다. Nest는 데이터베이스가 생성된 후에 server 컨테이너가 생성되고 이후 npm run start:prod가 실행되면서 Nest가 실행된다.

profile
프론트엔드 개발자

0개의 댓글