LIKET - 개발용 서버 구축하기

민경찬·2024년 7월 7일
18

백엔드

목록 보기
18/20
post-thumbnail

안녕하세요. LIKET 팀의 백엔드 개발을 담당하고 있는 민경찬입니다. 이번에는 LIKET 팀에서 필요한 개발 서버를 어떻게 구축했는지, 또 어떻게 운영하고 있는지 얘기해보려고 합니다.


❓ 개발 서버는 왜 필요한가요?

개발 서버가 있으면 다음과 같은 장점이 있습니다.

  1. 프로덕션에 올리기 전 QA 진행에 용이
  2. 프론트 개발 편이성 상승

프로덕션 환경에서 테스트 해본다는 것은 정말 위험합니다. 어떤 문제가 발생할지 모르기 때문이죠. 그래서 기존 서비스에는 영향을 미치지 않는 새로운 서버에서 자유롭게 테스트할 수 있습니다.

프론트 코드를 개발하는 것에 있어서도 API를 직접 호출해볼 수 있기 때문에 매우 편리해집니다.

그러나 개발 서버를 만드는 것에도 많은 고민이 필요합니다.

위 이미지는 프로덕션 인프라입니다. 테스트를 위해 개발 서버를 프로덕션 인프라와 동일하게 구현하면 불필요한 비용이 발생합니다.

🤔 개발 서버는 어때야하나요?

개발 서버는 개발용이기 때문에 프로덕션 상황보다 현저하게 트래픽이 적습니다. 따라서 프로덕션 환경에서의 고가용성 있는 서버를 구축할 필요가 없습니다.

또한 안전할 필요가 없습니다. 백엔드 코드 실수로 인하여 서버가 다운되더라도, 개발용 DB에 삭제되어서는 안되는 데이터가 삭제되더라도, 그저 다시 올려주기만 하면됩니다. 어떤 문제가 발생하더라도 치명적이지 않다는 것이죠.

정리해보면 다음과 같습니다.

  1. 컴퓨팅 파워가 낮아도 상관없다.
  2. 서버가 다운에 대한 안전장치가 필요하지 않다.

이제 개발 서버만의 특징을 잘 살려 개발 서버를 구축하는 방법들에 대해서 알아보겠습니다.


🤔 개발 서버를 구축하는 방법은 무엇이 있나요?

개발 서버를 구축하는 방법을 크게 3가지로 분류하였습니다. LIKET 팀에서는 모두 시도해본 방법들입니다.

  1. 로컬
  2. 온프레미스
  3. 클라우드

하나씩 알아보겠습니다.

1. 로컬 개발 서버

로컬 개발 서버란 API를 사용하려는 로컬 환경에서 서버를 구축하는 것을 의미합니다. 그러면 프론트 개발자가 DB셋팅도 다 해야하고 Nest.js 코드도 띄워야하는 걸까요? 아닙니다.

LIKET 팀에서는 Docker Compose를 이용하여 모든 서버 환경이 구축되도록 설정하였습니다.

Dockerfiledocker-compose.yml을 만들어 Nest.js서버가 정상적으로 작동할 수 있는 환경을 구현하였습니다.

init.sql에는 DB 셋팅이 전부 담겨있습니다. 계정과 테이블 설정부터 시드 데이터까지 모두 포함되어 있습니다.

docker compose \
	-p liket-mobile \ 
	-f dev-deploy/docker-compose.yml \
    up -d \
    --build --force-recreate

위 명령어 한 줄이면 API 서버가 열립니다. 하지만 이것도 복잡합니다.

package.json

"scripts": {
	"dev-deploy:up": "docker compose up...",
    "dev-deploy:down": "docker compose down..."
}

이제 npm run dev-deploy:up 명령어 한 줄이면 로컬에서 API 서버를 실행할 수 있습니다.

그러나 이 방식에도 치명적인 단점이 있습니다.

  1. 로컬에서 환경변수 필요
  2. 코드 변경마다 pull로 가져와야함
  3. 빌드 속도 느림

환경 변수에는 AWS관련 키를 포함하고 있어야 합니다. 그러나 키를 공유하는 것은 위험하다고 판단하였고 몇몇 API는 개발 서버에서 사용하지 않는 것으로 결정하였습니다.

또한 백엔드 코드가 수정될 때 프론트에서 매번 pull 명령어로 코드를 가져오는 것은 번거로운 작업입니다.

docker build 명령어는 꽤나 오래 걸립니다. 맥북 m1 pro 기준으로도 30초 조금 넘게 걸립니다. 개인 노트북 스펙이 빌드를 하기에 충분하지 않아 빌드에 실패하는 경우도 생겼습니다.

첫 빌드는 훨씬 더 오래걸립니다.

그러나 로컬 개발 서버는 그 어떤 서버 컴퓨터도 추가적으로 필요하지 않아 서버 비용이 무료입니다.

그러나 위 3가지 단점은 저희에게 치명적이였습니다. 개발도 불편하고 특정 기능은 테스트 해 볼 수도 없었죠. 다른 방법을 찾아야했습니다.

2. 온프레미스 개발 서버

개인 컴퓨터에 Ubuntu를 설치한 후 포트포워딩을 통해 연결하여 API 서버에 접근할 수 있도록 할 수 있습니다. (개인 컴퓨터를 이하 개인 서버로 칭하겠습니다.)

이 방법은 트래픽이 현저히 적은 개발 상황에서 너무나도 유용합니다. 개인 PC는 한 두명의 트래픽을 감당하기에 너무나도 충분한 스펙을 가지고 있기 때문이죠.

그러나 이 방법에도 치명적인 단점은 존재했습니다.

이미 개인 서버에는 너무나도 많은 개발 서버가 띄워져있다는 것이죠.

80포트와 443포트는 이미 다른 서버가 점유하고 있었습니다. HTTPS 프로토콜은 포기할 수 밖에 없었고 3003번 포트를 사용하였습니다.

Nginx를 이용하여 서버를 분배하는 것도 좋은 방법일 것입니다. 그러나 API서버가 너무 많다보니 다른 서버의 API가 호출된다던지 하는 문제가 발생하였습니다. 디버깅도 쉽지 않았죠. 서로 다른 도메인을 사용하는 것도 이 상황에서는 쉽지 않을 겁니다.

그러나 CORSMix-content문제가 발생하고 말았습니다.

  • CORS: Origin이 다른 경우 자원 공유를 브라우저 차원에서 차단
  • Mix-content: 프론트 페이지는 https프로토콜이지만 백엔드 API는 http 일 경우 차단

크롬 브라우저는 엄격했습니다. 백엔드 API서버와 HTTPS로 통신하지 않는다면 쿠키를 차단하더라구요. 치명적이였습니다. 로그인이 이루어지지 않기 때문이죠.

이 방법도 로컬 환경과 비슷하게 비용이 거의 나가지 않았습니다. 프론트 개발자 입장에서도 그저 연결만 하면 되니 로컬보다 훨씬 편합니다.

그러나 브라우저 보안 정책에 의해 테스트는 더욱 어려워졌고 프록시나 리버스 프록시 등의 방법을 사용해야만 했습니다. 리버스 프록시는 비용이 발생한다는 문제점이 있으며 프록시는 프론트 개발에 번거로움이 추가되며 프로덕션 환경과 멀어진다는 단점이 발생합니다.

다른 해결책이 필요한 것이죠.

3. 클라우드 개발 서버

어쩔 수 없이 한달에 만원을 내고 t3.micro를 빌리기로 하였습니다. EC2 인스턴스 내에 DB와 Nest.js 서버를 띄웠습니다.

이 경우 앞서 나온 문제점을 모두 해결할 수 있습니다.

  1. HTTPS 프로토콜 사용
  2. 프론트에서 더 이상 백엔드 코드를 볼 일이 없음
  3. HTTPS 사용과 도메인 적용으로 프로덕션과 비슷한 인프라

이제 쿠키도 잘 전달됩니다.

모든 것이 만원으로 완벽하게 해결된 줄 알았습니다. t3.micro가 멈추기 전까지는 말이죠.


💡 t3.micro의 한계 체험하기

1GB 램은 Nest.js서버를 띄우기에 너무나도 충분한 스펙입니다.

그러나 빌드하기에 충분한 스펙은 아니였습니다.

Nest.js서버와 PostgreSQL을 띄운 후 새로운 버전의 Nest.js 서버를 빌드할 때 CPU 크레딧이 전부 소모되어 한 동안 개발 서버가 먹통이 되어버렸습니다.

서버 빌드하기에 충분하지 않다면 서버 스펙을 올리거나 빌드 위치를 변경하면 된다고 생각했습니다.

그러나 빌드를 위해서 t3.small로 서버 스펙을 올리는 것은 불필요한 비용 지출이라고 생각했습니다.

그래서 빌드 작업을 수행하는 것을 다른 컴퓨터에서 진행하는 것으로 결정하였습니다.


💡 최후의 수단 Github Action

로컬에서 빌드하고 올리는 작업은 백엔드 개발자 입장에서 너무나도 번거로운 일입니다.

백엔드 입장에서는 매번 새로운 기능을 개발하고 배포하는 것에 부담이 생기는 것이죠. 자동화를 할 필요가 있었습니다. 최소한의 금액으로말이죠.

LIKET 팀에서는 이를 Github Action으로 해결하기로 결정하였습니다.

name: Build and Deploy Docker Image

on:
  push:
    branches:
      - develop

jobs:
	build: ...build image and push to ECR
    deploy: ...deploy to ec2

ECR을 사용하여 빌드된 이미지를 저장하였고 EC2에서 이를 pull을 땡겨 받아오는 형태로 자동화 하였습니다.

개발 서버를 배포하는 과정이 정말 편해진 순간이였습니다. 개발자는 앞으로 코드 레벨만을 신경쓰면 됩니다.

버그가 있다면 버그를 수정하고 develop 브랜치에 머지하면 됩니다. 개발자가 할 일은 머지하고 기다리기 밖에 없습니다.


⭐️ 결론

배포에 있어서도 현 시점에 가장 어울리는 방법을 선택할 필요가 있습니다.

쿠키를 사용하지 않는 서비스라면 클라우드 환경까지 고려하지 않았을테죠.

최선의 선택지를 고려하여 개발하는 LIKET팀의 백엔드 개발자 민경찬이였습니다.

감사합니다.

0개의 댓글