본문으로 건너뛰기

카페인팀 서버 아키텍처를 설명해드리겠습니다

· 약 11분
누누

안녕하세요 우아한테크코스 카페인팀 누누입니다

이번에 카페인 팀에서 배포 아키텍처를 결정하게 되었던 과정에 대해서 정리를 해보고 싶어서 글을 쓰게 되었습니다.

아키텍처와 서버가 배포되는 과정을 보여드리면서 시작하도록 하겠습니다

배포 아키텍처

서버가 배포되는 과정은 다음과 같습니다.

server image

우아한테크코스 인스턴스에 대한 소개

우테코에서 선택할 수 있는 인스턴스는 총 2가지 종류입니다.

  1. 퍼블릭 서브넷에 있는 인스턴스
    • 캠퍼스에서만 SSH 접근이 가능한 인스턴스입니다.
    • 미리 열려있는 포트들만 허용이 되어 있습니다.
    • 같은 서브넷에 있는 인스턴스끼리는 모든 포트가 허용되어 있습니다
  2. 프라이빗 서브넷에 있는 인스턴스
    • 퍼블릭 서브넷에 있는 인스턴스를 통해서만 접근이 가능합니다.
    • 같은 서브넷에 있는 인스턴스끼리는 모든 포트가 허용되어 있습니다.

1번 인스턴스를 2개 사용 가능하고, 2번 인스턴스를 1개 사용 가능합니다.

권장되는 환경에서 1개는 db 서버로 사용하고, 나머지 2개는 자유롭게 사용이 가능했습니다.

그전에 알면 좋아요

여기서는 Self Hosted Runner를 사용했는데요.

Self Hosted Runner에 대한 내용은 여기 에 잘 나와있습니다.

외부 IP로부터 SSH 접근이 불가능하기에, Self Hosted Runner 나, Jenkins 같은 방법을 사용할 수 있었는데, 러닝 커브를 고려해서 Self Hosted Runner를 선택하게 되었습니다.

배포 아키텍처에 대한 고민

저희 팀이 이번 아키텍처를 만들기 위해서 고민했던 점들은 다음과 같습니다.

  1. 어떻게 하면 장애의 영향을 최소화할 수 있을까?
  2. 운영 서버를 나중에 추가하게 되었을 때, 어떻게 중복으로 관리되는 부분을 최소화할 수 있을까?
  3. 2차 데모데이까지의 과제인 개발 서버를 어떻게 구성할 수 있을까?

여기서 1번을 가장 먼저 생각한 아키텍처를 구성하게 되었는데, 다음과 같습니다.

선택의 기준이 되었던 것은 총 3가지였습니다.

  1. DB는 프라이빗 서브넷에 위치시키고, 우리 인스턴스를 거쳐서만 접근이 가능하게 한다.
    • 이 부분은 보안을 위해서 어쩔 수 없이 선택하게 된 부분입니다.이 부분을 고려하다 보니, 최소한으로 구성할 수 있는 구조가 db 용 private 인스턴스 1개, 그리고 우리가 사용할 public 인스턴스 1개가 됩니다
  2. 운영 서버를 나중에 추가하게 되었을 때, 어떻게 중복으로 관리되는 부분을 최소화할 수 있을까?
    • 개발용 인스턴스에 CD 툴이나, 모니터링 툴을 설치하게 되면, 운영 서버에도 동일하게 작업을 해야 합니다.
    • 이 부분을 최소화하기 위해서, 개발용 인스턴스와, CD 툴, 모니터링 툴을 설치한 인스턴스를 분리하게 되었습니다.
  3. 어떻게 하면 장애의 영향을 최소화할 수 있을까?
    • 개발용 인스턴스와, CD 툴, 모니터링 툴을 설치한 인스턴스를 분리하게 않는다면 개발용 인스턴스에서 장애가 발생했을 때, CD 툴과 모니터링 툴에도 영향을 미치게 됩니다. 이 부분을 생각했을 때도, 개발용 인스턴스와, CD 툴, 모니터링 툴을 설치한 인스턴스를 분리해야 한다고 결정하게 되었습니다
    • 한 부분의 장애가 다른 툴까지 사용할 수 없게 만들게 되어서, 롤백이나, 상황 파악을 하기 힘들게 만들게 됩니다.

이런 과정들을 생각했을 때, 인스턴스 1개를 개발 서버용으로, 인스턴스 1개를 CD 툴과 모니터링 툴을 설치한 인스턴스로 사용하게 되었습니다.

실제 내부 구성은 어떻게 될까요?

개발 서버

이 인스턴스에는 총 2가지 기능이 들어가 있습니다.

  1. 프론트 서버
    • react로 되어있는 프론트엔드 코드를 사용자에게 전달해 주는 역할을 합니다.
  2. 백엔드 서버
    • spring으로 되어있는 api 서버입니다.

물론, 이렇게 하면 두 곳 중 한 곳에 장애가 발생했을 때, 프론트 서버와 백엔드 서버가 모두 영향을 받게 됩니다.

같이 관리하게 된 첫 번째 이유로 비용이 들기 때문에 비용의 문제를 고려하게 되었습니다. 개발 서버에서 프론트 서버와 백엔드 서버를 관리하게 되었습니다.

두 번째 이유로는, 아직 프로젝트 초창기 이기 때문에, 백엔드에서 장애가 났을 때, 프론트에서 일정 이상의 에러 처리가 불가능했습니다.

프로젝트가 많이 진행되었다면, 프론트엔드만으로 혹은 장애가 나지 않은 서버를 활용해 에러 처리를 할 수 있지만, 아직은 그런 기능을 구현하지 못했습니다.

이와는 별개로 실행 시 편의를 위해서 도커를 사용해 개발 서버를 관리하고 있습니다.

CD 툴과 모니터링 툴

이 인스턴스에는 총 3가지 기능이 들어가 있습니다.

  1. CD 툴
    • 위에서 설명드린 것처럼, self hosted runner 가 동작하게 되어있습니다
  2. 보안을 위한 리버스 프록시
    • 저희 프로젝트에서 구글 지도를 사용하게 되는데, 이때 API 키를 사용하게 됩니다. 이렇게 하면, API 키를 노출시키지 않고, 사용할 수 있습니다.
    • 이 API 키를 노출시키지 않기 위해서, 리버스 프록시를 하나 두고, 여기서 API 키를 추가해 요청을 보내는 방식으로 구성하게 되었습니다.
  3. 모니터링 툴
    • 저희 프로젝트에서 아직 도입하지 않았지만, 현재 이슈로는 올라가 있는 상태입니다.
    • Actuator, 프로메테우스, 그라파나 이 3가지를 활용해서 모니터링 툴을 구성하게 될 예정입니다

위 기능들이 한 인스턴스에 모여있기에, 위의 기능들은 추후에 운영 서버가 추가되었을 때, 중복으로 관리하지 않아도 됩니다.

배포 과정 더 자세히 알아보기

아래에 사진에서 보이는 과정을 통해서 배포를 진행하고 있는데요

server image

  1. 사용자가 push를 하면, github actions에서 도커 빌드를 진행하고, 도커 허브에 이미지를 올립니다.
  2. 도커 허브에 이미지가 올라간 이후에, self hosted runner 가 작동을 시작합니다.
  3. 개발용 인스턴스에 접근해서, 이미지를 받고, 컨테이너를 실행합니다.

이런 과정을 통해서, 개발용 인스턴스에 배포를 진행하고 있습니다.

느낀 점

좋은 아키텍처를 설계하기 위해서는 고려해야 할 점들이 정말 많다는 것을 다시 한번 느꼈습니다.

운영 서버가 추가된다던가, 인스턴스가 늘어나고, 줄어드는 상황에 유연하게 대처할 수 있도록 설계를 해야 한다는 것을 다시 한번 느꼈습니다.

중복으로 관리될 포인트를 줄여야 한다는 것도 다시 한번 느낄 수 있었고요

긴 글을 읽어주셔서 감사합니다