# workload selection 기준 ## 목적 이 문서는 각 컴포넌트를 - Deployment - StatefulSet - DaemonSet - Job - CronJob 중 무엇으로 배포할지 먼저 고정한다. 목표: - 상태 저장 / 무상태 / 노드로컬 / 일회성 / 주기성 워크로드를 섞지 않는다 - PVC가 필요하다는 이유만으로 StatefulSet을 선택하는 실수를 막는다 - Ingress controller / CNI / CSI / 로그 shipper / node-exporter 같은 노드로컬 에이전트를 Deployment로 배포하는 실수를 막는다 - migration / bootstrap / 백업을 장기 실행 앱과 분리한다 - 1000+ 서비스 스케일에서 operator-managed 패턴이 기본인 영역(DB, Kafka, monitoring)은 operator를 기본 선택으로 문서화한다 ## 공식 의미 (근거) - **Deployment**: stateless 장기 실행. `spec.replicas` 기반 수평 확장. ReplicaSet으로 rolling update. `https://kubernetes.io/docs/concepts/workloads/controllers/deployment/`. - **StatefulSet**: stable network identity, stable persistent storage, ordered deployment/scaling. 각 Pod는 `-` 이름을 가지고 PVC가 `volumeClaimTemplates`로 자동 생성. `persistentVolumeClaimRetentionPolicy` (GA since 1.27) 필드: 기본값 `{whenDeleted: Retain, whenScaled: Retain}`. `podManagementPolicy` (OrderedReady / Parallel). `updateStrategy` (RollingUpdate / OnDelete). - **DaemonSet**: 선택된 모든 노드에 정확히 한 Pod를 실행. 노드 추가/제거에 따라 자동 생성/삭제. `https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/`. - **Job**: 한 번 실행되어 완료. `restartPolicy: Never | OnFailure`. `backoffLimit` / `activeDeadlineSeconds` / `ttlSecondsAfterFinished` / `parallelism` / `completions`. - **CronJob**: 시간 기반 스케줄 Job. `concurrencyPolicy: Allow | Forbid | Replace`, `startingDeadlineSeconds`, `successfulJobsHistoryLimit` / `failedJobsHistoryLimit`. - **Operator pattern**: CRD + controller. 1000-서비스 스케일에서 DB/Kafka/Redis/monitoring은 사실상 Deployment/StatefulSet을 직접 쓰지 않고 operator가 소유. ## 기본 규칙 ### 1. 기본 선택 기준은 "상태 + 수명 + 배치 위치" 3축으로 먼저 분류: 1. **수명**: 장기 실행 / 일회성 / 주기성 2. **상태**: stable identity + persistent storage 필요 / 불필요 3. **배치**: 노드별 한 Pod 필요 / cluster-wide 자유 배치 매핑: - 장기 + 무상태 + 자유 배치 → **Deployment** - 장기 + stateful + 자유 배치 → **StatefulSet** (또는 operator) - 장기 + 무상태 + 노드별 한 Pod → **DaemonSet** - 일회성 → **Job** - 주기성 → **CronJob** ### 2. Deployment는 stateless 장기 실행 기본값 조건: - Pod identity가 교체 가능 - durable state가 외부 DB / 외부 storage / 외부 cache에 있음 - 수평 확장이 자연스러움 - Pod 이름 / 순서가 의미 없음 적용 후보: - `auth-server` - `test-server` (장기 실행 모드) - 외부 DB 사용하는 `keycloak` - 대부분의 stateless API / worker **필수 동반 리소스 (replicas≥2인 prod 워크로드):** - `PodDisruptionBudget` (minAvailable ≥ 50% 또는 SLO tier에 맞춘 값) - `HorizontalPodAutoscaler` v2 (behavior 포함) - `topologySpreadConstraints` (zone + hostname) - `ServiceMonitor` 또는 Prometheus scrape annotation ### 3. StatefulSet은 "stable identity + storage" 모두 맞을 때만 조건 중 하나라도 강하면: - stable network identity (DNS name per replica) 필요 - stable persistent storage per Pod 필요 - ordered rollout / termination 필요 - replica 간 peer discovery가 ordinal에 의존 적용 후보: - `postgres` (operator 없을 때 — 있으면 CloudNativePG 같은 operator 우선) - `minio` (MinIO Operator 가능) - `vault` (Raft storage mode) - `etcd` (외부) - `kafka`, `zookeeper` (Strimzi operator 우선) - `elasticsearch` (ECK operator 우선) **필수 선언**: - `serviceName` (headless Service 참조) - `volumeClaimTemplates` - `podManagementPolicy: OrderedReady` 기본. Parallel은 peer discovery가 순서를 요구하지 않을 때만. - `updateStrategy: RollingUpdate` + `partition`으로 canary rollout - `persistentVolumeClaimRetentionPolicy` 명시 (prod 기본 `{whenDeleted: Retain, whenScaled: Retain}`) ### 4. DaemonSet은 노드 전역 에이전트 전용 조건: - 노드별 한 개만 떠야 함 (또는 특정 노드 group에 한 개) - 노드 추가/제거에 자동 반응 - hostPath / hostNetwork / hostPID 필요한 경우 다수 적용 후보: - 로그 shipper: `fluent-bit`, `fluentd`, `vector` - metric exporter: `node-exporter`, `cadvisor` - CNI agent: `calico-node`, `cilium-agent` - CSI node plugin: `longhorn-manager`, `ceph-csi-node` - security agent: `falco`, `tetragon` - service mesh node proxy: `istio-cni-node` - ingress-nginx **DaemonSet 모드** (edge 노드가 고정되고 모든 edge 노드가 80/443 HostPort / hostNetwork로 외부 노출해야 할 때) **Ingress controller: DaemonSet vs Deployment 결정**: - **Deployment** + `Service type=LoadBalancer` (MetalLB / 외부 LB): 기본 권장. 노드와 ingress replica 수가 분리됨. HPA 적용 가능. - **DaemonSet** + `hostNetwork: true` / HostPort 80,443: bare-metal + 외부 LB 없이 모든 노드가 ingress가 되어야 할 때. 80/443 노드 포트 점유, HPA 불가, 노드 수 = replica 수. **필수**: - `tolerations`로 노드 taint (예: `node-role.kubernetes.io/control-plane`) 대응 결정 - `nodeSelector` 또는 `affinity`로 대상 노드 그룹 명시 (label 기반) - `updateStrategy: RollingUpdate` + `maxUnavailable` 지정 - `priorityClassName: system-node-critical` (필수 인프라 에이전트) ### 5. PVC가 있다고 무조건 StatefulSet 아니다 체크리스트: - Pod마다 고유한 storage identity 필요? 아니면 단일 PVC 공유? - Pod 이름 / 순서가 의미 있나? - peer discovery가 stable DNS name에 의존? 아니면: - **단일 replica Deployment + PVC (ReadWriteOnce)** 도 유효 - **Deployment + ReadWriteMany PVC** (여러 replica가 동일 storage 공유) 도 유효 (shared cache 등) ### 6. Job은 migration / bootstrap / one-off 기본값 적용 후보: - `flyway-migrate` / `liquibase-migrate` - schema validation - 초기 admin 사용자 bootstrap - 데이터 리페어 / 정리 - 이미지 빌드 trigger **필수**: - `restartPolicy: Never` (실패 원인 디버깅 가능) 또는 `OnFailure` (transient 실패 재시도) - `backoffLimit` 명시 (기본값 6은 prod에서 너무 관대할 수 있음) - `activeDeadlineSeconds` (무한 실행 방지) - `ttlSecondsAfterFinished` (완료 Job 자동 정리, 1000-서비스 스케일 필수) - ServiceAccount 최소 권한 ### 7. CronJob은 주기 실행 전용 적용 후보: - etcd / DB 백업 - 정기 정리 (old PVC, old Snapshot, old Job) - 정기 검증 / 리포트 - 비즈니스 배치 (야간 집계) **필수**: - `concurrencyPolicy: Forbid` 기본 (동시 실행 방지). 멱등하면 `Allow`. - `startingDeadlineSeconds` (노드 장애로 miss 된 job 무한 누적 방지) - `successfulJobsHistoryLimit: 3` / `failedJobsHistoryLimit: 5` - schedule timezone 명시 (`spec.timeZone` v1.25+) 금지: - 항상 떠 있어야 하는 서버를 CronJob으로 배포 - 본 서비스 온라인 처리를 CronJob에 의존 ### 8. Stateful workload는 retention / scale-down 정책을 먼저 박는다 StatefulSet의 `persistentVolumeClaimRetentionPolicy`: - `whenDeleted` (StatefulSet이 삭제될 때 PVC 처리): `Retain` (기본) / `Delete` - `whenScaled` (replica 축소될 때 PVC 처리): `Retain` (기본) / `Delete` **prod 기본**: `{whenDeleted: Retain, whenScaled: Retain}` (기본값). DB/Vault/MinIO 모두 여기서 이탈하지 않는다. **dev/staging**: `{whenDeleted: Delete, whenScaled: Delete}` 허용 (클러스터 재생성 시 자동 정리). ### 9. 외부 DB를 쓰는 앱 서버는 stateless 우선 Pod에 durable state가 없으면 Deployment. Pod identity가 고정되어야 한다는 이유만으로 StatefulSet 선택 금지. 기준: - `auth-server` → Deployment - 외부 DB 사용 `keycloak` → Deployment (caching은 external Redis / Infinispan cluster) - 외부 object store 사용 앱 → Deployment ### 10. Keycloak은 앱 레이어와 저장소를 분리 Keycloak 서버 자체는 stateless로 다룬다. - **외부 DB (PostgreSQL)** 사용이 prod 기본 - session / cache는 Infinispan embedded 또는 remote 모드 결정 (remote 선호, replica 간 peer discovery는 Kubernetes DNS) - **Deployment** + externalTrafficPolicy 고려 - HA replica ≥ 2 + PDB ### 11. Vault는 모드별로 다르다 - **dev mode**: 학습 전용. prod 절대 금지. - **standalone (file storage)**: StatefulSet + PVC. replica=1. 단일 장애점. - **HA Raft**: StatefulSet (integrated storage). replica 3 또는 5. `podManagementPolicy: Parallel` 허용. - **HA Consul backend**: StatefulSet (Vault) + StatefulSet (Consul). operator 권장. - **external Vault**: 클러스터 내부 서버 없음, ExternalSecrets로 참조만. prod 권장: **HA Raft mode StatefulSet (replica 3)** 또는 **external Vault**. ### 12. MinIO는 Operator 기본 (StatefulSet은 fallback) 1000-서비스 스케일에서 MinIO는 MinIO Operator + `Tenant` CRD가 기본. tenant가 StatefulSet을 내부적으로 생성. raw StatefulSet은 단일 node/dev 환경에서만 예외 허용. ### 13. Flyway는 Job 기본값 - 앱 startup 내부 migration 금지 (앱 부팅 실패와 migration 실패가 섞임) - Flyway Job이 선행되고 Success 후에 Deployment rollout - ArgoCD PostSync hook 또는 Argo Workflows로 순서 제어 - `migrate`, `validate`, `info`, `repair` 각각 독립 Job ### 14. Ingress controller 배치 결정 prod 권장: - **ingress-nginx Deployment** + `Service type=LoadBalancer` (MetalLB L2 또는 BGP, 또는 외부 LB) - 또는 **Envoy Gateway / Gateway API 기반 Deployment** - HPA 가능, PDB 필수 (tier-1 로 취급) - 복수 IngressClass (`nginx-public`, `nginx-internal`) 분리 DaemonSet 선택 조건: - edge 노드가 고정되어 있고 hostNetwork 80/443이 필요 - 외부 LB가 없고 DNS round-robin으로 다수 노드 IP 노출 ### 15. DB는 operator 기본, StatefulSet은 fallback 1000-서비스 스케일의 PostgreSQL: - **CloudNativePG Operator** 기본 → `Cluster` CRD. operator가 StatefulSet/Service/Secret/ConfigMap/Backup 전부 관리. - **Zalando Postgres Operator**도 대안 - raw StatefulSet은 dev / 특수 케이스에만 MySQL/MariaDB: - **MariaDB Operator** / **mysql-operator** Redis: - **Spotahome redis-operator** / **Redis Enterprise Operator** - cluster 모드면 StatefulSet, sentinel 모드면 Deployment(sentinel) + StatefulSet(redis) ### 16. Batch / 대량 병렬은 Job + `parallelism` + IndexedJob 단일 Job으로 수천 개 task 병렬 실행: - `completionMode: Indexed` + `parallelism: N` - 각 Pod가 `JOB_COMPLETION_INDEX` env로 자기 작업 식별 - 더 복잡한 DAG는 Argo Workflows / Tekton ### 17. workload 종류만 맞는다고 품질이 보장되지 않는다 최종 결정 전 동반 표준 확인: - `storage-pvc.md` (StorageClass / volumeClaimTemplate / snapshot) - `network-ingress-tls.md` (ingressClassName / TLS) - `resources-probes-availability.md` (PDB / HPA / probe / resources) - `backup-restore.md` (RPO / RTO / 절차) - `security-podsecurity.md` (PSA / seccomp / capabilities) - `observability.md` (ServiceMonitor / log shipping) ### 18. priority class / preemption 전략 - 플랫폼 에이전트 (CNI, CSI, log shipper, node-exporter): `system-node-critical` - 클러스터 컨트롤러 (cert-manager, external-secrets, operator): `system-cluster-critical` - 비즈니스 tier-1: 커스텀 `tier-1-critical` (value 1000000) - 비즈니스 tier-2: `tier-2` (value 100000) - 비즈니스 tier-3 / batch: `tier-3` (value 10000) ## 현재 스택 기본 권장안 (prod) | 컴포넌트 | workload 종류 | operator | 비고 | |----------------------|--------------------------------|-------------------|--------------------------------| | `auth-server` | Deployment | — | tier-1 HPA+PDB | | `test-server` (장기) | Deployment | — | | | `test-server` (검증) | Job | — | ttlSecondsAfterFinished | | `keycloak` | Deployment (외부 DB) | — | HA replicas≥2 | | `postgres-identity` | StatefulSet (via CNPG) | CloudNativePG | replica 3 | | `vault` | StatefulSet (Raft) | Vault Operator | replica 3 | | `minio` | StatefulSet (via Tenant) | MinIO Operator | | | `kafka` | StatefulSet (via Strimzi) | Strimzi | | | `redis` | StatefulSet (via operator) | redis-operator | sentinel 또는 cluster 모드 | | `flyway-migrate` | Job | — | ArgoCD PostSync hook | | `postgres-backup` | CronJob | CNPG ScheduledBkp | operator가 소유 | | `ingress-nginx` | Deployment + MetalLB | — | public / internal 분리 | | `cert-manager` | Deployment | — | system-cluster-critical | | `external-secrets` | Deployment | — | system-cluster-critical | | `prometheus` | StatefulSet (via Prometheus) | Prometheus Op | | | `fluent-bit` | DaemonSet | — | system-node-critical | | `node-exporter` | DaemonSet | — | system-node-critical | | `cilium-agent` | DaemonSet | Cilium Op (opt) | system-node-critical | | `longhorn-manager` | DaemonSet | Longhorn | | ## 프로젝트 기준 요약 - stateless 장기 → Deployment (+PDB+HPA+topologySpread 필수) - stateful + stable identity/storage → StatefulSet (또는 operator) - 노드 전역 에이전트 → DaemonSet - 일회성 → Job (ttlSecondsAfterFinished 필수) - 주기성 → CronJob (concurrencyPolicy + startingDeadlineSeconds) - PVC ≠ StatefulSet 신호 전부 아님 - DB/Kafka/Redis/Prometheus는 operator 기본 - `persistentVolumeClaimRetentionPolicy` 명시, prod는 Retain/Retain - Flyway는 Job, 앱 startup 내부 migration 금지 - ingress controller는 Deployment+LB 기본, DaemonSet은 edge 조건에만