refactor: 폴더 구조 변경

This commit is contained in:
donghyeon-ka
2026-08-02 00:22:19 +09:00
parent f9c463f87a
commit be2f8e4863
1869 changed files with 4565 additions and 295591 deletions
+99 -62
View File
@@ -1,83 +1,120 @@
# 운영 / 검증
# Operations and validation
bootstrap, teardown, validate.sh, 환경별 차등 계획의 **설계 의도** 를 정리한 문서. 단계별 실제 실행 절차는 [guide.md](../guide.md) 에 있다.
## bootstrap 단계
`VaultConnection` / `VaultAuth` / `VaultStaticSecret` 은 VSO Helm 설치로 CRD 가 등록된 뒤에만 apply 할 수 있다. 그래서 `overlays/dev/vso/` 는 dev kustomization 집계에 포함되지 않으며, `bin/bootstrap.sh` 마지막 단계에서 별도로 `kubectl apply -k overlays/dev/vso/` 한다.
| Phase | 작업 | 의존하는 직전 상태 | 멱등 안전? |
|:---:|---|---|---|
| 0 | MinIO Operator Helm install (`tasks/minio-operator-install.sh`) | helm 가능한 클러스터 | ✅ `helm upgrade --install` |
| 1 | `kubectl apply -k base/managing/namespace/` (PSS restricted 라벨 선행) | — | ✅ `kubectl apply` |
| 2 | VSO-managed Secret 점검 | namespace 존재 | ⚠️ `RESET_STALE_SECRETS=yes` 옵션 시 파괴적 |
| 3 | `kubectl apply -k overlays/dev/` (vault + registry + 앱) | namespace + PSS 라벨 | ✅ `kubectl apply` |
| 4 | `vault-0` Pod Running 대기 | Phase 3 의 Vault StatefulSet | ✅ wait 만 |
| 5 | `tasks/vault-init.sh` (init / unseal / auth / policy×2 / role×2) | `vault-0` Running | ✅ 상태 체크 후 차이만 적용 |
| 6 | `tasks/vso-install.sh` (helm upgrade --install) | Vault auth/role 준비 | ✅ `helm upgrade --install` |
| 7 | `kubectl apply -k overlays/dev/vso/` (VaultConnection / VaultAuth / VaultStaticSecret) | Phase 6 의 VSO CRD 등록 | ✅ `kubectl apply` |
Phase 5 의 1 회성 셋업 흐름은 [secret-pipeline-bootstrap 시퀀스](diagrams/sequence/secret-pipeline-bootstrap.md), Phase 7 이후의 정상 reconcile 은 [secret-pipeline-runtime 시퀀스](diagrams/sequence/secret-pipeline-runtime.md) 참고.
## Bootstrap
```bash
# dev — 비밀번호를 프롬프트에서 무음 입력 (bash history 에 안 남음)
bash k8s/scripts/bin/bootstrap.sh dev
# teardown — 대화형 y/N
bash k8s/scripts/bin/teardown.sh dev
export KUBE_CONTEXT_LAB='<expected-context>'
bash scripts/bin/bootstrap.sh lab
```
## 스크립트 구조
각 stage는 `render -> server-side dry-run -> diff -> confirm -> apply` 순서로
실행됩니다. `CONFIRM=yes`는 비대화 환경에서만 사용하고 context 확인을
우회하지 않습니다.
`k8s/scripts/``bin / ci / lib / tasks` 4 축:
| Order | Entrypoint / task | Completion boundary |
| ---: | --- | --- |
| 1 | `namespaces` | Namespace Active |
| 2 | `00-platform` | cert-manager와 Keycloak Operator Available |
| 3 | MinIO/VSO Helm task | controller Ready, CRD registered |
| 4 | `10-vault` | `vault-0` Running |
| 5 | Vault init/unseal/policy/seed | KV와 Kubernetes auth 준비 |
| 6 | `20-secrets` | data 선행 destination Secret 생성 |
| 7 | `30-data` | PostgreSQL/MinIO/Keycloak Ready |
| 8 | MinIO registry provision task | bucket/access key 생성 후 Vault 기록 |
| 9 | `35-registry` | registry Secret 생성과 Deployment rollout 완료 |
| 10 | `40-operations` | Flyway Complete, RealmImport Done |
| 11 | `50-apps` | auth-server/oauth2-proxy rollout 완료 |
| 디렉토리 | 역할 |
|---|---|
| `bin/` | 사용자 진입점. `bootstrap.sh` / `teardown.sh` |
| `ci/` | CI / 로컬 검증. `validate.sh` (kustomize + kubeconform + kube-linter) |
| `lib/` | 공통 Bash 라이브러리. `common.sh` (strict mode / trap / log / confirm / retry / mask_secret) + `vault.sh` |
| `tasks/` | 재사용 작업. `vault-init.sh` / `vault-seed-apps.sh` / `vso-install.sh` |
`gitops/clusters/lab/main/all`은 절대 apply하지 않습니다.
모든 쉘 스크립트는 `set -Eeuo pipefail` + `IFS=$'\n\t'` + `trap_cleanup` 으로 공통 에러 처리. root token / registry BasicAuth 같은 민감 값은 **stdin 파이프** 로만 전달하고 stdout 에 찍지 않는다.
## Vault init material
## 검증 (validate.sh)
기본 lab 경로는 repo root의 ignored `vault-init-keys.json`입니다. 스크립트는
`0600`으로 쓰지만 암호화 파일은 아닙니다. `VAULT_KEYS_FILE`로 repo 밖의
안전한 위치를 지정하는 방식을 권장하며 prod에서는 필수입니다.
키, root token, password, MinIO secret key를 argv로 전달하지 않습니다.
unseal/login, JSON 조립, Vault 기록은 stdin 경로를 사용합니다.
`docker-registry/minio`는 일반 seed 대상이 아닙니다. `30-data`에서 MinIO가
Ready가 된 뒤 MinIO가 bucket-scoped access key를 생성하고, bootstrap task가
그 결과를 Vault에 기록합니다. `35-registry`는 그 이후에만 VSO CR과 registry
Deployment를 적용하므로 missing Secret 상태의 Pod를 만들지 않습니다.
## Secret rotation
VSO destination은 `overwrite: true`로 선언되어 Vault 변경을 Kubernetes
Secret에 반영합니다. auth-server와 oauth2-proxy는 지원되는 Secret 변경 시
rollout target을 사용합니다.
다음 credential은 외부 시스템 상태와 함께 회전해야 하므로 Vault 값만 바꾸면
안 됩니다.
- PostgreSQL role password
- Keycloak DB password
- MinIO access key credential
- registry basic-auth/pull credential
각 소비자와 backend credential을 순서대로 갱신하고 stage health를 확인하는
별도 rotation runbook이 필요합니다.
## Teardown
기본 teardown은 앱과 one-shot operation만 삭제합니다.
```bash
bash k8s/scripts/ci/validate.sh
bash scripts/bin/teardown.sh lab
```
3 단계:
데이터, Vault, namespace까지 삭제하려면 명시적으로 opt-in합니다.
1. 각 overlay 에 대해 `kustomize build` (환경 중립성 / patch 유효성)
2. 렌더 결과에 `kubeconform -strict -ignore-missing-schemas` (Kubernetes OpenAPI + Datree CRD catalog)
3. 렌더 결과에 `kube-linter lint --config .kube-linter.yaml` (securityContext / resources / PSS / image tag 등)
`.kube-linter.yaml`**블록 단위 분석으로 생기는 컨텍스트 오탐 4 종**(`dangling-service`, `non-existent-service-account`, `mismatching-selector`, `no-anti-affinity`) 만 제외한다. 나머지는 모두 활성.
목표 상태:
```
k8s/overlays/dev build=ok schema=ok lint=ok
k8s/overlays/dev/vso build=ok schema=ok lint=ok
```bash
DELETE_DATA=yes bash scripts/bin/teardown.sh lab
```
## 환경별 배포
공유 operator와 cluster-scoped 리소스까지 삭제하는 것은 전용 lab cluster에서만
사용합니다.
현재 `dev` overlay 만 완성. `staging` / `prod` 는 의도적으로 비어 있고 추후 확장 예정. validate.sh 는 `kustomization.yaml` 이 없는 환경을 자동 스킵한다 — 빈 overlay 가 CI 를 빨갛게 만들지 않기 위함.
```bash
DELETE_DATA=yes TEARDOWN_PLATFORM=yes \
bash scripts/bin/teardown.sh lab
```
### 계획된 환경별 차등
`FORCE_FINALIZERS=yes`는 정상 삭제가 반복해서 실패한 namespace 복구의 최후
수단입니다. orphaned volume과 controller state를 만들 수 있습니다.
| 리소스 | dev | staging | prod |
|---|---|---|---|
| Vault replicas / storage | 1 / 1Gi | 1 / 5Gi | 3 (HA Raft) / 20Gi |
| Registry replicas / storage | 1 / 5Gi | 1 / 10Gi | 2 / 50Gi |
| PostgreSQL retention policy | Delete | Retain | Retain |
| 이미지 tag 정책 | semver tag | semver tag | `@sha256:` digest pin |
| TLS | 비활성화 | cert-manager | cert-manager + HSTS |
## Validation
prod 승격 시 필수 작업:
```bash
make check
```
- Vault storage `file``raft` + KMS auto-unseal
- Postgres backup CronJob (Velero / pgBackRest)
- cert-manager ClusterIssuer 로 TLS 전환
- 이미지 tag → digest pin
로컬 profile은 render를 항상 수행하고 설치되지 않은 부가 도구는 알려준 뒤
건너뜁니다. full profile은 다음 도구가 모두 없으면 실패합니다.
- kustomize 또는 kubectl
- kubeconform
- kube-linter
- shellcheck
- shfmt
- gitleaks
```bash
mise install
VALIDATION_PROFILE=full make check
```
Gitea workflow는 full profile을 실행합니다. 검증 entrypoint의 source of truth는
`tests/kustomize-entrypoints.txt`입니다.
## External incident actions
현재 tree에서 민감 파일을 untrack/ignore하는 것만으로 과거 노출은 해결되지
않습니다. 다음 작업은 live Vault와 모든 협업자에게 영향을 주므로 repository
refactor와 분리합니다.
1. root token과 unseal/recovery material 회전
2. 영향 credential 전체 회전
3. 백업과 감사 로그에서 노출 범위 확인
4. 협업자에게 force-fetch/reclone 절차 공지
5. 승인된 maintenance window에서 원격 Git history 정리