인프라

멀티테넌트 SaaS를 에어갭 박스로 뜯어내기

클라우드 SaaS를 단일 온프레미스 어플라이언스로 제공하는 것은 배포 변경이 아닙니다. 이는 적절한 위치에서 테넌트, 크레딧, 관리형 인증 및 모든 클라우드 종속성을 제거하는 것을 의미합니다.

이 글은 영어 원문을 AI 모델이 번역한 것입니다. 표현이 원문과 다를 수 있습니다. 영어 원문 보기

고객이 귀사의 다중 테넌트 미디어 SaaS를 자체 네트워크에 설치하여 인터넷 연결 없이, 사용량 기반 과금 없이, 직원을 위한 무제한 처리 기능을 갖춘 단일 박스로 사용하길 원합니다. 이는 패키징 작업처럼 들립니다. 그렇지 않습니다. 제품의 모든 계층은 테넌트, 크레딧, 관리형 로그인, 클라우드 컨트롤 플레인을 가정하고 있으며, 이러한 가정들은 각각 그것이 존재하는 바로 그 위치에서 들어내야 합니다. 하나라도 놓치면 어플라이언스는 클라우드 호출을 유출하거나, 판매 시 약속했던 "무제한" 요구사항을 충족하지 못하게 됩니다.

함정: UI를 숨기는 것은 제한을 제거하는 것이 아닙니다

요구사항은 무제한 처리였습니다. 가장 먼저 드는 생각은 업그레이드 페이지와 크레딧 측정기를 숨기는 것입니다. 그것은 완전히 잘못된 생각입니다. 크레딧 확인은 한 곳에만 있는 것이 아닙니다. 세 군데에서 실행됩니다.

  • 프런트엔드는 잔액이 0일 때 작업을 숨깁니다.
  • API는 잔액을 초과할 요청을 거부합니다.
  • 워커는 작업이 완료될 때 원장에서 차감합니다.

UI만 숨기면 숨겨진 카운터가 0이 되는 순간 API는 여전히 "크레딧 부족"을 반환합니다. 작업은 워커 깊은 곳에서 여전히 실패합니다. 실제로 "무제한"을 제공하려면 세 계층 모두에서 한 번에 확인을 제거해야 합니다. 즉, UI 게이트를 없애고, API 거부를 없애고, 원장 차감을 no-op으로 전환해야 합니다. 이것이 바로 부분적인 변경이 데모에서는 완료된 것처럼 보이지만 2주 차에 고장 나는 지점입니다.

모든 클라우드 종속성에는 온프레미스 대체 요소가 필요합니다

에어갭(Air-gapped)은 사용자가 명시적으로 허용하지 않은 호출을 박스가 전혀 하지 않는다는 것을 의미합니다. 해당 SaaS는 시작 시 그리고 거의 모든 요청 시에 클라우드 서비스에 연결했습니다. 이러한 각각의 연결은 로컬 대체 요소가 되었습니다:

에어갭 경계: 허용된 이그레스 vs 제거된 클라우드 종속성 에어갭 박스 앱 + 워커 로컬 DB, 스토리지 1 2 번역 API TTS 공급업체 // 두 개의 이그레스 호출만 허용됨; 로그인, CDN, 결제, 구성 저장소는 제거됨

구체적인 교체 내용은 다음과 같습니다.

  • 부팅 시 클라우드 파라미터 스토어에서 구성을 가져왔습니다. 설치 프로그램이 작성하는 시드된 로컬 .env 파일로 교체했습니다.
  • 서명된 미디어 URL은 관리형 엣지 워커(managed edge worker)에 의해 생성되었습니다. 경로에서 HMAC를 검증하는 nginx 리버스 프록시로 교체했습니다.
  • 로그인은 클라우드 싱글 사인온(single sign-on)이었습니다. 관리자가 미리 생성하는 로컬 ID 및 비밀번호 계정으로 교체했으며, 셀프서비스 가입은 없습니다.
  • 객체 스토리지는 클라우드 버킷이었습니다. 로컬 S3 호환 서버로 교체했으며, 동일한 클라이언트를 다른 엔드포인트로 재사용합니다.

아웃바운드 호출은 번역 API와 텍스트 음성 변환(text-to-speech) 공급업체, 단 두 곳만 허용 목록에 추가되었습니다. 그 외 모든 것은 박스 내의 로컬 프로세스입니다.

시작을 거부하는 환경 게이트

서비스에는 알려진 클라우드 환경 외부에서 실행을 거부하는 시작 검사가 있었는데, 이는 누군가 실수로 프로덕션 구성을 부팅하는 것을 방지하는 보호 장치였습니다. 에어갭(air-gapped) 환경의 컴퓨터에서는 부팅할 때마다 그 보호 장치가 발동했습니다. 해결책은 구성 유효성 검사기가 수용하는 새로운 환경 모드인 "on-prem"이었습니다. 그래서 동일한 바이너리가 결코 충족할 수 없는 클라우드 검사 없이 로컬 인프라스트럭처에 대해 시작될 수 있었습니다. 이는 보호 장치를 삭제하는 것보다 더 깔끔한 방법입니다. 왜냐하면 그 보호 장치가 여전히 클라우드 빌드를 보호하기 때문입니다.

자신의 아키텍처 다이어그램을 믿기 전에 코드를 읽어보세요

마이그레이션 작업의 일부는 모든 서비스에서 클라우드 설정 클라이언트를 제거하는 것이었습니다. 한 워커가 "런타임에 클라우드에서 설정을 읽어온다"는 이유로 목록에 포함되어 있었습니다. 하지만 사실이 아니었습니다. 코드를 읽어보니 그 워커는 항상 일반 로컬 파일을 읽어왔고, 클라우드 파라미터 스토어는 실행 중인 프로세스가 아닌 배포 스크립트에만 등장했습니다. 그 워커는 코드 변경이 전혀 필요 없었고, 다른 시드 파일만 있으면 되었습니다.

이와 같은 추출 작업을 할 때마다 교훈은 반복됩니다. 무엇이 클라우드에 의존하는지에 대한 당신의 멘탈 모델은 실제 클라이언트 호출을 grep으로 찾아보기 전까지는 추측에 불과합니다. 당신이 우려했던 의존성은 배포 시점의 편의 기능으로 드러날 수 있고, 잊고 있던 의존성은 요청 핸들러 안에 숨겨져 있을 수 있습니다. 머릿속의 다이어그램이 아니라 코드를 보고 각각의 의존성을 확인해야 합니다.

"에어갭"의 실제 비용

SaaS를 어플라이언스로 전환하는 것은 대부분 신중하게 수행해야 하는 빼기 작업입니다.

  • 프런트엔드, API, 워커에서 테넌트별 및 사용량별 제한을 함께 제거해야 합니다. 그렇지 않으면 데모에서는 볼 수 없는 부분에서 "무제한"이라는 약속이 깨집니다.
  • 모든 클라우드 종속성에 이름이 지정된 로컬 대체 항목을 제공하고, 아웃바운드 호출에 엄격한 허용 목록을 적용하여 잊어버린 호출이 외부로 통신(phoning home)하는 대신 큰 소리로 실패하도록 해야 합니다.
  • 클라우드 빌드를 보호하는 가드를 삭제하는 대신 환경 모드를 추가해야 합니다.
  • 위험해 보이는 종속성은 배포 시에만 사용되는 경우가 많고 실제 종속성은 요청 경로에 숨어 있으므로, 각 종속성을 소스와 대조하여 확인해야 합니다.

관련 글