hub / edge 두개의 홈랩 클러스터
홈랩 클러스터가 두 환경에 걸쳐 두개로 배포되어있습니다. 하나는 지금 사는 집, 하나는 본가에 배포되어있습니다.
첫 공부를 시작할떄부터 본가에서 홈랩을 구성하기 시작한지 벌써 4년이 넘어가네요. 3년이 넘도록 public IP 변경 한번없이 도메인을 그대로 쓸 수 있게 해줬던 통신사에게도 꽤 고마운 마음을 가지고있긴 헀습니다.
이제는 새로운 환경에서도 홈랩을 구성 할 수 있게되어, 클러스터가 두벌이 되었습니다. Stateless 한 노드들은 여러군데에 둘 수 있지만, 스토리지 장비를 각각 두기엔 또 부담이라, 한군에만 둘 수 있겠더라고요.
사실 이 동일한 패턴을 EKS 클러스터간 매니지먼트할떄와 동일한 패턴으로 쓰고있었는데요 기존에 이 두환경을 Stage / Prod 라고 임의로 이름붙여서 배포하다보니, 실제 두개 상황과는 괴리감이 점점 커지는것같아, 이름을 변경해야겠다는 생각이들어 이름부터 새로 지어줬습니다.
그래서 이름을 역할대로 다시 지었습니다. hub와 edge.
| hub (현재집, 舊 stage) | edge (본가, 舊 prod) | |
|---|---|---|
| 도메인 | hub 전용 도메인 | edge 전용 도메인 |
| 노드 | 다수의 서버 + Synology NAS | 단일 노드 |
| 역할 | 중앙 — 스토리지·관측·SSO·CI등의 종착지 | 스포크 — 서비스만 돌리고 상태저장은 전부 hub로 |
| 스토리지 | NAS 기반의 storageClass (NFS) | 없음 |
| 관측 | vmcluster(vmstorage) + Grafana + vmalert | vmagent 하나 |
| 인증 | Keycloak (hub SSO) | 자체 IdP 없음 — hub Keycloak에 OIDC 위임 |
보유중인 도메인이 2개였어서 환경 이름이 도메인과 1:1이 된 것도 장점이라면 장점이겠네요.
1. 전체 지도
두 집 사이를 오가는 데이터 트래픽은 딱 하나 — edge vmagent의 remote write입니다. 집 밖을 나가는 경로라 인증이 붙습니다.
2. edge를 stateless로 만든 이유
원래 edge에도 hub와 똑같은 VictoriaMetrics 풀스택이 있었습니다. 다만, 스토리지 장비를 들고 이사를갔으니… 상태저장할 곳이 없어지기도 했습니다.
꼭 그게 중요한건 아닌데요, 현재 운영중인 서비스 클러스터의 상태저장소도 “아예” 두지않고 Managed Service 영역으로 이관한 이후하고 클러스터 위에 상태저장이 필요한 컴포넌트들은 그 앞의 관리 클러스터로 이관하는쪽이 좋아보이는 패턴이였습니다.
-
물론 EKS의 생명주기를 Blue / Green 으로 자주 갈아엎기에 용이한 패턴이라는 뜻 입니다.
-
부트스트랩이 재현 가능해집니다. edge가 통째로 날아가도 ArgoCD 하나만으로 apps-root 하나만 배포하면 전부 Green 이 됩니다.
-
원격지에 백업·용량·디스크 교체 같은 운영 부담을 두지 않습니다.
그래서 edge의 VM 스택은 vmagent 하나로 줄였고(저장·조회·알림 전부 hub로 위임), keycloak·uptime-kuma 같은 stateful한 앱은 제거했습니다. 지금 edge에서 도는 건 블로그·청첩장 같은 무상태 서비스 몇 개와 vmagent뿐입니다.
원칙은 딱 하나, edge에는 PVC를 요구하는 앱을 배포하지 말자
3. 메트릭 파이프라인 — 공인망을 건너는 유일한 트래픽
edge vmagent는 자기 클러스터의 메트릭들을 cluster=edge 라벨과 함께 hub의 메트릭 수집 엔드포인트로 remote write 를 수행합니다.
hub 자신의 vmagent애서 들어오는 메트릭들은 cluster=hub를 답니다.
VM Select 혹은 Grafana에서 라벨 별로 두 클러스터의 메트릭을 각각 조회합니다.
이 경로는 인증 없이 공인망을 타게 둘 수는 없어 쓰기·읽기 앞에 vmauth를 뒀습니다.
- VMAuth 에서 VMUser 계정별 라우팅을 정의합니다.
edge계정은/insert/*만 vminsert로,viewer계정은/select/*만 vmselect로 통과시킵니다. 경로 밖 요청과 미인증 요청은 401. - istio VirtualService의 목적지를 vminsert/vmselect가 아닌 vmauth로 전환
- hub 내부 소비자는 이 관문과 무관합니다. Grafana·vmalert·hub vmagent는 클러스터 내부 svc로 직결이라 vmauth 장애가 나도 hub 관측은 살아 있습니다.
4. GitOps·CI — 사람 손은 앱 repo까지만
배포는 세개의 repo로 나누어 관리중입니다.
| repo | 역할 |
|---|---|
| montstrap | app-of-apps 정의. {hub,edge}/apps/*.yaml에 ArgoCD Application 정의, platform/manifests/에 istio·cert-manager 같은 플랫폼 컴포넌트 |
| mont-helm | 외부 helm chart에 먹일 custom values ($values 멀티소스로 참조) |
| montstrap-manifest | raw manifest 앱 (deployment/service/VS + kustomization) |
앱 repo에 push하면 GitHub Actions가 이미지를 빌드해 Docker Hub에 올리고 montstrap 계열 repo의 kustomization newTag(또는 deployment 이미지 태그)에 커밋을 밉니다. 거기서부터는 두 클러스터의 apps-root가 각자 pull해서 수렴합니다. 배포에 사람이 kubectl을 만지는 지점이 없습니다.
apps-root 자신도 {env}/apps/ 디렉토리 안에 들어 있습니다. 자기가 자기를 관리하는 구조라 루트 Application 스펙을 고치는 것도 git push 하나로 끝납니다. 예전엔 이 파일만 수동 apply 전용이었는데, 그 탓에 edge가 두 달치 수정을 못 받고 방치된 적이 있었습니다.
환경 분리는 디렉토리 하나입니다. 같은 repo의 hub/와 edge/가 각 클러스터의 전체 상태고 두 클러스터는 서로의 존재를 모릅니다 — 접점은 오직 §3의 remote write와 §5의 OIDC뿐입니다.
리네임 후기: 디렉토리 이름을 바꾸는 것 자체는 git mv 두 번이지만 여파는 세 repo의 경로 참조 전부와 앱 repo 12개의 CI 워크플로우까지 닿았습니다. CI가 stage/... 경로를 하드코딩하고 있었기 때문입니다. 이런 리네임은 “git 치환 → 클러스터 apps-root 재적용 → CI 경로 수정”을 한 호흡에 끝내야 합니다. 그러지 않으면 옛 경로를 바라보는 CI가 존재하지 않는 디렉토리에 커밋을 미는 중간 상태가 생깁니다.
5. IdP는 한곳으로
stateless 원칙은 인증에도 적용됩니다. Keycloak은 DB가 필요한 stateful 앱이라 edge에 둘 수 없고 둘 필요도 없어, edge의 ArgoCD를 포함한 인증/인가는 hub의 Keycloak을 OIDC provider로 등록이 되어있습니다.
이렇게 Stateful 한 클러스터와, Stateless 한 클러스터를 각각 구축해 운영을 시작한 홈랩 프로젝트 근황을 남겨봅니다.
읽어주셔서 감사합니다.