우선 기능 구현은 잠시 보류하고, CI / CD를 위한 배포부터 먼저 하기로 했다.
배포 구상도는 다음과 같다.

Backend는 EC2에, Frontend는 S3에 배포하고, NginX를 통해 SSL 인증과 사용자의 요청에 따른 프록시 작업을 수행한다.
/api 경로로 들어오는 요청은 Spring 컨테이너로 보내주고, 나머지는 S3으로 보내주게 설정했다.
HTTP 요청이 들어올 경우 HTTPS로 리다이렉트 시켜주도록 설정했다.
Docker 빌드
Backend는 Docker 이미지로 빌드해서 배포했다.
Docker-Compose로 묶은 채로 배포하고 싶었지만, 이미지를 빌드할 때 환경변수를 설정해야 하는데, Docker 이미지는 이를 plain text로 저장한다. 이런 값들은 노출되면 큰일나기 때문에, 환경변수는 서버에 두고 서버에서 환경변수를 통해 이미지를 새로 빌드하는 방식을 선택했다.
FROM openjdk:17-alpine
RUN mkdir -p /usr/app/backend
WORKDIR /usr/app/backend
COPY ./build/libs/*-SNAPSHOT.jar .
ENTRYPOINT [ "java", "-jar", "OpenRoadmaps-0.0.1-SNAPSHOT.jar"]
EXPOSE 8080
위와 같이 jar 파일을 복사해 실행만 해주는 간단한 Dockerfile을 만들어 이미지를 빌드했고, Hub에 배포했다.
https://hub.docker.com/repository/docker/devjaewoo/openroadmaps-develop/general
Docker
hub.docker.com
그 다음 Hub에서 Backend 이미지를 받아오고, Redis와 PostgreSQL과 함께 묶어서 실행하기 위해 docker-compose.yml을 작성했다.
version: "3"
services:
# 세션 저장을 위한 Redis 컨테이너
redis:
image: redis:latest
container_name: redis
# Spring Backend 컨테이너
backend:
image: devjaewoo/openroadmaps-develop:latest
container_name: backend
ports:
- 8080:8080
environment:
- SPRING_JPA_HIBERNATE_DDLAUTO=validate
- SPRING_DATASOURCE_URL=jdbc:postgresql://database:5432/postgres # 내부 네트워크를 사용한다.
- SPRING_DATASOURCE_USERNAME=${DATABASE_USERNAME}
- SPRING_DATASOURCE_PASSWORD=${DATABASE_PASSWORD}
- SPRING_REDIS_HOST=redis
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTID=${GOOGLE_CLIENT_ID}
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTSECRET=${GOOGLE_CLIENT_SECRET}
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTID=${GITHUB_CLIENT_ID}
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTSECRET=${GITHUB_CLIENT_SECRET}
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_REDIRECTURI=https://develop.openroadmaps.co.kr/api/{action}/oauth2/code/{registrationId}
- SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_REDIRECTURI=https://develop.openroadmaps.co.kr/api/{action}/oauth2/code/{registrationId}
- SPRING_OAUTH2_SUCCESSURI=https://develop.openroadmaps.co.kr
- FILE_ROOTDIR=/home/files/
volumes:
- /home/ubuntu/files:/home/files # 파일 볼륨 마운트
depends_on: # Redis, Database 컨테이너가 실행된 이후에 Backend 컨테이너를 실행한다.
- redis
- database
# Postgres DB 컨테이너
database:
image: postgres:latest
container_name: database
environment:
- POSTGRES_USERNAME=${DATABASE_USERNAME}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
volumes:
- ./postgres:/var/lib/postgresql/data:rw
Backend, Redis, PostgreSQL 컨테이너를 묶어서 실행하지 않고 따로따로 실행해도 됐는데, 그럴 경우 컨테이너 관리가 힘들어진다. 또한 컨테이너 간 통신을 위해 포트를 열어놔야 하는데, 보안 관점에서 별로 좋지 않은것 같았다. 환경변수 등록도 번거롭다.
Docker Compose를 사용하면 up / down 명령어로 컨테이너들을 한번에 제어할 수 있고, 컨테이너 간 내부 네트워크를 사용해 외부에선 접근할 수 없기 때문에 해킹당할 위험이 낮아진다. 또한 .env 파일에서 환경 변수를 자동으로 가져오기 때문에 관리도 편하다.
이런 이유로 Docker Compose를 사용했고, 정상적으로 실행되는걸 확인할 수 있었다.

Backend 배포
백엔드는 EC2 컨테이너에 배포했다. 배포 과정에서 한 작업을 간단하게 요약하자면 다음과 같다.
- EC2 Ubuntu 컨테이너 생성
- SSH 키 다운로드 및 보안 그룹 인바운드 규칙 설정
- Elastic IP 할당, 도메인 연결
- SSH 접속 후 초기 세팅
- Docker 설치 및 컨테이너 실행
우선 EC2 컨테이너를 생성하고, 아래와 같이 HTTP / HTTPS 포트를 열여놨다.
학교랑 집 PC의 SSH 접근도 허용으로 설정했다.

그 다음 EC2 컨테이너가 실행될 때마다 IP 주소가 바뀌는걸 방지하기 위해 Elastic IP를 할당하고, 가비아에서 구매한 도메인을 해당 IP에 연결했다.

그 다음 발급받은 SSH 키를 통해 연결하고, Docker 공식 가이드를 따라 Docker 설치를 진행했다.
Install Docker Engine on Ubuntu
docs.docker.com
sudo apt-get -y update
sudo apt-get -y install \
ca-certificates \
curl \
gnupg \
lsb-release
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get -y update
sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo docker run hello-world
이후 docker-compose.yml과 .env 파일을 복사하고, sudo docker compose up을 통해 실행시켜 배포를 완료했다.
Frontend 배포
Frontend는 S3 버킷에 배포했다. 배포 과정이 생각보다 간단했다.
- S3 버킷 생성 및 설정
- React 빌드
- S3 버킷에 빌드 결과물 업로드
아래와 같이 퍼블릭 액세스 차단을 해제하고, 정적 웹 사이트 호스팅을 활성화했다.


그 다음 아래 명령어로 Webpack 빌드를 진행하고,
npm run build
결과물을 업로드해 배포를 완료했다.

Backend, Frontend 각각은 배포됐고, 이제 NginX를 통한 프록시 작업과 SSL 인증을 적용해야 한다.
'Projects > OpenRoadmaps' 카테고리의 다른 글
[OpenRoadmaps] Github Actions를 통한 CI/CD 구축하기 (0) | 2023.03.08 |
---|---|
[OpenRoadmaps] 10. SSL 인증 + NginX Proxy 적용기 (0) | 2023.03.01 |
[OpenRoadmaps] 블로그 카테고리 Unique Constraint 오류 해결 (0) | 2023.02.06 |
[OpenRoadmaps] 8. 블로그 글 작성, 글 뷰어 기능 개발 (2) | 2023.02.05 |
[OpenRoadmaps] 7. 로드맵 뷰어 기능 개발 (0) | 2023.02.05 |