# Repository Structure ## 설계 목표 이 구조는 특정 제품의 파일 배치보다 변경 주기와 소유권을 우선합니다. - 한 리소스에는 한 명확한 소유자가 있다. - 재사용 구현과 실제 배포 진입점을 분리한다. - 소규모 구성은 선택 영역을 생략할 수 있다. - 규모가 커져도 기존 경계를 바꾸지 않고 같은 종류의 leaf를 추가한다. - 사람이 실행하는 명령과 CI 검증이 같은 진입점을 사용한다. ## 소유권 매트릭스 | 대상 | 소유 경로 | 직접 실행 여부 | 변경 주기 | |---|---|---:|---| | state backend, 초기 identity | `bootstrap/foundation` | 예 | 매우 낮음 | | 네트워크, IAM, DNS, 클러스터 | `infrastructure/live` | 예 | 낮음 | | 재사용 IaC 단위 | `infrastructure/components` | 아니요 | 중간 | | 재사용 IaC 조합 | `infrastructure/stacks` | 아니요 | 중간 | | GitOps 컨트롤러와 root 연결 | `bootstrap/gitops` | 예 | 낮음 | | 클러스터 desired state | `gitops/clusters` | reconcile 진입점 | 지속적 | | cluster-wide addon | `gitops/platform` | 아니요 | 중간 | | 애플리케이션 배포 정의 | `gitops/apps` | 아니요 | 높음 | | 정책과 tenant 정의 | `gitops/policies`, `gitops/tenants` | 아니요 | 중간 | Catalog 영역(`components`, `stacks`, `platform`, `policies`, `tenants`, `apps`)은 직접 배포하지 않습니다. 실제 진입점이 필요한 항목만 조합해서 참조합니다. ## 의존 방향 ```text bootstrap/foundation │ output ▼ infrastructure/components ◀── infrastructure/stacks ▲ ▲ └──────── infrastructure/live ─┘ │ cluster endpoint/identity ▼ bootstrap/gitops │ root reference ▼ platform ─┐ policies ─┼────────▶ gitops/clusters tenants ─┤ apps ─┘ ``` 역방향 의존은 만들지 않습니다. 예를 들어 reusable component가 특정 `live/prod` 값을 읽거나, app base가 특정 cluster overlay를 참조하면 안 됩니다. ## Infrastructure 경계 ### `components` 네트워크, identity, registry, Kubernetes cluster처럼 작고 응집된 재사용 단위입니다. Terraform/OpenTofu를 선택했다면 일반적으로 backend가 없는 child module에 해당합니다. ### `stacks` 여러 component를 반복해서 같은 방식으로 조합할 때만 사용합니다. 작은 프로젝트는 이 계층 없이 `live`가 component를 직접 호출할 수 있습니다. stack이 다른 stack을 깊게 중첩하기보다는 live root에서 평평하게 조합하는 방식을 권장합니다. ### `live` 실제로 plan/apply하는 root입니다. leaf 하나는 다음을 만족해야 합니다. - 독립된 state와 locking - 명시적인 provider와 backend 설정 - 고정된 component/module/chart 버전 - 비밀이 아닌 환경 입력만 저장소에 커밋 - 출력값과 downstream contract 문서화 작은 구성은 `live/dev/cluster`로 충분합니다. 계정과 리전이 늘어나면 `live/////`처럼 경로를 확장합니다. 자동화는 경로의 고정 깊이에 의존하지 말고 실행 가능한 root 파일을 기준으로 대상을 찾도록 작성합니다. 서로 다른 환경의 root가 상대 경로로 다른 환경 구현을 import하면 안 됩니다. 공유가 필요하면 versioned component나 명시적인 remote output/data contract를 사용합니다. ## GitOps 경계 ### `clusters` 클러스터가 reconcile하는 유일한 진입점입니다. 공통 리소스를 복사하지 않고 platform, policy, tenant, app catalog에서 필요한 항목만 참조합니다. 작은 구성은 `clusters/dev/main`, 다중 리전 구성은 `clusters///` 형태를 사용할 수 있습니다. 여기에도 고정된 경로 깊이를 강제하지 않습니다. ### `platform` cluster-wide controller와 addon을 둡니다. 예시는 다음과 같습니다. - ingress/gateway, external DNS, certificate - storage class/CSI, autoscaling - metrics, logs, traces, alerting - secret operator와 delivery controller 각 component는 `base`와 필요한 `overlays`를 같은 디렉터리 안에 응집시킵니다. 환경 차이는 전체 파일 복사 대신 Kustomize patch 또는 별도 values로 표현합니다. ### `policies`, `tenants`, `apps` - `policies`: cluster-wide admission 규칙, 거버넌스와 예외 - `tenants`: 구체적인 namespace, RBAC, quota, limit range, NetworkPolicy - `apps`: application source code가 아닌 배포 정의 애플리케이션 팀이 별도 저장소를 소유하면 `apps`에는 그 저장소/OCI artifact를 참조하는 GitOps 리소스만 둘 수 있습니다. Cloud DNS zone/delegation과 cloud IAM role은 `infrastructure`가 소유합니다. External DNS controller, 동적 record 요청과 Kubernetes ServiceAccount binding은 `gitops/platform`이 소유합니다. 두 계층 사이에는 zone ID, role ARN 같은 명시적인 output contract만 전달합니다. ## Bootstrap 경계 Bootstrap은 선언형 관리가 스스로 시작될 수 없는 최소 범위만 담당합니다. - `foundation`: state backend, 최초 CI identity와 같은 선행 조건 - `gitops`: Flux 또는 Argo CD 중 선택한 컨트롤러 설치와 root reference ingress, cert-manager, observability 같은 addon은 bootstrap이 아니라 GitOps가 소유합니다. bootstrap 이후의 변경을 계속 수동 명령으로 누적하지 않습니다. ## 규모 확장 기준 | 단계 | 추가하는 것 | 그대로 유지하는 것 | |---|---|---| | 소형 | 단일 live root, 단일 cluster root, 최소 platform | lifecycle/ownership 경계 | | 중형 | reusable stack, staging/prod, 정책, 관측성 | component와 entrypoint 분리 | | 대형 | 계정·리전별 state, 다중 cluster, tenants, CODEOWNERS | 한 리소스 한 소유자 | | 조직 분리 | lifecycle/team별 repository 분리 가능 | 각 repository 내부의 동일한 계약 | repository를 분리하는 시점은 폴더 수가 아니라 권한, 배포 주기와 소유 팀이 실제로 달라졌을 때입니다. ## 설계 참고 자료 - [Kubernetes: Kustomize를 이용한 선언형 객체 관리](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) - [Flux: GitOps repository 구조](https://fluxcd.io/flux/guides/repository-structure/) - [OpenTofu: reusable module](https://opentofu.org/docs/language/modules/) - [OpenTofu: 평평한 module composition](https://opentofu.org/docs/language/modules/develop/composition/)