하나의 레포로 클라우드 SaaS와 온프레미스를 함께 운영하기
같은 코드를 클라우드(AWS) SaaS와 고객사 안의 쿠버네티스(온프레미스) 양쪽에서 돌린 방법을 정리합니다. 특히 인터넷이 막힌 곳에 어떻게 설치했는지를 다룹니다.
1편에서 서비스를 한 레포에 모았다는 이야기를 했습니다. 그런데 그 코드를 돌려야 하는 곳이 한 군데가 아니었습니다.
- 하나는 우리가 직접 운영하는 클라우드 SaaS입니다. AWS 위에서 우리가 관리합니다.
- 다른 하나는 온프레미스입니다. 고객사 데이터센터 안의 쿠버네티스에 제품을 통째로 설치해 드립니다. 데이터가 회사 밖으로 못 나가는 곳을 위해서입니다.
같은 제품인데 운영 환경이 정반대였습니다. 한쪽은 인터넷에 활짝 열려 있고, 한쪽은 인터넷이 아예 막혀 있습니다. 이 둘을 하나의 레포로 감당한 방법을 적어 봅니다.
한 레시피, 두 주방

비유하자면 같은 요리를 두 주방에서 만드는 일이었습니다. 하나는 모든 설비가 갖춰진 큰 중앙 주방(클라우드)이고, 하나는 고객의 집 주방(온프레미스)입니다. 집 주방에는 우리가 쓰던 설비가 없습니다.
레시피(코드)를 두 벌로 나누면 관리가 무너집니다. 그래서 레시피는 한 벌로 두고, 환경에 따라 부품만 바꿔 끼웠습니다.
핵심은 "환경마다 다른 부분"을 코드 본문에서 떼어내, 갈아 끼울 수 있는 부품으로 만든 것입니다. 전원 어댑터에 비유할 수 있습니다. 노트북(코드)은 그대로 쓰고, 나라(환경)가 바뀌면 콘센트 어댑터만 바꿉니다.
| 갈아 끼운 부품 | 클라우드(SaaS) | 온프레미스 |
|---|---|---|
| 로그인 | 클라우드 관리형 인증 | 직접 띄우는 인증 서버 |
| 파일 저장소 | AWS S3 | S3 호환 저장소(직접 설치) |
| 실행 환경 | 관리형 컨테이너 | 고객사 쿠버네티스 |
코드 입장에서는 "파일을 저장한다"만 알면 됩니다. 그것이 AWS S3인지 직접 설치한 저장소인지는 환경 변수로 정한 부품이 처리합니다. 본문 코드는 어느 환경인지 몰라도 동작합니다.
이 패턴 덕분에 새 기능을 만들 때 "이건 클라우드용, 이건 온프레용"으로 나눠 짤 필요가 없었습니다. 한 번 짜면 양쪽에서 돕니다.
이미지는 두 벌로
코드는 한 벌이지만, 배포 이미지는 환경에 따라 조금 달랐습니다. 예를 들어 온프레미스 쪽 이미지에는 쿠버네티 스가 서비스 상태를 확인할 때 쓰는 작은 도구(상태 점검기)를 함께 넣어야 했습니다. 클라우드 쪽과 점검 방식이 달랐기 때문입니다(2편 옆 동네인 헬스체크 이야기와 닿아 있습니다).
이런 차이는 빌드 설정(Dockerfile)을 환경별로 두 벌 두어 흡수했습니다. 본문 코드가 아니라 포장 단계에서만 갈라지게 한 것입니다.
가장 큰 벽, 인터넷이 없다
진짜 어려움은 온프레미스의 인터넷이 막혀 있다는 점이었습니다(에어갭, air-gap). 클라우드에서는 필요한 프로그램이나 이미지를 그때그때 인터넷에서 받아오면 됩니다. 하지만 고객사 안에서는 그게 불가능합니다.

인터넷이 되는 곳에서의 설치는 마트가 옆에 있는 것과 같습니다. 재료가 떨어지면 사 오면 됩니다. 에어갭 설치는 전기도 인터넷도 없는 산장에 들어가 살림을 차리는 일입니다. 필요한 재료를 하나도 빠짐없이 미리 싸 들고 가야 합니다. 가서 빠진 걸 발견하면 늦습니다.
그래서 설치 방식이 달라졌습니다.
- 제품이 필요로 하는 모든 컨테이너 이미지를 미리 묶음으로 만들어 함께 가져갔습니다.
- 고객사 안에 사설 레지스트리(이미지 보관소)를 띄우고, 묶음을 거기에 풀었습니다. 설치는 인터넷이 아니라 이 사설 보관소에서만 이미지를 받습니다.
여기서도 한 번 데였습니다. 사설 보관소에서 이미지를 받는 속도가 생각보다 느렸습니다. 작은 이미지는 괜찮았지만, 큰 이미지는 받다가 시간이 너무 걸렸습니다. 결국 용량이 큰 이미지는 보관소를 거치지 않고 컨테이너 런타임으로 직접 가져오는 방식으로 우회했습니다.
설치 스크립트도 처음엔 인터넷이 되는 환경을 가정하고 짜여 있어, 막힌 환경에서 몇 군데가 멈췄습니다. "받아올 수 있다"는 가정이 코드 곳곳에 숨어 있었던 것입니다. 그 가정을 하나씩 찾아 걷어냈습니다.
마무리
- 같은 제품을 클라우드 SaaS와 온프레미스 양쪽에서 운영해야 했습니다. 한쪽은 인터넷에 열려 있고, 한쪽은 막혀 있습니다.
- 레시피(코드)는 한 벌로 두고, 환경마다 다른 부분만 갈아 끼우는 부품으로 뺐습니다(로그인·저장소·실행 환경). 본문 코드는 어느 환경인지 모 릅니다.
- 환경 차이는 가능한 한 본문이 아니라 가장자리(빌드 설정, 환경 변수, 설치 단계)에서 흡수했습니다.
- 에어갭 설치는 "필요할 때 받아온다"는 가정을 모두 걷어내고, 필요한 것을 전부 싸 들고 가는 방식으로 바꿔야 했습니다.
다음 편에서는 화면(프론트엔드) 쪽 이야기를 해보겠습니다. 하나의 코드베이스로 여러 개의 웹 앱을 만들고 배포한 방법을 적어 볼 생각입니다.