refactor: 폴더 구조 변경
This commit is contained in:
@@ -96,41 +96,38 @@ spec:
|
||||
## 좋은 예시 2: multi-region prod overlay 디렉터리 (kr-main + kr-dr)
|
||||
|
||||
```text
|
||||
k8s/
|
||||
base/
|
||||
app/
|
||||
units/
|
||||
identity/
|
||||
auth/
|
||||
gitops/
|
||||
apps/
|
||||
identity-auth/
|
||||
base/
|
||||
kustomization.yaml
|
||||
deployment.yaml
|
||||
service.yaml
|
||||
servicemonitor.yaml
|
||||
pdb.yaml
|
||||
hpa.yaml
|
||||
overlays/
|
||||
dev/
|
||||
staging/
|
||||
prod/
|
||||
kr-main/
|
||||
kustomization.yaml
|
||||
deployment.yaml
|
||||
service.yaml
|
||||
servicemonitor.yaml
|
||||
pdb.yaml
|
||||
hpa.yaml
|
||||
plugins/
|
||||
ingress-nginx/
|
||||
cert-manager/
|
||||
external-secrets/
|
||||
managing/
|
||||
flyway-migrate-identity/
|
||||
overlays/
|
||||
dev/
|
||||
kustomization.yaml
|
||||
staging/
|
||||
kustomization.yaml
|
||||
prod/
|
||||
kr-main/
|
||||
kustomization.yaml
|
||||
patches/
|
||||
auth-replicas.yaml
|
||||
auth-resources.yaml
|
||||
auth-topology-spread.yaml
|
||||
kr-dr/
|
||||
kustomization.yaml
|
||||
patches/
|
||||
auth-replicas.yaml
|
||||
auth-image-pull-mirror.yaml
|
||||
patches/
|
||||
kr-dr/
|
||||
kustomization.yaml
|
||||
patches/
|
||||
flyway-migrate-identity/
|
||||
base/
|
||||
overlays/
|
||||
platform/
|
||||
ingress-nginx/
|
||||
cert-manager/
|
||||
secret-delivery/
|
||||
clusters/
|
||||
dev/main/
|
||||
staging/main/
|
||||
prod/kr-main/
|
||||
prod/kr-dr/
|
||||
```
|
||||
|
||||
**왜 좋은가:**
|
||||
@@ -375,7 +372,7 @@ spec:
|
||||
image: registry.example.com/auth:1.24.3
|
||||
```
|
||||
|
||||
**문제:** `selector.matchLabels`는 Deployment/StatefulSet에서 **immutable**이다. `version`은 배포마다 바뀌고 `environment`는 overlay가 주입한다 → 첫 배포 이후 재apply 시 `field is immutable` 에러로 영구 차단. selector에는 불변 3종(`name`/`instance`/`component`)만.
|
||||
**문제:** `selector.matchLabels`는 Deployment/StatefulSet에서 **immutable**이다. `version`은 배포마다 바뀌고 `environment`는 overlay가 주입한다 → 첫 배포 이후 재apply 시 `field is immutable` 에러로 영구 차단. selector에는 불변 2종(`name`/`instance`)만.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -600,7 +600,7 @@ resources:
|
||||
- aescbc:
|
||||
keys:
|
||||
- name: fallback-2026-q1
|
||||
secret: c2VjcmV0LTMyLWJ5dGUtZmFsbGJhY2sta2V5LTIwMjZxMS1leGFtcGxl
|
||||
secret: <kms-fallback-key-base64>
|
||||
- identity: {}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# db / migration 예시
|
||||
|
||||
모든 YAML은 `kubectl apply` 가능하다. 상세 Flyway Job 예시는 `examples/infra/flyway.md` 참조.
|
||||
모든 YAML은 `kubectl apply` 가능하다. 상세 Flyway Job 예시는
|
||||
`docs/examples/infra/flyway.md` 참조.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ metadata:
|
||||
app.kubernetes.io/managed-by: keycloak-operator
|
||||
spec:
|
||||
instances: 3
|
||||
image: registry.example.com/platform/keycloak:26.0.7-optimized
|
||||
image: registry.example.com/platform/keycloak:26.0.7-optimized # gitleaks:allow
|
||||
startOptimized: true
|
||||
db:
|
||||
vendor: postgres
|
||||
|
||||
@@ -8,35 +8,39 @@ kubectl kustomize <dir> | kubectl apply --server-side --field-manager=ci --dry-r
|
||||
|
||||
---
|
||||
|
||||
## 좋은 예시 1: base / components / overlays 전체 구조 + 실제 base `kustomization.yaml`
|
||||
## 좋은 예시 1: catalog unit의 base / components / overlays 구조
|
||||
|
||||
```text
|
||||
k8s/
|
||||
base/
|
||||
app/units/identity/auth/
|
||||
kustomization.yaml
|
||||
deployment.yaml
|
||||
service.yaml
|
||||
servicemonitor.yaml
|
||||
pdb.yaml
|
||||
hpa.yaml
|
||||
components/
|
||||
with-topology-spread-zone/
|
||||
kustomization.yaml
|
||||
patch.yaml
|
||||
with-pdb-tier1/
|
||||
kustomization.yaml
|
||||
patch.yaml
|
||||
overlays/
|
||||
gitops/
|
||||
apps/
|
||||
identity-auth/
|
||||
base/
|
||||
kustomization.yaml
|
||||
deployment.yaml
|
||||
service.yaml
|
||||
servicemonitor.yaml
|
||||
pdb.yaml
|
||||
hpa.yaml
|
||||
components/
|
||||
with-topology-spread-zone/
|
||||
kustomization.yaml
|
||||
patch.yaml
|
||||
with-pdb-tier1/
|
||||
kustomization.yaml
|
||||
patch.yaml
|
||||
overlays/
|
||||
prod/kr-main/
|
||||
kustomization.yaml
|
||||
patches/
|
||||
auth-resources.yaml
|
||||
auth-ingress-host.yaml
|
||||
clusters/
|
||||
prod/kr-main/
|
||||
kustomization.yaml
|
||||
patches/
|
||||
auth-resources.yaml
|
||||
auth-ingress-host.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
# k8s/base/app/units/identity/auth/kustomization.yaml
|
||||
# gitops/apps/identity-auth/base/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
@@ -66,7 +70,7 @@ labels:
|
||||
## 좋은 예시 2: base Deployment (완전 apply-ready)
|
||||
|
||||
```yaml
|
||||
# k8s/base/app/units/identity/auth/deployment.yaml
|
||||
# gitops/apps/identity-auth/base/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -206,12 +210,12 @@ spec:
|
||||
## 좋은 예시 3: overlay prod/kr-main — 환경 차이만
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kr-main/kustomization.yaml
|
||||
# gitops/apps/identity-auth/overlays/prod/kr-main/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: prod-identity-auth
|
||||
resources:
|
||||
- ../../../base/app/units/identity/auth
|
||||
- ../../../base
|
||||
components:
|
||||
- ../../../components/with-topology-spread-zone
|
||||
- ../../../components/with-pdb-tier1
|
||||
@@ -246,7 +250,7 @@ patches:
|
||||
```
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kr-main/patches/auth-resources.yaml
|
||||
# gitops/apps/identity-auth/overlays/prod/kr-main/patches/auth-resources.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -302,7 +306,7 @@ spec:
|
||||
## 좋은 예시 4: Kustomize Component — `with-pdb-tier1`
|
||||
|
||||
```yaml
|
||||
# k8s/components/with-pdb-tier1/kustomization.yaml
|
||||
# gitops/apps/identity-auth/components/with-pdb-tier1/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
resources:
|
||||
@@ -310,7 +314,7 @@ resources:
|
||||
```
|
||||
|
||||
```yaml
|
||||
# k8s/components/with-pdb-tier1/pdb.yaml
|
||||
# gitops/apps/identity-auth/components/with-pdb-tier1/pdb.yaml
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
@@ -343,7 +347,7 @@ spec:
|
||||
## 좋은 예시 5: ConfigMap generator + hash suffix를 활용한 자동 rollout
|
||||
|
||||
```yaml
|
||||
# k8s/base/app/units/identity/auth/kustomization.yaml (with generator)
|
||||
# gitops/apps/identity-auth/base/kustomization.yaml (with generator)
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
@@ -373,7 +377,7 @@ generatorOptions:
|
||||
## 좋은 예시 6: HPA v2 + behavior (base 리소스)
|
||||
|
||||
```yaml
|
||||
# k8s/base/app/units/identity/auth/hpa.yaml
|
||||
# gitops/apps/identity-auth/base/hpa.yaml
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
@@ -433,12 +437,12 @@ spec:
|
||||
## 나쁜 예시 1: `commonLabels`로 environment 주입 → selector immutable 에러
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kustomization.yaml (BAD)
|
||||
# gitops/apps/identity-auth/overlays/prod/kustomization.yaml (BAD)
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
namespace: prod-identity-auth
|
||||
resources:
|
||||
- ../../base/app/units/identity/auth
|
||||
- ../../base
|
||||
commonLabels:
|
||||
example.com/environment: prod
|
||||
```
|
||||
@@ -450,10 +454,10 @@ commonLabels:
|
||||
## 나쁜 예시 2: overlay가 base를 거의 재작성
|
||||
|
||||
```text
|
||||
k8s/base/app/units/identity/auth/deployment.yaml (150 lines)
|
||||
k8s/overlays/prod/deployment.yaml (140 lines, 95% identical)
|
||||
k8s/overlays/staging/deployment.yaml (140 lines)
|
||||
k8s/overlays/dev/deployment.yaml (135 lines)
|
||||
gitops/apps/identity-auth/base/deployment.yaml (150 lines)
|
||||
gitops/apps/identity-auth/overlays/prod/deployment.yaml (140 lines, 95% identical)
|
||||
gitops/apps/identity-auth/overlays/staging/deployment.yaml (140 lines)
|
||||
gitops/apps/identity-auth/overlays/dev/deployment.yaml (135 lines)
|
||||
```
|
||||
|
||||
**문제:** overlay가 base의 95%를 복붙 + 몇 줄 수정. drift 발생 시점부터 base가 의미 없어진다. 해결: overlay는 `patches:` + `images:` + `replicas:` + `labels:`만 쓰고 전체 리소스는 base에서 가져온다.
|
||||
@@ -463,7 +467,7 @@ k8s/overlays/dev/deployment.yaml (135 lines)
|
||||
## 나쁜 예시 3: 운영 secret을 `secretGenerator`로 plaintext Git 커밋
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kustomization.yaml (BAD)
|
||||
# gitops/apps/identity-auth/overlays/prod/kustomization.yaml (BAD)
|
||||
secretGenerator:
|
||||
- name: auth-secrets
|
||||
literals:
|
||||
@@ -478,7 +482,7 @@ secretGenerator:
|
||||
## 나쁜 예시 4: `patchesStrategicMerge` / `patchesJson6902` (deprecated)
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kustomization.yaml (BAD, v5 deprecated)
|
||||
# gitops/apps/identity-auth/overlays/prod/kustomization.yaml (BAD, v5 deprecated)
|
||||
patchesStrategicMerge:
|
||||
- patches/auth-resources.yaml
|
||||
patchesJson6902:
|
||||
@@ -497,7 +501,7 @@ patchesJson6902:
|
||||
## 나쁜 예시 5: base에 환경 host / domain 고정
|
||||
|
||||
```yaml
|
||||
# k8s/base/app/units/identity/auth/ingress.yaml (BAD)
|
||||
# gitops/apps/identity-auth/base/ingress.yaml (BAD)
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
@@ -523,11 +527,11 @@ spec:
|
||||
## 나쁜 예시 6: `bases:` 사용 (v2.1에서 `resources:`로 통합됨)
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kustomization.yaml (BAD)
|
||||
# gitops/apps/identity-auth/overlays/prod/kustomization.yaml (BAD)
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
bases:
|
||||
- ../../base/app/units/identity/auth
|
||||
- ../../base
|
||||
```
|
||||
|
||||
**문제:** `bases:`는 v2.1에서 `resources:`에 흡수됨. 신규 코드에서 사용 금지. 해결: `resources:` 사용.
|
||||
@@ -537,7 +541,7 @@ bases:
|
||||
## 나쁜 예시 7: HPA가 있는 Deployment에 overlay `replicas:`로 고정값 주입
|
||||
|
||||
```yaml
|
||||
# k8s/overlays/prod/kustomization.yaml (BAD — conflicts with HPA)
|
||||
# gitops/apps/identity-auth/overlays/prod/kustomization.yaml (BAD — conflicts with HPA)
|
||||
replicas:
|
||||
- name: auth
|
||||
count: 3
|
||||
|
||||
@@ -581,7 +581,7 @@ metadata:
|
||||
namespace: minio-prod
|
||||
type: Opaque
|
||||
stringData:
|
||||
token: "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9..."
|
||||
token: "<minio-prometheus-token>"
|
||||
---
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
@@ -636,42 +636,31 @@ data:
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
mc alias set minio https://minio.minio-prod.svc.cluster.local "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" --api S3v4
|
||||
mc --config-dir /tmp/mc alias import minio <<EOF
|
||||
{
|
||||
"url": "https://minio.minio-prod.svc.cluster.local",
|
||||
"accessKey": "$MINIO_ROOT_USER",
|
||||
"secretKey": "$MINIO_ROOT_PASSWORD",
|
||||
"api": "s3v4",
|
||||
"path": "auto"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Object Lock은 bucket 생성 시점에만 활성화 가능
|
||||
mc mb --with-lock minio/critical-audit || true
|
||||
mc retention set --default COMPLIANCE 2555d minio/critical-audit # 7년 보관
|
||||
mc --config-dir /tmp/mc mb --with-lock minio/critical-audit || true
|
||||
mc --config-dir /tmp/mc retention set --default COMPLIANCE 2555d minio/critical-audit
|
||||
|
||||
# Versioning + lifecycle
|
||||
mc mb minio/app-data || true
|
||||
mc version enable minio/app-data
|
||||
mc ilm add --expire-noncurrent-days 90 minio/app-data
|
||||
mc ilm add --expire-incomplete-upload-days 7 minio/app-data
|
||||
mc --config-dir /tmp/mc mb minio/app-data || true
|
||||
mc --config-dir /tmp/mc version enable minio/app-data
|
||||
mc --config-dir /tmp/mc ilm add --expire-noncurrent-days 90 minio/app-data
|
||||
mc --config-dir /tmp/mc ilm add --expire-incomplete-upload-days 7 minio/app-data
|
||||
|
||||
# SSE-KMS 기본 적용
|
||||
mc encrypt set sse-kms minio-app-key minio/app-data
|
||||
mc encrypt set sse-kms minio-critical-key minio/critical-audit
|
||||
|
||||
# Service account 발급 (앱 전용, 최소 권한 policy)
|
||||
mc admin policy create minio auth-server-rw /policies/auth-server-rw.json
|
||||
mc admin user svcacct add minio "$MINIO_ROOT_USER" \
|
||||
--access-key "$AUTH_SERVER_ACCESS_KEY" \
|
||||
--secret-key "$AUTH_SERVER_SECRET_KEY" \
|
||||
--policy /policies/auth-server-rw.json || true
|
||||
mc --config-dir /tmp/mc encrypt set sse-kms minio-app-key minio/app-data
|
||||
mc --config-dir /tmp/mc encrypt set sse-kms minio-critical-key minio/critical-audit
|
||||
|
||||
echo "bootstrap complete"
|
||||
|
||||
auth-server-rw.json: |
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket"],
|
||||
"Resource": ["arn:aws:s3:::app-data/*", "arn:aws:s3:::app-data"]
|
||||
}
|
||||
]
|
||||
}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
@@ -703,21 +692,11 @@ spec:
|
||||
secretKeyRef:
|
||||
name: minio-root-creds
|
||||
key: password
|
||||
- name: AUTH_SERVER_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: auth-server-minio-svcacct
|
||||
key: access_key
|
||||
- name: AUTH_SERVER_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: auth-server-minio-svcacct
|
||||
key: secret_key
|
||||
volumeMounts:
|
||||
- name: scripts
|
||||
mountPath: /scripts
|
||||
- name: policies
|
||||
mountPath: /policies
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
@@ -734,12 +713,10 @@ spec:
|
||||
items:
|
||||
- key: init.sh
|
||||
path: init.sh
|
||||
- name: policies
|
||||
configMap:
|
||||
name: minio-bootstrap
|
||||
items:
|
||||
- key: auth-server-rw.json
|
||||
path: auth-server-rw.json
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 64Mi
|
||||
```
|
||||
|
||||
**왜 좋은가:**
|
||||
@@ -747,7 +724,8 @@ spec:
|
||||
- `mc mb --with-lock`은 bucket 생성 시점에만 Object Lock 활성화 가능 — Job이 그 타이밍을 보장
|
||||
- COMPLIANCE 모드 7년 retention = 감사/규제 요구 충족 (root도 bypass 불가)
|
||||
- `app-data` bucket은 versioning + lifecycle (90일 noncurrent expire + 7일 incomplete abort)
|
||||
- service account는 특정 bucket prefix만 접근 가능한 policy로 제한
|
||||
- 애플리케이션 access key 발급은 별도 bootstrap에서 inline 최소 권한 policy와
|
||||
함께 수행하고, 생성 secret은 Vault로 직접 전달
|
||||
- `backoffLimit: 3` + idempotent 명령 (`|| true`) → 재실행 안전
|
||||
|
||||
---
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
|
||||
```bash
|
||||
# 1) render
|
||||
kubectl kustomize k8s/overlays/prod > /tmp/render.yaml
|
||||
kubectl kustomize gitops/clusters/prod/main/stages/50-apps > /tmp/render.yaml
|
||||
|
||||
# 2) diff
|
||||
kubectl diff -k k8s/overlays/prod
|
||||
kubectl diff -k gitops/clusters/prod/main/stages/50-apps
|
||||
|
||||
# 3) apply
|
||||
kubectl apply -k k8s/overlays/prod
|
||||
kubectl apply -k gitops/clusters/prod/main/stages/50-apps
|
||||
|
||||
# 4) rollout status with timeout
|
||||
kubectl rollout status deployment/auth-server -n auth-prod --timeout=10m
|
||||
@@ -607,10 +607,10 @@ kubectl get pods -A -o wide --field-selector spec.nodeName="${NODE}"
|
||||
git checkout v1.24.0
|
||||
|
||||
# 2) diff
|
||||
kubectl diff -k k8s/overlays/prod
|
||||
kubectl diff -k gitops/clusters/prod/main/stages/50-apps
|
||||
|
||||
# 3) apply
|
||||
kubectl apply -k k8s/overlays/prod
|
||||
kubectl apply -k gitops/clusters/prod/main/stages/50-apps
|
||||
|
||||
# 4) rollout status
|
||||
kubectl rollout status deployment/auth-server -n auth-prod --timeout=10m
|
||||
@@ -627,7 +627,7 @@ kubectl rollout status deployment/auth-server -n auth-prod --timeout=10m
|
||||
## 나쁜 예시 1: diff 없이 apply
|
||||
|
||||
```bash
|
||||
kubectl apply -k k8s/overlays/prod
|
||||
kubectl apply -k gitops/clusters/prod/main/stages/50-apps
|
||||
```
|
||||
|
||||
**문제:**
|
||||
|
||||
@@ -106,8 +106,8 @@ Environment:
|
||||
CONFIRM=yes non-interactive confirmation (alternative to --yes)
|
||||
|
||||
Examples:
|
||||
render-diff-apply --overlay k8s/overlays/prod --context prod-eu
|
||||
CONFIRM=yes render-diff-apply --overlay k8s/overlays/prod --context prod-eu --timeout 15m
|
||||
render-diff-apply --overlay gitops/clusters/prod/main/stages/50-apps --context prod-eu
|
||||
CONFIRM=yes render-diff-apply --overlay gitops/clusters/prod/main/stages/50-apps --context prod-eu --timeout 15m
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ spec:
|
||||
- stateless 장기 실행 → Deployment 정답
|
||||
- PDB + HPA + topologySpread (zone+hostname) 모두 tier-1에 맞게 동반
|
||||
- digest pinning, restricted PodSecurity 호환, preStop sleep으로 graceful drain
|
||||
- selector에는 불변 3종만 (version/environment 없음)
|
||||
- selector에는 불변 2종만 (`name`/`instance`; version/environment 없음)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user