50P by xguru 3달전 | favorite | 댓글 9개

- 스트레스 없이, 느릿하게 SaaS를 운영하는 1인 개발자의 아키텍쳐 설명
- 여러개의 프로젝트를 동시에 운영하는 인프라를 구성했음
- 자신이 최근에 만든 PanelBear 라는 SaaS를 기준으로 설명
ㅤ→ 가장 작은 VPS에서 SQLite + Django로 시작
ㅤ→ 6개월간의 이터레이션을 통해, EKS 위에서 Django 모노리스 + Postgres + ClickHouse(분석) + Redis(캐싱) + Celery(예약 작업)
ㅤ→ 대부분 자동화 : 오토스케일링, ingress, TLS 인증서, failover, 로깅, 모니터링 등
ㅤ→ 이 설정을 여러개의 프로젝트에서 사용하므로, 비용을 줄이고 실험들을 정말 쉽게 시작할 수 있음
ㅤ→ 인프라 관리에는 거의 시간이 들지않음 (한달에 0~2시간).
ㅤ→ 대부분의 시간은 기능 개발, 고객 지원, 비즈니스를 성장시키는데 사용

- AWS에서 Kubernetes를 사용하지만 꼭 이게 필요한 건 아님. 다만, 본인은 익숙하기에 안정적으로 운영할 수 있다고 생각.
ㅤ→ 참을성 있는 팀(에러를 같이 참고 막아줄)에서 이 도구를 몇년간 사용하며 배웠음
ㅤ→ "쿠버네티스는 단순한 걸 복잡하게 만들지만, 복잡한 것을 단순하게 만들기도 함"

- 자동 DNS, SSL 및 로드밸런싱
ㅤ→ CloudFlare Proxy 에서 AWS L4 NLB(Network Load Balancer) 로 모든 트래픽 전달
ㅤ→ Request가 들어오면 LB가 k8s 클러스터 노드중 하나로 포워드
ㅤ→ 이 노드들은 여러개의 AZ(Availability Zone) 에 걸쳐져 있는 프라이빗 서브넷에 있음
ㅤ→ k8s 가 요청할 서비스를 알아내는 것은 ingress-nginx(Nginx 클러스터) 가 함
ㅤ→ nginx가 트래픽 전달전에 RateLimiting 및 트래픽 쉐이핑 규칙을 적용
ㅤ→ PanelBear의 경우 앱 컨테이너는 Uvicorn 에서 서빙되는 Django
ㅤ→ Terraform/K8s 간에 몇개의 설정파일이 있고 그걸 대부분의 프로젝트가 공유
ㅤ→ 새 프로젝트 배포 할때 20 라인 정도의 ingress 설정으로 가능

- 자동 롤아웃 및 롤백
ㅤ→ 마스터에 푸시할때마다 GitHub Actions 로 CI 파이프라인 실행
ㅤ→ 코드베이스 검사, Docker-Compose로 완전환 환경을 만들어 E-to-E 테스트
ㅤ→ 검사 통과시 ECR(AWS의 Docker Registry)로 푸시되는 새 Docker 이미지를 빌드
ㅤ→ k8s 클러스터에 flux 컴포넌트 ( https://fluxcd.io/ ) 가 알아서 클러스터내의 이미지를 동기화
ㅤ→ Flux 가 자동으로 Incremental Rollout 실행

- Horizontal Autoscaling
ㅤ→ CPU/메모리 사용량 기반으로 오토스케일링
ㅤ→ 클러스터의 노드당 Pod가 너무 많은 경우 자동으로 더 많은 서버를 생성해서 클러스터 용량을 늘리고 부하를 줄임. 일이 없을때는 축소
ㅤ→ Panelbear 의 경우 API Pod를 2개에서 8개까지 복제본을 자동 조정

- CDN을 이용해서 Static Asset 캐슁
ㅤ→ CloudFlare를 DNS에 설정해서, 모든 요청을 처리하고 DDoS 방지까지 처리
ㅤ→ Static 파일 서빙에는 Whitenoise ( https://github.com/evansd/whitenoise ) 를 사용해서 NGinx/Cloudfront/S3에 파일 업로드할 필요가 없음
ㅤ→ Panelbear 의 랜딩 같은 몇개의 정적 웹사이트에는 NextJS 를 사용

- 어플리케이션 데이터 캐슁
ㅤ→ 일정부분에서는 파이썬이 제공하는 인메모리 LRU 캐슁을 사용
ㅤ→ 대부분의 엔드포인트는 인 클러스터 Redis를 사용

- EndPoint 당 Rate Limiting
ㅤ→ nginx-ingress 에서 글로벌 레이트 리밋을 하지만, 가끔 엔드포인트/메소드 당 특정 리밋을 줄 필요가 있음
ㅤ→ Django Ratelimit 라이브러리를 사용해서 Django 뷰당 제한을 선언 가능
ㅤ→ Redis 를 백엔드로 사용해서 각 엔드포인트에 요청하는 클라이언트를 추적하도록 구성(IP가 아닌 클라이언트 키 기반 해시)

- App Administration
ㅤ→ Django 의 Admin Panel 이 기본적으로 데이터를 보고 편집하는 기능들을 지원
ㅤ→ 의심스러운 계정 접근 차단 / 공지 이메일 발송 / 계정 삭제 요청 처리등의 기능을 추가(처음엔 소프트 삭제후, 72시간내에 완전 삭제)

- 예약된 작업 실행
ㅤ→ SaaS에선 다양한 예약작업이 실행 : 고객에 대한 일일 보고서, 15분마다 사용 통계 계산, 직원들에게 보내는 지표 이메일 등
ㅤ→ Celery 워커 몇개와 Celery beat 스케줄러를 클러스터내에서 실행중. Redis를 태스크 큐로 사용
ㅤ→ 예약된 작업이 제대로 실행되지 않을때 SMS/Slack/Email 등으로 공지 받기 위해 HealthChecks.io 를 사용

- App Configuration
ㅤ→ 모든 설정은 환경변수를 이용. 구식이지만 이식 가능하고 잘 지원됨

- Keeping Secrets
ㅤ→ kubeseal 을 이용. 비대칭 암호화를 사용해서 Secret들을 암호화함. 암호 해독 키에 접근할 권한이 있는 클러스터만 암호 해독 가능
ㅤ→ 클러스터내의 Secret 들을 보호하기 위해 AWS KMS의 암호화 키를 이용

- 관계형 데이터 : Postgres
ㅤ→ 실험들을 위해 클러스터내에서 바닐라 Postgres 컨테이너를 운영하고, K8s Cronjob 으로 S3에 매일 백업을 수행
ㅤ→ 프로젝트가 성장하면 데이터베이스를 클러스터 내에서 RDS로 옮기고, AWS가 암호화된 백업 및 보안 업데이트등을 처리하게 함
ㅤ→ 보안을 강화하기 위해, AWS의 DB는 Private Network 에서만 접근 가능

- 컬럼 데이터 : ClickHouse
ㅤ→ PanelBear의 분석데이터를 효율적으로 저장하고 실시간 쿼리하기 위해 ClickHouse 를 사용
ㅤ→ 훌륭한 Columnar 데이터 베이스로, 엄청 빠르고 구조만 잘 잡으면 높은 압축률을 보임(스토리지 감소 = 수익 증가)
ㅤ→ K8s 클러스터내에서 ClickHouse 인스턴스를 자체 호스팅
ㅤ→ S3에 Columnar 데이터를 주기적으로 백업하는 CronJob 생성
ㅤ→ 재해시 S3에서 데이터를 수동으로 백업하고 복원하는 몇개의 스크립트

- DNS기반 서비스 디스커버리
ㅤ→ K8s 가 클러스터내의 DNS 레코드를 자동으로 관리해서 트래픽을 해당 서비스로 라우팅
ㅤ→ 오토스케일링중에도 건강한 pod 들과 연결되도록 자동으로 DNS 레코드를 동기화

- Version-Controlled Infrastructure
ㅤ→ Docker, Terraform, K8s manifest 를 단일 저장소(Infra Mono-Repo)에서 관리
ㅤ→ 간단한 명령으로 인프라 생성 및 삭제가 가능하고 버전 관리를 통해 재현가능

- Cloud Resource를 위한 Terraform
ㅤ→ 대부분의 클라우드 리소스는 Terraform 으로 관리
ㅤ→ 이를 통해 인프라 자원과 설정을 문서화 하고 추적이 가능

- App 배포를 위한 K8s manifest
ㅤ→ 인프라 모노 레포의 YAML 파일에 K8s Manifest 가 적혀있음
ㅤ→ cluster 와 apps 두개의 폴더로 분할
ㅤ→ cluster 에는 nginx-ingress, 암호화된 secret들, Prometheus 스크래퍼 처럼 클러스터 전체 서비스 관련 설정을 포함
ㅤ→ apps 에는 프로젝트당 하나의 네임스페이스에 정보들 저장

- 구독 및 결제
ㅤ→ Stripe Checkout 을 이용해서 모든 결제 처리
ㅤ→ 결제 정보 자체에 관여할 필요 없어서 제품에 집중 가능
ㅤ→ 고객 세션 만들고 Stripe의 페이지로 리디렉션 한뒤 WebHook 으로 결과받으면 끝

- Logging
ㅤ→ 로깅 에이전트를 쓰지 않고 간단히 stdout 에 로그출력하면 k8s 가 자동으로 로그를 수집하고 rotate도 수행
ㅤ→ FluentBit 등을 통해서 Elasticsearch/Kibana 등으로 보낼수 있겠지만, 간단히 유지하기 위해 아직은 하지 않음
ㅤ→ 로그 검사를 위해서는 CLI 도구인 stern 사용

- 모니터링 및 경고
ㅤ→ 처음에는 Prometheus / Grafana 를 자체호스팅 했지만, 클러스터 문제 발생시 경고시스템도 같이 중단 되어서 불편
ㅤ→ 그래서 New Relic 으로 변경
ㅤ→ 모든 서비스에는 자동으로 지표를 수집하고 Datadog, New Relic, Grafana Cloud 등으로 보낼수 있는 Prometheus Integration 이 있어서, New Relic 으로 이관시 그들이 제공하는 Prometheus Docker 이미지를 사용하는 것만으로 가능

- 오류 추적
ㅤ→ Sentry 를 이용해서 애플리케이션 오류를 수집
ㅤ→ Slack #alerts 채널을 이용해서 downtime, cron job failures, security alerts, performance regressions, application exceptions 등 모든 경고를 중앙 집중화

- Profiling 및 다른 좋은 것들
ㅤ→ 심층 분석이 필요할때는 cProfile 이나 snakeviz 같은 도구를 사용
ㅤ→ 로컬 머신에서는 Django Debug Toolbar 이용

xguru 3달전  [-]

저는 국내에도 자기 서비스로 돈을 버는 1인 개발자 또는 소규모 팀들이 더 많이 나왔으면 합니다.
여기 긱뉴스는 그런 서비스들이 자신을 알리고, 건전한 피드백을 받는 공간으로 성장했으면 좋겠어요.

- 1인 SaaS 스타트업 6개월 운영 회고 https://news.hada.io/topic?id=2415
- 최소한의 노력으로 소프트웨어 스타트업 운영하기 https://news.hada.io/topic?id=1534
- 2021년 독립 SaaS의 현황 보고서 [63p 슬라이드] https://news.hada.io/topic?id=3728
- 1조 회사를 만들다 실패한 경험 이야기 https://news.hada.io/topic?id=2
- 저는 인터넷에서 양파를 팝니다 https://news.hada.io/topic?id=3
- 삼성출신 스타트업 대표가 12억 날리며 깨달은 것 https://news.hada.io/topic?id=3015
- 스타트업을 년6$로 운영하기 https://news.hada.io/topic?id=1621

reedids 3달전  [-]

동의합니다. 감사합니다 :)

e1q88 3달전  [-]

👍

admin2 3달전  [-]

Sentry와 New Relic의 기능차이가 많이 날까요?
비슷한 기능을 한다고 생각했었는데 아직 써본적이 없어서요.

kbumsik 3달전  [-]

오 우리회사에서 k8s도입을 검토중인데 1인 스타트업이 아니여도 상당히 좋은 글이군요

fortune 3달전  [-]

좋은글 감사합니다. 영감받고갑니다.

khris 3달전  [-]

굳이 1인 스타트업이 아니라도 좋은 글이네요

yshrust 3달전  [-]

사소한 오타가,,
- 오류 추적
ㅤ→ Sentry 를 이용해서 애플리케이션 오류를 집
=> 수집인 것 같습니당

xguru 3달전  [-]

고맙습니다. 수정했습니다~!