1단계. EC2 Docker Compose 기반 초기 배포 설계 - 100-hours-a-week/KTB4-17th-wiki GitHub Wiki

V1 서비스 규모 및 인프라 설계

1. 서비스 정의

앱 종류 : 소개팅 앱

우리 서비스의 타켓층 : 20-30대

우리 서비스의 핵심 서비스:AI 연습대화 (매칭 성공률 높여주기)

1일 사용 시간 : 10~12분

주 사용시간(peck time) : 오후 8~10시사이

예상 DAU :1775명 예상 MAU :2795명 예상 평균 RPS :6.2 예상 피트 RPS :33.7

v1기능 : 1:1채팅 (사람-사람),내 페르소나 대화 (ai-ai),연습 대화 (ai-사람),알림,카카오톡 소셜로그인,마이페이지

인프라 팀 상황: ‘미러’라는 ai 소개팅앱이 26년 7월에 출시되었는데 시장을 이기고 ‘틴더’처럼 시장을 독점하고 싶다. 시장을 독점하기 위해 사용자가 필요했고 우리는 마케팅 비용에 대부분의 비용을 지출해서 돈이 없다. 인프라 비용을 최소한으로 가져가지만 적어도 유저들이 접속했을 때, 서버에 장애가 났을 경우 아무리 못해도 화면이라도 보여주고 싶다.


2. 초기 서비스 규모 정의

2-1. 예상 사용자수

마케팅 후 사용자 수

항목 값
여성 고객 유입을 위해서 2주동안 200만원을 마케팅 비용으로 썼을때 예상되는 유입 사용자 1425명
마케팅 후 총 MAU 2795명
마케팅 후 총 DAU 1775명
마케팅 전 dau/mau = 870/1370 = 63.5%
마케팅 후의 dau = 마케팅 후의 mau x 63.5% = 2795 x 63.5% = 1775
마케팅 후의 1일 평균 RPS = DAU * 1인당 평균 접속수 * 세션당 api 요청 횟수 / 86400
            = 1775 * 6.08 * 50 / 86400 = 6.245
예상 유저 흐름
유저 목록 조회 4회 (10명씩 페이지네이션 했다고 가정 총 40명을 스와이프 함)
  ↓
유저 프로필 상세 조회 15회 (가정치)
  ↓
그 중 좋아요 등록 12회 (좋아요 누를 확률이 30% 라는 자료 존재)
  ↓
매칭 생성 4회 (매칭이 생성될 확률 35%라는 자료 존재)
  ↓
채팅 api 15회 (가정치)
────────────────────────────────
합계 = 50
기능별 예상 api 읽기/쓰기 횟수 비율 읽기:쓰기 =7:3
기능 읽기 쓰기
로그인 1 1
온보딩 9 3
마이페이지 2 0
프로필 정보 수정 1 2
알림 2 1
페르소나 관리 6 3
차단 2 1
데이터 관리 2 1
채팅 목록 1 0
사람과의 채팅 2 1
AI와 AI 채팅 3 1
사람과 AI 채팅 2 1
대화 정리 위임 4 2
좋아요 3 2
메인 4 1
관상 매칭 4 1
사주 3 1
읽기 : 쓰기 = 7:3 49 22
마케팅 전 초기 사용자
항목 값 근거
MAU 1370명 초기 사용자는 개발자들의 지인으로 충성 고객이다.
DAU 870명 글램 DAU user 1% 벤치마킹
1인당 일평균 앱 실행 횟수 6.08회 큐피스트(글램 회사)
세션당 api 요청 횟수 50회 로그인, 온보딩 제외 (최초 1회만 하기 때문)

1일 평균 RPS

1일 평균 RPS = DAU * 1인당 평균 접속수 * 세션당 api 요청 횟수 / 86400
             = 870 * 6.08 * 50 / 86400
             = 3.02
여성 고객 1명당 발생하는 마케팅 비용 : 7000원
- Liftoff의 데이팅 앱 광고 분석에 따르면 여성 유저 획득 비용은 $3.02이며, 여성 유저의 설치→회원가입 전환율은 60.5%였다. 이를 기반으로 여성 회원가입자 1명의 CPA를 약 $4.99로 추정하였다. 따라서 여성 신규 가입자 340명을 확보하기 위한 광고비는 약 $1,697(약 238만원, $1=1,400원 가정)으로 추정한다. - 소개팅 앱의 남여 성비 8:2비율 유지 , 여성 유저 1명당 남성 고객 4명 유입. (총 7000원에 5명이 유입된다고 가정)

출처: https://link.springer.com/article/10.1007/s40685-015-0018-z?utm_source=chatgpt.com

시장조사
  • 사용 연령대 : 25-44세가 데이팅 앱의 83~95%임.
  • 대부분은 직장인이기 때문에 피크 타임 평일 9-6시 제외.
틴더
  • 25년 8월 사용자수 사용자수 105115명
  • 2024년 기준 공식 틴더 블로그 기준 오후 9~10시피크 타임. 발렌타인 데이 직전 매칭수 10프로 증가. 좋아요 3천만건 증가→ 전체 17%증가 .
  • 25년 8월 기준 일 평균 사용시간 12분 ~13.5분 사용
글램
  • 22년도 DAU 글램 : 8만 6849명
  • 25년 8월 사용자수 77482명
  • 인당 사용 월 평균 시간 2시간 20분~40분
  • 25년 8월 기준 일 평균 사용 시간 : 8.9~12.55분
  • 스타트업 초기 아는 선후배 500명에게 연락해 사용자 확보
큐피스트
(글램 회사)
  • 1인당 일평균 앱 실행 횟수 : 6.08회 (여성 하루 평균 6.33회, 남성 5.84회 접속)
출처

2-2. 예상 Peak Traffic

  • peak time의 20~22시 사용자 45%가 동시 접속기준
피크 계수 = 피크 시간대 사용자 동시 접속율 * 24시간 / 1인당 하루 사용시간
         = 0.45 * 24 / 2
         = 5.4
구분 산식 피크 RPS
마케팅 전 평균 RPS × 피크 계수 = 3.69 * 5.4 19.9
마케팅 후 평균 RPS × 피크 계수 = 6.24 * 5.4 33.7
출처
kleo라는 데이팅 어플 공식 블로그
  • 피크 오후 8~10시 (일일 이용자 45%)
  • 1월 2주 동안 활성 사용자수 150%증가
2024년 기준 공식 틴더 블로그
  • 오후 9~10시피크 타임. 발렌타인 데이 직전 매칭수 10프로 증가. 좋아요 3천만건 증가→ 전체 17%증가.

2-3. 배포빈도

DORA

지표 정의 목표
배포 빈도 프로덕트 환경에 출시하는 기간. 정기 배포: 2주에 한번, 총 3회 (v1, v2, v3)
리드 타임 커밋에서 배포까지 걸리는 시간 1시간이내
평균 복구 시간 서비스 중단이 발생할 떄 팀이 서비스를 복원하는데 걸리는 평균 시간. 1시간 이내
변경 실패율 가동 중지 시간, 서비스 저하, 롤백 상황 15%안쪽 목표
개발 서버 배포 목표
  • v1기준 총 14주 동안 총 11회 진행.
회차 배포 기준
배포 1회차 카카오 로그인, 온보딩 -대화 업로드 : ai기능 통합전
배포 2회차 온보딩 -AI정면 인식 통합후
배포 3회차 메인 화면 구현 완료후
배포 4회차 좋아요 구현 완료 후
배포 5회차 채팅 목록 완료
배포 6회차 사람-사람과 채팅 구현에서 사진 보내기 전구현후
배포 7회차 사람-사람과 채팅 구현에서 재전송, 알림 기능 완료, 더보기 기능 완료 후
배포 8회차 ai와 ai대화 리포트 완료후
배포 9회차 연습 대화 구현 완료 후
배포 10회차 마이페이지 목록 구현 완료후
배포 11회차 마이페이지 알림 기능 구현 완료 수

2-4. 서버 구성요소

CSP 선택 이유

우리 서비스의 상황


우리 서비스는 이제 막 시작한 스타트업이다. 유저를 모으기 위해 마케팅에 대부분의 비용을 사용했기 때문에 **인프라에 사용할 수 있는 돈이 많지 않다.**

따라서 첫 배포에서는 **핵심 AI 기능인 연습 대화가 죽지 않을 정도의 안정성을 확보하면서도 비용을 최소화할 수 있는 인프라 구성**이 필요하다.

다른 애플리케이션의 장애가 ai 서버로 전파되지 않도록 ai 서버를 따로 분리할 예정이고, 정확한 설계가 나오지는 않았지만, 기존에 고려했던 하나의 ec2 안에 모든 애플리케이션을 넣는 설계보다 인스턴스의 개수가 늘어날 예정이기 때문에 인스턴스의 가격이 중요할 것이라고 생각했다.

클라우드 플랫폼 비교

GCP

GCP의 Compute Engine은 동일 스펙 (v1 기준 목표로 잡고 있는 vcpu 2, mem 4Gib) 기준 AWS EC2보다 비싸다.

  • GCP Compute Engine: 월 약 55달러
  • AWS EC2: 월 약 30달러

또한 GCP는 AWS보다 리전이 상대적으로 적어, 다른 하드웨어 시리즈를 사용하고 싶어도 서울 리전에서 제공되지 않는 경우가 많다.

그렇다면 KT Cloud나 NCP 같은 국내 클라우드 플랫폼을 사용할 수도 있지만 동일 스펙 기준:

  • KT Cloud: 월 약 7.7만 원
  • NCP: 월 약 7만 원
  • AWS EC2: 월 약 30달러 ≈ 4만 원

수준으로 AWS가 더 저렴하다.

무엇보다 위의 단점들을 감수하면서까지 우리 서비스가 GCP를 선택해야 할 강점이 없다.

GCP가 강점을 가지는 강력한 데이터 분석이나 BigQuery 등의 기능도 현재 우리 서비스에서는 중요하지 않은 기능이다.

또한 GCP 무료 크레딧에는 별도의 SLA 99% 보장이 없다.

스타트업 크레딧 비교

사실 일반 사용자라면 AWS를 선택할 이유가 크지 않을 수도 있다. 하지만 우리는 초기 스타트업이고 인프라에 사용할 수 있는 돈이 부족하다.

AWS는 AWS Activate Founders를 통해 초기 단계 스타트업에게 1,000달러의 크레딧을 1년간 사용할 수 있도록 지원한다.

각 플랫폼의 지원 혜택은 다음과 같다.

  • AWS: 1,000달러 / 1년
  • GCP: 300달러 / 8개월
  • Azure Startup: 1,000달러 / 6~9개월

GCP는 상대적으로 혜택이 적기 때문에 고려 대상에서 제외했다.

따라서 AWS와 Azure 중 하나를 선택할 것이며, 초기 배포 이후 서버를 다른 플랫폼으로 이전하지 않을 계획이기 때문에 크레딧뿐만 아니라 지원 종료 이후의 비용도 중요하다.

AWS vs Azure

AWS와 Azure에서 동일한 성능의 서버를 기준으로 비용을 비교했다.

  • AWS t3.medium: CPU 2개, RAM 4GB → 시간당 0.052달러
  • Azure B2ls_v2: CPU 2개, RAM 4GB → 시간당 0.052달러

서버 가격은 동일하다.

GCP와 마찬가지로 익숙함을 버리고 꼭 Azure를 써야 한다는 강점을 찾지 못했다. (가격, 안정성 등) 따라서 우선 스타트업 크레딧 지원 기간이 더 긴 AWS를 선택하려고 한다.

서버 분리 이유 (서버리스,lamdba고려)

AI 서버의 안정성 높이기

돈이 부족한 상황에서 AI 서버의 안정성은 높이고 싶다.

AI 서버의 안정성이 부족한 것 같은 이유는

금액을 아끼고자 하나의 인스턴스에 다 몰아넣으면 각 애플리케이션의 자원 경쟁으로 인해 AI 서버가 죽을수도 있다고 예상된다.

1. 서버 분리

AI 서버를 분리한다고 생각했을 때, BE와 AI서버의 자원이 분리되어 서로에게 영향을 끼치지 않게 할 수 있으며, 이로 인해 안정성을 챙길 수 있다고 생각했다.

다만 단순히 서버를 분리한다고 해도 백엔드가 단일 장애 지점이 될 가능성이 없어지는 것은 아니지만, 해당 부분을 챙기려면 적어도 하나의 추가 백엔드 인스턴스, 또 그 요청을 최소 2개 이상의 백엔드 인스턴스로 나눠줄 프록시나 로드벨런서가 필요하다고 판단하여 지금 비용 수준에서는 포기해야할 것 같다.

2. 서버리스

서버 분리를 가정해두고 고민을 해보다가, 우리의 기획을 다시 봤다.

V1 목표 기능을 살펴보았을 때, AI의 기능은 2개밖에 없었고, 이마저도 유저당 하루 35회로 제한적으로 운용을 할 계획이였다.

만약 요청량이 적다면, 서버리스로 AI 서버를 분리하였을 때 비용적으로 이득을 볼 수 있지 않을까라는 생각에서 비교를 시작하였다

먼저 살펴본 서버리스 서비스들은 aws lambda, aws app runner, aws ecs, gcp cloud run 이였다.

이 중에서 app runner와 ecs는 scale to zero를 지원하지 않기 때문에 고려사항에서 바로 제외했다.

3. aws lambda 비용 계산

lambda의 비용 구조는 lmabda 호출 횟수 기반 비용 + 작동시간 비용

AI API 사용량 하루 사용량 한달 사용량 한달 작동 시간
35회 (최악, 100% 사용 가정) 62125 1863750 9318750초
24회 (기준, 70% 사용 가정) 42600 1278000 6390000초
17회 (낙관, 50% 사용 가정) 20175 605250 3026250초

512MB 기준

무료티어 40만 GB-s = 실행시간(800000)

6390000 - 800000 = 5590000

→ 단가 계산 하면 46달러 가량 = 한화 약 6.2만원

Image
  • 추가로 네트워크 비용도 발생 (vpc 통신이 아니기 때문)

Cloud Run은 scale to zero 지원하긴 하지만, 멀티 클라우드의 복잡성? 그리고 네트워크 비용 등.. V1에서는 아직 굳이이다. (우린 빠르게 배포해야 한다.)

S3를 사용한 이유

V1에서는 프로필 이미지와 채팅 중 전송되는 이미지를 저장할 스토리지가 필요하다.

이미지를 저장할 수 있는 방법으로 DB, EBS, S3를 고려했다.

선택지 장점 고려한 문제
DB 별도의 저장소를 구성하지 않아도 됨 평균 3MB의 이미지를 지속적으로 저장하면 DB 용량이 빠르게 증가하며, 이미지 데이터와 서비스의 정형 데이터가 함께 저장됨
EBS EC2에서 파일 시스템처럼 사용할 수 있음 EC2에 연결하여 사용하는 블록 스토리지이므로 애플리케이션 서버와 스토리지의 결합도가 높아짐
S3 애플리케이션 서버와 독립적으로 객체 저장 가능 요청 및 데이터 전송에 따른 비용 발생

우리 서비스에서는 이미지가 애플리케이션 서버의 데이터를 하나의 데이터베이스로 관리해야 할 필요성이 없다고 생각했고,

이후 서버가 교체되거나 여러 대로 확장되더라도 동일한 이미지 저장소를 사용할 수 있기 때문에 이미지와 같은 객체 저장에 적합한 S3를 이미지 저장소로 선택했다.

비용관점

사진 데이터를 현재 상태에서 아주 극단적으로 가정했지만 데이터의 양이 많이 때문에 S3를 도입해서 비용을 낮추려고 함. 채팅방에 이전기록에 대한 검색 기능을 제공하지 않기 떄문에 아주 이전 내용을 다시 볼 확률이 낮음. 30일이 지난 데이터는 수명 주기 정책 설정 후 S3 Glacier Instant처럼 저렴한 S3로 이전. 하지만 즉시 조회는 되어야함.

스토리지 클래스 저장 비용
S3 standard 0.023
S3 Glacier Instant 0.004
Cloud Front를 사용한 이유

S3에 이미지를 저장한 이후에는 이미지 조회 트래픽을 어떻게 처리할 것인지를 고려했다.

S3에서 이미지를 직접 조회할 수도 있지만, 이미지가 조회될 때마다 S3 GET 요청이 발생하며 사용자에게 이미지를 전달하기 위한 데이터 전송도 발생한다.

특히 우리 서비스에서 이미지 조회가 가장 많이 발생할 것으로 예상되는 기능은 메인 화면의 사용자 탐색(스와이프) 기능이다.

각 사용자마다 하루에 30번의 스와이프를 한다고 가정했을 때, 유저당 이미지 조회는 최소 30 + a 회 이다. ( 프로필 사진도 한 사람당 여러 개 일 수 있고, 채팅에서도 이미지 전송 및 조회가 있다.)

따라서 dau인 1775에 30을 곱하면 하루 당 최소 5.3만회의 조회 요청이 발생한다. 물론 최소 요청 기준 굉장히 미비한 금액(원화 기준 한달 25 + a)이라 해당 이유만으로는 도입 사유가 부족하다.

또 다른 이유는 조회 패턴이 모든 사용자가 완전히 다른 이미지를 조회하는 구조가 아니라는 것이다.

우리 서비스는 사용자가 설정한 지역을 기준으로 추천 후보를 먼저 필터링하기 때문에 동일 지역의 사용자들은 서로 겹치는 추천 프로필을 조회할 가능성이 매우 높다.

따라서 다음과 같은 요청 패턴이 발생할 것으로 예상했다.

동일 지역 사용자 → 동일한 프로필 추천 → 동일한 프로필 이미지 반복 조회

이러한 특성 때문에 이미지 캐시 적중률을 확보할 수 있을 것이라고 판단했다.

따라서 S3 앞에 CloudFront를 배치하여 자주 조회되는 이미지를 캐싱하고, S3까지 도달하는 요청을 줄이는 동시에 이미지 응답 속도를 높여 사용자 경험을 개선하기 위해 CloudFront를 사용했다.

DB는 분리하는 이유

디스크는 RAM이나 다른 자원보다 상대적으로 느리기 때문에 읽기 쓰기를 같은 서버내에서 사용하면 자원을 많이 쓴다. 현재 서비스의 기능에서 IO요청이 많기 때문에 DB를 같은 서버안에 넣는게 병목이 된다고 판단해 분리하기로 함.

출처 자료 : https://virtunetsystems.com/four-leading-causes-of-storage-io-bottlenecks-in-virtualized-data-centers/

ai와 be를 하나의 인스턴스에 둔 이유

가장 먼저 비용 절감을 생각하고 하나의 인스턴스에 두었다.

그리고 ai의 기능을 살펴보면 요청을 받고 -> 외부 llm api로 요청을 보내고, 돌아온 응답을 다시 백엔드로 전달하는 역할을 하는 것이다.

따라서 ai 서버 자체에서 자원을 많이 사용을 하지 않을 것이라고 생각했고, 별도의 작은 인스턴스를 생성해서 할당해주는 것보다 백엔드와 같이 한 인스턴스에 넣고, 0.5cpu, 500mb 메모리 정도의 자원을 제한해서 할당해주는 쪽이 비용을 절약할 수 있을 것이라고 생각했다.

image

2-5. 예상 인프라 비용

EC2 인스턴스 타입 선정

우리 서비스는 피크 트래픽 패턴이 있는 서비스이기 때문에, 피크 상황에 크레딧을 소모하며 성능을 내는 t 시리즈가 알맞다고 생각했다.

서버의 스펙도 ai+be는 2vCpu와 4GB 메모리로 생각했는데, 이유는 다음과 같다.

be 기본 메모리 사용량 300MB 트래픽 증가에 따른 be의 메모리 사용량 증가 OS 및 Docker 등의 시스템 자원 여유 자원 여기서 고민이 들었던 부분은 x86 아키텍처의 t3와 arm 아키텍처의 t4g 중 어떤 것을 사용할지였는데, 고민이 들었던 이유는 자주 사용했던 t3 보다 t4g가 저렴했다.

medium 기준 각각 한달 약 37달러와 29달러로 한화 약 1.1만원 정도 t4g가 더 저렴했다.

하지만, arm 아키텍처의 특성을 고려해보았을 때, 소프트웨어 호환성이 x86보다 좋지 않았다는 점이 있었고

초기 인프라에서 월 약 1만 원의 비용을 추가로 절감하는 것보다 기존에 사용해 본 경험이 있고 소프트웨어 호환성에 대한 제약이 상대적으로 적은 x86 환경을 사용하는 것이 운영 복잡도를 낮출 수 있다고 판단했다.

따라서 V1에서는 t3.medium을 선택하고, 이후 비용 최적화가 필요한 시점에 t4g로 전환하는 것을 고려하는 편이 좋을 것이라고 판단했다.

CDN:cloudfront 예상 비용 : 1.5USD
  • S3에서 CDN으로 가져오는 요금 : 없음
  • CDN에서 외부로 나갈떄 요금 : 15달러(20550원)
    • 한달전송량 :3MB1775명31장*30일=5TB
    • pro의 요금이 1.5달러이고 50TB라는 전송량이 있기 때문에 5TB기준으로 별도의 과금은 되지 않음.

출처 : https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/flat-rate-pricing-plan.html?refid=6a2236c1-f996-415b-917a-ddc149c871f1#usage-allowance


3. Docker 컨테이너 구성 설계

컨테이너 사용이유 : 가상화
  1. 컨테이너 왜 써야할까? : 현재 인프라 비용이 한정적인 상태라 최대한 주어진 서버 자원을 효율적으로 다 써야 하는 상황이다.여러대의 EC2를 띄워서 자원이 남는 경우를 원하지 않는다. 하나의 서버안에 여러개의 컨테이너를 넣어서 최대한 사용하고 싶어서 사용했다. 1-1 그럼 VM가상화는 안되나 장애 전파도 안되고 오히려 좋은거 아닌가? : VM으로 가상화를 하지 않는 이유는 VM은 컨테이너보다 오히려 자원을 많이 잡아 먹기 때문이다. VM은 2GB의 한도를 줬을 때 메모리가 docker 보다 7.7배 많이 잡아 먹는다. (docker는 0.03GB, VM 0.23GB를 사용 했다고 한다 출처 : https://arxiv.org/pdf/1807.01842)
image

4. Docker Compose 기반 배포 구조 설계

Docker compose를 사용하는 이유

배포를 빠르게 진행해야 하는 초반에 도커 이미지의 변경도 잦아질 것이다.

하지만 배포할 때마다 BE와 AI의 이미지를 각각 교체하기 위해 기존 컨테이너를 종료하고, 새로운 이미지를 받아 컨테이너를 다시 실행하면서 네트워크, 환경변수 등의 설정을 매번 직접 지정하는 것은 비효율적이다. 또한 이런 과정에서 일부 설정을 누락하거나 잘못 적용해 배포 오류가 발생할 가능성도 있다.

따라서 Docker Compose를 사용하여 여러 컨테이너의 실행 방식과 네트워크, 환경변수 등의 설정을 하나의 파일로 정의하였다. 이를 통해 배포 시 동일한 설정을 반복해서 입력할 필요 없이 docker-compose 파일을 기반으로 일관된 설정으로 컨테이너를 실행할 수 있도록 구성하였다. (설정이 바뀔 때에도 용이하다)

version:

services:
  backend:
    image: <ECR_URI>/backend-17:<commit-sha> # 이미지 저장소는 ECR, 태그는 Git Commit SHA 사용
    ports:
      - "8080:8080" # 외부 요청은 백엔드 8080만 노출
    restart: unless-stopped # 재시작 정책
    env_file:
      - .env # 노출 여부 구분 없이 전부 서버 내부 .env 파일로 관리
    networks:
      - app # 사용자 지정 브릿지 네트워크 
  ai:
    image: <ECR_URI>/ai-17:<commit-sha>
    restart: unless-stopped
    env_file:
      - .env
    networks:
      - app

networks:
  app:
    driver: bridge
1.Network

백엔드와 AI 애플리케이션 컨테이너가 하나의 EC2 인스턴스에 들어가 있는 구조이고, AI 애플리케이션의 요청은 모두 백엔드로 부터 들어오게 된다.

따라서 AI의 포트를 외부로 노출할 필요가 없다고 판단하였다.

백엔드의 포트도 마찬가지로 외부로 부터 요청을 받을 수 있는 8080 포트만 노출하면 된다.

만약 host network를 사용할 경우 컨테이너간 네트워크 격리가 사라지고 공격 표면이 넓어지기 때문이다.

따라서 사용자 지정 네트워크를 bridge network로 생성해서 백엔드의 8080포트를 호스트의 8080포트와 바인딩 하여 네트워크를 구성하였다.

2.이미지 태그 정책

먼저 latest는 고려하지 않았다. 그 이유는 latest라는 똑같은 태그에 이미지가 매번 변경되기 때문에 특정 이미지가 배포됐던 시점을 추적하기 어려우며, 롤백이 어려워지는 명확한 단점이 있어서 고려하지 않았다. (AI 해커톤때 latest 태그 붙였다가 큰 장애를 일으켰던 기억이 있습니다..)

이미지 태그 정책은 크게 시멘틱 버저닝과 Git Commit Sha를 고려하였다.

시멘틱 버저닝은 dev에서 개발하거나 추가할때는 1.1.0아니 1.1.1을 사용하고 v2배포할때 2.0.0을 사용하는 방식으로 버전이 직관적이라는 장점이 있다.

하지만 매 배포마다 버저닝을 하는것도 하나의 관리 포인트가 될 수 있고 초반의 빠른 배포단계를 가지는 우리 팀에게는 어울리지 않는다고 판단했다.

반면 Commit Sha를 이미지 태그로 사용하면 Docker 이미지와 Git Commit을 1:1로 대응시킬 수 있다는 장점이 있다.

빠른 배포 주기를 가지면서 의도치 않은 배포가 진행되거나 장애가 발생했을 때 현재 배포되어있는 이미지가 어떤 코드에서 만들어졌는지 바로 확인할 수 있어 롤백이 용이하다는 장점이 있어 현재 우리 팀에 적합한 선택이라고 판단했다.

3.이미지 저장소 선정

결정:Image Registry ECR

기존에 사용하는 aws와 github , docker에 있는 프라이빗 레지스트리 비교했다. 굳이 이미지 저장을 위해 외부 플랫폼을 설정하는게 번거롭다고 생각하여 더 많은 건 고려하지 않았다. github는 전송량과 스토리지 비용이 ECR에 비해 많이 나갔다.

  • ECR : 동일 리전 내에서 ECR →EC2로 데이터 전송하는데 비용이 들지 않음. 스토리지 요금 500MB무료이고 이후 1GB당 0.1달러
  • GitHub Packages: 전송량 1GB이상부터는 1GB당 0.50달러, 스토리지 500MB초과시 1GB당 0.25달러 (X)
  • docker hub : CICD에서 로그인 정보를 넘겨줘야함.
4.그 외의 설정 (환경변수, restart 정책 )

환경 변수

노출되도 괜찮은 환경변수와 노출되면 안되는 걸 굳이 구분하지 않고 하나의 환경변수에 넣은뒤 직접 서버에서 .env로 관리하는 방식으로 정했다.
이유는 Secret의 보안성을 강화하기 위해 Vault와 같은 외부 서비스를 고려할 수 있지만, 현재 관련된 경험이 없어 초반 학습 곡선이 있을 것이 우려되며, 인스턴스 내부에 .env 파일을 두고 권한 설정을 타이트 하게 가져가는 것으로 대체하였다.

Container Restart 정책

Container Restart 정책 : unless-stopped

고려항목 : no, always, on-failure,alway,unless-stopped

unless-stopped : 개발자가 중지하지 않으면 계속 재시작한다.docker compose를 중지하고 서버를 재시작 했을때 다시 컨테이너가 시작되는 걸 원치 않아 always방식은 사용하지 않았다. 우리팀은 재시작을 통해서 설정이나 이미지 반영을 빠르게 하길 원하는 요구사항이 있는데 no와 on-failure은 그 요구사항과 맞는 않아 제외했다.


5. 현재 구조의 한계 정의

장점

인프라의 구성이 간단해 빠르게 세팅할 수 있다. 운영의 어려움도 적다. public subnet에 서버들이 있어 별도의 nat getway나 nat instance비용이 나가지 않고쉽게 접근이 가능하다. v1버전에 맞게 빠르게 배포할 수 있는 인프라 구성을 가지고 있다.

한계

현재 단일 AZ구성으로, 이중화가 되어 있지 않아서 장애 발생시 서비스가 중단된다. auto scaling group이 없어 트래픽이 몰릴 시 자원 고갈로 서버가 죽을 수 있다. public subnet에 모든 인스턴스를 두어서 보안상으로 취약하다. volume이 없어 컨테이너가 죽으면 로그를 볼 수 없어 디버깅이 힘들어진다. 현재는 모니터링 방식이 별도로 존재하지 않아 이용자 수가 갑자기 늘어 트래픽이 갑자기 커지거나 예기치 못한 장애에 미리 대응하지 못한다. 현재 세션처리를 별도로 하고 있지 않아서 서버의 갯수를 늘리는 것에 한계가 있다. DB의 백업에 대한 별도 설정을 정의하지 않아, 인스턴스 장애나 데이터 손상, 운영 중 실수로 인한 삭제 등이 발생할 경우 데이터를 복구하기 어렵다. 환경 변수와 Secret 등의 민감 정보를 서버 내부의 .env 파일에 평문으로 저장하고 있어, 서버가 침해되거나 해당 파일에 대한 접근 권한이 탈취될 경우 민감 정보가 함께 노출될 수 있다.


⚠️ **GitHub.com Fallback** ⚠️