주뇽's 저장소

[AWS EC2 with Docker] 하나의 도커 컨테이너에서 프론트엔드와 백엔드 이미지를 만들어 AWS EC2에 배포하기 본문

클라우드서비스

[AWS EC2 with Docker] 하나의 도커 컨테이너에서 프론트엔드와 백엔드 이미지를 만들어 AWS EC2에 배포하기

뎁쭌 2024. 6. 13. 11:41
728x90
반응형

이번 글에서는 리액트와 스프링부트 애플리케이션을 하나의 도커 컨테이너에 담아 AWS EC2에 배포하는 방법을 설명한다. 이 과정은 프론트엔드와 백엔드 애플리케이션을 빌드하고, 이를 하나의 도커 이미지로 만든 후 AWS EC2에 배포하는 단계로 진행한다.

 

 

프로젝트 구조

프로젝트의 디렉토리 구조는 다음과 같다:

/Myapp
  ├── Backend (스프링부트 애플리케이션)
  └── reactworkspace/Myapp (Vite + React 애플리케이션)

1. 프론트엔드 애플리케이션 빌드

먼저 프론트엔드 애플리케이션을 빌드한다. Vite를 사용하여 리액트 애플리케이션을 빌드하는 방법은 다음과 같다:

cd 자신의 프론트 루트 폴더
npm install
npm run build

위 명령어가 성공적으로 실행되면 dist 디렉토리가 생성된다.

2. 백엔드 애플리케이션 빌드

스프링부트 애플리케이션을 Gradle을 사용하여 빌드한다:

cd 자신의 백엔드 루트 폴더
./gradlew clean build

 

이 명령어가 성공적으로 실행되면 build/libs 디렉토리에 JAR 파일이 생성된다.

3. Dockerfile 작성

프로젝트 루트 디렉토리 (C:\Users\jypor\Desktop\programing\m_life\M-Life)에 Dockerfile을 작성한다. 이 Dockerfile은 멀티 스테이지 빌드를 사용하여 프론트엔드와 백엔드를 하나의 도커 이미지로 만든다.

 

Dockerfile 상세 설명

# Stage 1: Build the frontend
FROM node:20.14.0 AS frontend-build

WORKDIR /app
COPY reactworkspace/myapp/package*.json ./
RUN npm install
COPY reactworkspace/myapp ./
RUN npm run build

# Stage 2: Build the backend
FROM gradle:7.5.1-jdk17 AS backend-build

WORKDIR /app
COPY backend/build.gradle backend/settings.gradle ./
COPY backend/src ./src
RUN gradle clean build

# Stage 3: Create the final image
FROM openjdk:17-jdk-slim

# Set up the backend
COPY --from=backend-build /app/build/libs/*.jar /app/app.jar

# Set up the frontend
RUN apt-get update && apt-get install -y nginx
COPY --from=frontend-build /app/dist /usr/share/nginx/html

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

# Expose ports
EXPOSE 8080 80

# Copy the start script
COPY start.sh /start.sh
RUN chmod +x /start.sh

# Start the applications
CMD ["/start.sh"]

Nginx란 무엇인가?

Nginx는 고성능 HTTP 서버이자 리버스 프록시 서버다. 특히 정적 파일을 서빙하는 데 최적화되어 있어, 리액트와 같은 프론트엔드 애플리케이션의 정적 파일을 효율적으로 제공할 수 있다. 또한, Nginx는 리버스 프록시로서 백엔드 서버로 요청을 전달하는 역할도 할 수 있다.

Nginx가 필요한 이유

  1. 정적 파일 서빙: 리액트 애플리케이션은 빌드 후 HTML, CSS, JavaScript 파일 등 정적 파일로 구성된다. Nginx는 이러한 정적 파일을 클라이언트(브라우저)에게 빠르게 제공하는 데 최적화되어 있다.
  2. 리버스 프록시: Nginx는 리버스 프록시로서 클라이언트 요청을 백엔드 서버로 전달할 수 있다. 예를 들어, 클라이언트가 /api로 요청을 보내면, Nginx는 이 요청을 스프링부트 애플리케이션으로 전달한다. 이는 보안 및 로드 밸런싱에도 유용하다.
  3. 성능 및 확장성: Nginx는 매우 가볍고 빠르며, 높은 동시 접속 처리가 가능하다. 이는 대규모 트래픽을 처리하는 데 유리하다.

 

Nginx 기본 설정 파일 (nginx.conf)

nginx.conf 파일은 다음과 같이 구성한다. 이 파일은 Nginx의 전역 설정을 포함한다:

user  www-data;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

서버 블록 설정 파일 (default.conf)

Nginx의 서버 블록을 포함하는 default.conf 파일을 /etc/nginx/conf.d/ 디렉토리에 생성한다:

server {
    listen 80;

    location / {
        root   /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }

    location /api {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

 

시작 스크립트 작성

프로젝트 루트 디렉토리 (C:\Users\jypor\Desktop\programing\m_life\M-Life)에 start.sh 스크립트를 작성한다:

#!/bin/bash

# 백엔드 애플리케이션을 백그라운드에서 시작한다.
java -jar /app/app.jar &

# Nginx 서버를 포어그라운드 모드에서 시작하여 컨테이너가 계속 실행되도록 한다.
nginx -g "daemon off;"

 

Docker 이미지 빌드 및 실행

  1. Docker 이미지 빌드
    전체 루트 폴더
    docker build -t my-fullstack-app .

     
  2. Docker 컨테이너 실행
    docker run -d -p 80:80 -p 8080:8080 my-fullstack-app

7. AWS EC2에 Docker 이미지 배포

  1. EC2 인스턴스 생성
    • AWS Management Console에서 EC2 인스턴스를 생성한다. Ubuntu 또는 Amazon Linux를 선택하고 보안 그룹에서 HTTP(포트 80) 및 SSH(포트 22)를 허용한다.
  2. EC2 인스턴스에 접속
    ssh -i /path/to/your-key-pair.pem ec2-user@your-ec2-public-ip

     

  3. Docker 설치
    # Ubuntu
    sudo apt update
    sudo apt install -y docker.io
    sudo systemctl start docker
    sudo systemctl enable docker
    sudo usermod -aG docker $USER
    
    # Amazon Linux
    sudo yum update -y
    sudo amazon-linux-extras install docker
    sudo service docker start
    sudo systemctl enable docker
    sudo usermod -aG docker ec2-user

 

- Docker 이미지 저장

docker save my-fullstack-app -o my-fullstack-app.tar

- SCP를 사용하여 tar 파일 전송

scp -i /path/to/your-key-pair.pem my-fullstack-app.tar ec2-user@your-ec2-public-ip:/home/ec2-user

 - EC2 인스턴스에서 Docker 이미지 로드

docker load -i my-fullstack-app.tar

- Docker 컨테이너 실행

docker run -d -p 80:80 -p 8080:8080 my-fullstack-app

8. 애플리케이션 접속

웹 브라우저를 열고 EC2 인스턴스의 퍼블릭 IP 주소를 입력하여 애플리케이션에 접속한다:

 

이렇게 하면 AWS EC2에 Docker 컨테이너를 배포하고 애플리케이션을 실행할 수 있다. EC2 인스턴스의 보안 그룹 설정에서 HTTP(80) 및 필요한 다른 포트가 열려 있는지 확인해야 한다.

 

오류 원인 및 해결 과정

이번 과정에서 발생한 주요 오류는 다음과 같다:

  1. Nginx 설정 파일 오류:
    • 초기 설정 파일에서 user nginx; 지시어가 문제가 되어 getpwnam("nginx") failed 오류가 발생했다. 이는 "nginx" 사용자가 존재하지 않아 발생한 오류다.
    • 해결 방법: nginx.conf 파일에서 user nginx; 지시어를 user www-data;로 변경했다.
  2. Nginx 서버 블록 위치 오류:
    • nginx.conf 파일에 server 블록이 포함되어 있어 server directive is not allowed here 오류가 발생했다.
    • 해결 방법: server 블록을 별도의 설정 파일(default.conf)로 분리하여 /etc/nginx/conf.d/ 디렉토리에 위치시켰다.

이러한 과정을 통해 Nginx 설정 파일을 올바르게 구성하고 Docker 컨테이너를 다시 실행하면 문제가 해결된다. 문제가 지속되면 추가 로그를 확인하여 더 자세한 진단을 진행한다.

이상으로 리액트와 스프링부트 애플리케이션을 하나의 도커 컨테이너에 담아 AWS EC2에 배포하는 과정을 마친다. 이 글을 통해 처음 도커와 AWS EC2를 사용하는 사람들도 쉽게 따라할 수 있기를 바란다.

 
 

'클라우드서비스' 카테고리의 다른 글

[Cloud] AWS EC2  (0) 2023.12.28
5. 도커 이미지 만들기  (0) 2023.10.03
4. Redis를 이용하여 컨테이너 실행  (0) 2023.10.01