[Full Stack 배포] React + Springboot + Docker 로컬 환경에서 실행

장성준·2024년 1월 17일
1

Full Stack 배포

목록 보기
5/8
post-thumbnail
post-custom-banner

이번 시간에는 Docker, docker-compose를 사용하여 로컬 환경에서 Nginx(React), Tomcat(Springboot)을 명령어 한줄로 실행시켜 보도록 하겠습니다.

전체 배포 과정을 시리즈로 다루고 있습니다.
궁금하신 분들은 여기에서부터 순차적으로 따라와주시길 바랍니다.

Docker를 어떻게 공부해야할 지 모르겠다면 진행에 앞서 다음 강좌의 학습을 우선적으로 추천드립니다.

도커 한방에 정리
초보를 위한 도커 안내서
도커 쓸 땐 필수! 도커 컴포즈


구체적인 순서는 다음과 같습니다.

  1. Docker Desktop 다운로드
  2. DockerHub 가입 및 로그인
  3. Dockerfile 작성
  4. Nginx 설정 파일 작성
  5. Docker Image 빌드 및 도커허브에 push
  6. 도커허브에서 pull 및 docker-compose.yml 파일로 컨테이너 실행

빌드된 이미지를 도커허브에 올리고 로컬 환경에서 pull 받아 뛰울 수 있다면 EC2에서도 같은 방식으로 쉽게 실행시킬 수 있습니다.

그럼 순서대로 알아보도록 하겠습니다.


Docker Desktop 설치

https://www.docker.com/products/docker-desktop

Git을 Sourcetree라는 GUI 앱으로 조작하듯이 Docker 명령어를 일일히 칠 필요 없이 Docker Desktop을 통해서 편리하게 제어할 수 있습니다.
해당 앱을 설치하면 Docker도 자동으로 같이 설치됩니다.


DockerHub 가입 및 로그인

https://hub.docker.com

Git으로 관리하는 소스코드를 GitHub라는 사이트에 올리고 받듯이 DockerHub는 Docker 이미지를 원격에 올리고 받을 수 있도록하는 사이트입니다.

다음과 같이 로그인이 되었다면 이미지를 만들고 올릴 수 있도록 소스코드를 수정해주도록 합시다.


Backend

build.gradle

jar {
	enabled = false
}

끝에 다음과 같이 추가해줍시다. 빌드 시 jar 파일이 하나만 생성되도록 해줍니다.

bootJar를 수행하여 build/libs 폴더 및에 jar 파일이 생성되도록 해줍니다.

build 밑에 libs 폴더를 수동으로 추가하셔도 상관없습니다.
jar 파일이 하나만 생성되는지도 확인해 봅시다.

루트 디렉토리에 Dockerfile 파일을 추가하고 다음과 같이 추가해줍니다.

# OpenJDK 17을 기반으로 하는 경량화 스프링 부트 이미지
FROM openjdk:17-alpine

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

# JAR 파일을 컨테이너에 복사(jar파일이 하나만 생기도록 설정해줘야 함.)
COPY build/libs/*.jar app.jar

# 포트 설정
EXPOSE 8080

# 실행 명령어
ENTRYPOINT ["java", "-jar", "app.jar"]

Docker는 Dockerfile을 참고하여 이미지를 만듭니다.

터미널에서 해당 디렉토리로 이동한 후 이미지를 만들어줍니다.

docker build -t [도커허브 유저명]/[이미지 명] .

현재 폴더의 Dockerfile을 참고하여 이미지를 만드는 명령어 입니다.
예시) docker build -t g6y116/full-stack-be .

다음 명령어를 입력하여 이미지 목록을 확인할 수 있습니다.

docker images

Docker Desktop에서는 더 쉽게 확인할 수 있습니다.

해당 이미지를 DockerHub에 push 해줍니다.

docker push [도커허브 유저명]/[이미지 명]

예시) docker push g6y116/full-stack-be

Docker Desktop에서 확인해 봅시다.

앱에서 로그인을 해야 Hub 탭이 활성화 됩니다.

이미지를 DockerHub에서 pull 받아봅시다.

Local 탭에서 해당 이미지를 삭제하고 다음 명령어를 입력해봅시다.

docker pull [도커허브 유저명]/[이미지 명]

예시) docker pull g6y116/full-stack-be

이미지를 제대로 받았는지 확인해 봅시다.

docker images

Docker Desktop에서 조작할 수도 있지만 EC2에 접근했을때는 명령어만 입력할 수 있기 때문에 명령어를 쳐보는 방식으로 한 번 진행해 보았습니다.


Frontend

루트 디렉토리에 다음과 같이 폴더와 파일을 추가해줍시다.

nginx.conf

worker_processes 1; # 1개의 워커 프로세스를 사용

events {
    worker_connections 1024; # 각 워커 프로세스가 동시에 처리할 수 있는 최대 연결 수를 1024로 설정
}

http {

    include /etc/nginx/mime.types;
    
    upstream backend {
        server backend:8080; # backend : 도커컴포즈 서비스명
    }

    server {
        listen 80; # 클라이언트의 요청을 받을 포트 설정

        # 기본 루트 경로와 인덱스 파일을 설정
        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
            try_files $uri $uri/ /index.html;
        }

        # '/api/'로 시작하는 모든 요청에 대해 백엔드 서버로 프록시하도록 설정
        location /api/ {
            proxy_pass http://backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

mime.types

types {
    text/html                            html htm shtml;
    text/css                             css;
    image/gif                            gif;
    image/jpeg                           jpeg jpg;
    image/svg+xml                        svg;
    application/javascript               js;
}

루트 디렉토리에 도커파일을 추가해줍시다.

Dockerfile

# Node.js를 기반으로 하는 리액트 앱 이미지
FROM node:16-alpine as build

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

# 의존성 설치 및 빌드(CI)
COPY package.json .
RUN npm install
COPY . .
RUN npm run build

# Nginx를 기반으로 하는 최종 이미지
FROM nginx:alpine

# Nginx 설정 파일 복사
COPY nginx/nginx.conf /etc/nginx/nginx.conf

# mime.types 파일을 복사
COPY nginx/mime.types /etc/nginx/mime.types

# 빌드된 리액트 앱을 Nginx의 HTML 디렉토리로 복사
COPY --from=build /app/build /usr/share/nginx/html

# 포트 설정
EXPOSE 80

# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]

해당 이미지는 80번 포트에서 실행되는 Nginx 이미지를 만듭니다.
React 앱을 빌드하면 하나의 문서로 변환되는데 이것을 Nginx의 index.html 역활로 두어 브라우저가 도메인에 접근하면 해당 문서를 주도록 설정하였습니다.

그다음은 이전과 비슷합니다.
다만 주의해야할 점은 이미지명을 다르게 주셔야합니다.

터미널에서 해당 디렉토리로 이동한 후 이미지를 만들어줍니다.

이미지 빌드

docker build -t [도커허브 유저명]/[이미지 명] .

예시) docker build -t g6y116/full-stack-fe .

이미지 확인

docker images

이미지 푸시

docker push [도커허브 유저명]/[이미지 명]

예시) docker push g6y116/full-stack-fe

Docker Desktop - Local 탭에서 해당 이미지를 삭제하고 DockerHub에서 pull

docker pull [도커허브 유저명]/[이미지 명]

예시) docker pull g6y116/full-stack-fe

이미지 확인

docker images

docker-compose.yml 파일 작성

도커 환경에서 여러 개의 컨테이너를 동시에 실행하기 위해서는 docker-compose.yml 파일을 작성하는 것이 좋습니다. 같은 네트워크에서 컨테이너를 돌릴 수도 있고 복잡한 설정들을 명령어 한줄로 실행할 수 있도록 도와줍니다.

두 레포지토리 폴더와 같은 수준에 다음 파일을 추가해줍시다.

docker-compose.yml

version: '3'
services:
  backend:
    image: [도커허브 유저명]/[백엔드 이미지 명]
    ports:
      - "8080:8080"
    networks:
      - network

  frontend:
    image: [도커허브 유저명]/[프론트엔드 이미지 명]
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - network

networks:
  network:

실행

해당 경로에서 다음 명령어를 입력해봅시다.

docker-compose up -d

프론트엔드와 백엔드이미지가 컨네이터화 되어 실행되는 것을 확인할 수 있습니다.

명령어로 컨테이너 상태 확인

docker ps -a

Docker Desktop에서 확인

Running 상태로 유지되는지 확인해줍시다.


결과

http://localhost:80

WebServer(Nginx)에 정상적으로 접근되는 것을 확인할 수 있습니다.
그런데 http는 80번 포트를 입력하지 않아도 뒤에 붙여주기 때문에 다음과 같이 접근할 수가 있습니다.

http://localhost

기존 사이트와 같이 도메인 주소로 접근할 수 있게 되었습니다.

마무리

이로써 Docker, docker-compose를 사용하여 로컬 환경에서 Nginx(React), Tomcat(Springboot)을 docker-compose 명령어 한 줄로 실행시켜 보았습니다.

여기에서 조금만 응용하면 EC2에 수동으로 뛰울 수 있습니다.

하지만.. 실제 현업에서는 코드 변경이 있을때마다 지금과 같이 수동으로 명령어를 입력해서 배포하는 것일까요?

다행이도, 깃허브에 소스를 푸시만 하면 자동으로 빌드 테스트를 하고 배포시키는 방법이 있습니다.
대표적으로 CI/CD 기능을 제공하는 JenkinsGitHub Action이 있는데요.

GitHub Action으로 하는 방식이 상대적으로 간단하면서도 강력하기 때문에 GitHub Action을 사용하여 EC2에 자동으로 배포하는 방법을 알아보도록 하겠습니다.

감사합니다.

profile
Backend Engineer
post-custom-banner

0개의 댓글