안녕하세요!
이번에는 AWS 비용에서 벗어나는 방법을 소개해드리려고 합니다.
그리고, Docker를 활용하여 웹 서비스를 배포하는 방법도 소개하려 합니다.
서론
최근 진행한 프로젝트를 배포하기 위해 AWS 서비스를 활용했습니다.
해당 프로젝트에서 Elastic Search, Mysql, Next 등 서버 성능이 꽤 필요한 기술들을 활용하였습니다. 그러다 보니 무료 EC2 인스턴스보다는 성능이 보장되는 Medium 이상의 인스턴스를 사용하는 것이 필요했습니다. 결국 비용을 지불하고 Medium 인스턴스로 프로젝트를 배포하였는데요.
하지만 환율 문제로 요금 부담이 점점 커져 갔습니다. 이 비용을 아끼기 위해 개인 서버용으로 미니 PC를 구매하게 되었고, 다행히 팀원이 미니 PC 비용을 부담해 주었습니다.
매달 AWS 요금 8만원 나온 것을 5만원으로 해결한 과정 지켜봐 주세요!
미니 PC 서버 세팅
저희 팀원이 서버 구축 과정에서 진행한 세팅들을 정리해두었습니다.
https://velog.io/@1c2/series/%EA%B0%9C%EC%9D%B8-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%EA%B8%B0
시리즈 | 개인 서버 구축기 - 1c2.log
미니 PC로 우분투 서버를 만들면 재밌을 것 같아서 일단 미니PC를 당근에서 구매했습니다. PC스펙은 대충 > CPU : i5-4210U (1.7GHz) RAM : DDR3 16GB SSD : 128GB 엄청 좋은 스펙은 아니지만 가격이 매우 저렴하
velog.io
먼저 docker에 대해 설명드리려고 합니다.
docker 개념
컨테이너는 서버의 공간을 효율적으로 나누는 기술입니다. 예를 들어, 하나의 큰 건물(서버)이 있을 때, 예전에는 각 세입자가 자기 공간을 갖기 위해 방을 완전히 따로 구분하는 방식(가상 머신)을 사용했습니다. 그런데 이렇게 하면 시간이 많이 걸리고 자원을 낭비하게 되죠.
컨테이너는 마치 세입자가 이동 가능한 컨테이너에 살면서, 필요할 때마다 이 컨테이너를 큰 건물(서버)로 쉽게 옮기는 방식입니다. 이렇게 하면 빠르고 효율적이겠죠.
도커는 이 컨테이너를 쉽게 만들고 관리하는 도구입니다. 즉, 사용자는 도커에게 "컨테이너를 만들어줘"라고 요청하면, 도커가 자동으로 처리해줍니다.
docker의 장점은 다음과 같습니다.
- 컨테이너를 생성할 때, npm, Java 등 버전에 대한 환경 설정을 할 수 있으며, 이를 바탕으로 Docker가 컨테이너를 생성합니다. 그러다 보니 개발환경과 운영환경을 일관되게 할 수 있습니다.
- 도커는 컨테이너끼리 격리된 환경을 제공하기 때문에 하나의 서버에서 여러 애플리케이션을 독립적으로 운용할 수 있게 되었습니다.
그래서 하나의 미니 PC에 여러 서비스를 독립적으로 실행시키기 위해 도커를 활용하였습니다.
docker 설치 전 세팅
docker를 설치하기 전 ubuntu에 필요한 패키지들을 설치해야 합니다.
sudo apt update
먼저 우분투 패키지 목록들을 최신 상태로 업데이트 합니다.
sudo apt install curl
sudo apt install openssh-server
sudo apt install -y curl git wget vim
sudo apt install openjdk-17-jdk
- curl → HTTP API 요청 테스트 및 파일 다운로드를 위해 설치합니다
- openssh-server → MobaXterm으로 원격 서버에 접속하기 위해 설치합니다.
- git → 버전 관리 및 소스 코드 관리에 필요한 git 명령어를 사용하기 위해 설치합니다
- vim → 서버에서 파일을 편집할 수 있도록 vi 편집기를 설치합니다.
- java → 프로젝트에서 사용했던 java version을 설치합니다.
docker 설치
필요한 패키지를 설치한 후, 이제 mobaxterm 툴을 사용하여 원격 서버에서 작업을 진행합니다.
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo systemctl status docker
sudo docker run hello-world
docker -v
docker compose version
다음과 같은 명령어로 docker를 설치하고 version을 확인하여 제대로 설치가 되었는지 확인합니다.
git으로 레파지토리 clone
git clone {repo 깃 주소}
git clone으로 repository를 가져옵니다.
docker로 mysql, elasticsearch 설치
springboot로 만들어진 백엔드에서 MySQL, Elasticsearch 애플리케이션 설정이나 의존성 때문에 먼저 MySQL, Elasticsearch를 설치해야하는데요
sudo docker run -d -p 3306:3306 mysql --name mysql
sudo docker run --network=back -d --name els -p 9200:9200 -p 9300:9300 docker.elastic.co/elasticsearch/elasticsearch:8.10.0
- docker run → 로컬에 없으면 먼저 설치를 하고 실행을 하게 됩니다.
- -d → 컨테이너를 백그라운드에서 실행하도록 지정합니다.
- -p 3306:3306 → 호스트 3306번 포트로 접근하면 MySQL 서비스가 실행되는 Docker 컨테이너 3306로 전달됩니다.
- --name mysql → 컨테이너에 이름을 지정하여 쉽게 관리할 수 있습니다.
- mysql → Docker hub에서 사용할 이미지를 지정합니다.
- -network=back → Docker 네트워크를 지정합니다. 이렇게 하면 back이라는 네트워크 내에 있는 컨테이너 끼리 서로 통신을 할 수 있습니다. 즉, spring과 elasticsearch가 서로 통신을 할 수 있게 됩니다.
backend 도커 파일 만들기
먼저 Dockerfile은 어떤 환경에서 실행되어야하는지 어떻게 이미지를 만들 것인지 설정하는 파일입니다. docker는 이 file을 기반으로 이미지 빌드가 시작됩니다.
즉 dockerfile만 있으면 개발환경이든, 운영환경이든 같은 환경에서 개발이 가능합니다.
FROM openjdk:17
ARG JAR_FILE=build/libs/*SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","app.jar"]
제가 작성한 dockerfile입니다.
먼저, Dockerfile에서 Java 17을 기본 환경으로 설정합니다. 그런 다음, 애플리케이션이 빌드된 JAR 파일을 Docker 컨테이너 내부로 복사한 후, 컨테이너가 시작될 때 해당 JAR 파일을 실행하도록 설정합니다.
backend 도커 실행하기
먼저, Dockerfile을 작성한 후에는 백엔드 서버 이미지를 생성해야 합니다.
그 전에, MySQL 데이터베이스를 먼저 생성하고, 초기 데이터를 넣기 위해 DUMP 파일을 실행합니다.
그다음, Elasticsearch의 설정 파일인 elasticsearch.yml에서 보안을 비활성화 (xpack.security.enabled: false)로 설정합니다. 이렇게 설정하는 이유는, 서버 내에서만 통신이 이루어지기 때문에 HTTPS 설정을 따로 적용할 필요가 없기 때문입니다.
설정을 모두 마쳤다면 docker로 이미지 생성하고 실행합니다.
sudo docker run -d -p 8080:4040 --name backend --network back \
-e SPRING_DATASOURCE_URL=${데이터베이스 연결 URL} \
-e SPRING_DATASOURCE_USERNAME=${사용자이름} \
-e SPRING_DATASOURCE_PASSWORD=${비밀번호} \
-e SPRING_DATASOURCE_DRIVER_CLASS_NAME=${드라이버 클래스} \
backend
- -p 8080:4040 → 호스트 8080번 포트로 접근하면 백엔드 Docker 컨테이너 4040으로 전달됩니다.
- --name backend→ 컨테이너에 이름을 지정하여 쉽게 관리할 수 있습니다.
- -network=back → Docker 네트워크를 지정합니다. 이렇게 하면 back이라는 네트워크 내에 있는 컨테이너 끼리 서로 통신을 할 수 있습니다. 즉, spring과 elasticsearch가 서로 통신을 할 수 있게 됩니다.
- e → 컨테이너 내에서 사용할 환경 변수를 지정합니다.
frontend 도커 파일 만들기
마찬가지로 도커파일로 개발환경과 운영환경 세팅을 맞춰줍니다.
# Step 1: Node.js 환경에서 Next.js 앱 빌드
FROM node:18-alpine AS build
# 작업 디렉토리 설정
WORKDIR /app
# package.json 및 package-lock.json 복사
COPY package.json package-lock.json ./
# 종속성 설치
RUN npm install
# 프로젝트 파일 복사
COPY . .
# Next.js 빌드
RUN npm run build
# Step 2: Node.js 런타임 환경으로 설정
FROM node:18-alpine
# 작업 디렉토리 설정
WORKDIR /app
# 빌드 결과물 및 Node.js 환경 필요 파일 복사
COPY --from=build /app /app
# 포트 설정
EXPOSE 3000
# Next.js 애플리케이션 실행
CMD ["npm", "run", "start"]
먼저 build를 먼저 하고 build 된 파일을 front 도커에 복사하여 3000번 포트로 실행합니다.
frontend 도커 실행하기
sudo docker run --name frontend run -d -p 3000:3000 frontend
다음과 같이 도커를 실행해줍니다.
nginx 설치 및 설정
마지막 단계입니다. 이제 Nginx와 Certbot을 설치하여 실제 웹 서버를 운영합니다.
sudo apt install nginx
// certbot 설치를 위한 패키지관리자 업데이트
apt-get update
apt-get install software-properties-common
add-apt-repository universe
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install certbot python3-certbot-nginx // certbot 설치
certbot --nginx -d www.withme.my // certbot 실행
먼저 nginx,와 certbot을 설정해서 HTTPS 세팅을 마칩니다.
그리고 nginx 설정을 합니다.
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name www.withme.my;
location /_next/ {
proxy_pass http://localhost:3000/_next/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /api/ {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
#... 이처럼 proxy 서버 설정
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/www.withme.my/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/www.withme.my/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.withme.my) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name www.withme.my;
return 404; # managed by Certbot
}
proxy 설정 및 ssh 설정을 합니다.
'project > etc' 카테고리의 다른 글
setInterval로 DB 갱신 여부, WebSocket으로 개선하기 (0) | 2025.02.25 |
---|---|
페이징 쿼리 성능 개선 (1) | 2025.02.19 |
최단 경로 성능 개선 (0) | 2025.02.19 |