CRD Mode
Wave는 두 가지 운영 모드 중 하나로 동작합니다.
Console Mode(기본값)에서는 모든 운영 설정을 web console에서 구성하고 Wave가 저장합니다. 대부분의 팀은 여기서 시작합니다.
CRD Mode에서는 운영 설정을 Git에 Custom Resource(wavek8s.com/v1alpha1)로 선언하고, ArgoCD나 kubectl로 클러스터에 적용합니다. Wave는 이 리소스들을 감시하며 콘솔과 동일한 설정을 적용합니다. 운영 설정에 대해 web console은 읽기 전용이 됩니다.
CRD Mode를 도입하는 이유:
- 여러 클러스터에서 동일한 설정 유지: Git repo 하나로 어디서나 똑같이 동작합니다.
- PR로 검토되는 설정 변경: 정책을 바꿀 때마다 평소 사용하는 리뷰 워크플로우를 거칩니다.
- 콘솔 drift 없음: 클러스터 상태는 항상 repo로부터 도출할 수 있고, 문서화되지 않은 콘솔 전용 변경이 생기지 않습니다.
Console Mode와 CRD Mode 비교
| Console Mode | CRD Mode | |
|---|---|---|
| 설정 위치 | Web console | kubectl apply 또는 ArgoCD |
| Source of truth | Wave의 내부 저장소 | Git + Custom Resource |
| 콘솔의 역할 | 전체 읽기/쓰기 | 운영 설정에 대해 읽기 전용 |
| 적합한 상황 | 단일 클러스터, 빠른 반복 작업 | 멀티 클러스터, GitOps 워크플로우, 규제가 있는 환경 |
CRD Mode에서도 다음 항목은 콘솔에서 계속 편집할 수 있으며 CRD로 관리되지 않습니다:
- 사용자 계정과 역할
- SSO 설정
- 라이선스 관리
그 밖의 모든 것, 즉 스케일링 정책, 알림 규칙, 사이징 범위, flow 정책, 진단 작업은 여러분의 CR이 소유합니다.
동작 방식
- Wave 설정을 Git에 Custom Resource로 선언합니다.
- ArgoCD(또는
kubectl)가 이 CR들을 클러스터에 적용합니다. - Wave는 CR을 감시하며 콘솔과 동일한 설정을 적용합니다. CR이 추가, 변경, 삭제되면 그에 맞춰 설정을 생성, 업데이트, 또는 되돌립니다.
- 각 CR의
.status는 Wave가 정상적으로 reconcile했는지를 보여줍니다.
2단계 검증:
-
구조적 오류(잘못된 타입, 알 수 없는 필드, 필수 필드 누락, 잘못된 enum 값 등)는
kubectl apply시점에 CRD 스키마가 잡아냅니다. Wave가 리소스를 보기도 전에 apply 자체가 거부됩니다. -
필드 간 시맨틱 규칙은 apply가 성공한 뒤 Wave가 평가합니다. 예를 들어
WaveAlertChannel은http,slackWebhook,slackWebApi중 정확히 하나만 설정해야 합니다. 아무것도 설정하지 않거나 둘 이상 설정하면 시맨틱 오류입니다. 실패하면.status.conditions에ValidationFailed로 나타나며, spec을 고쳐서 다시 적용해야 합니다.
한편, target이나 참조 대상이 아직 존재하지 않는 CR은 검증 실패가 아닙니다. .status에 TargetNotFound 또는 RefNotFound로 표시되며, target이 나타나면 자동으로 수렴합니다.
레퍼런스 페이지 전반에서 Default 열은 필드를 생략했을 때 Wave가 실제로 사용하는 값을 나타냅니다. 이 중 일부는 CRD 스키마 자체의 기본값이 아니라 Wave가 reconcile 시점에 적용하는 값입니다. 마찬가지로 일부 Required 표시는 API 서버가 아니라 Wave가 reconcile 시점에 강제하는 것이며, 해당 필드 설명에 그 사실을 명시해 두었습니다.
CRD Mode 활성화하기
활성화하기 전에 아래 경고를 먼저 확인하세요. Console Mode에서 자동으로 내보내는 기능은 없습니다. 전환 시점에 Git에 선언되어 있지 않은 항목은 모두 기본값으로 되돌아갑니다.
WA_CONFIG_MODE를 전환하기 전에 CR을 Git에 작성하고 깨끗하게 apply되는지 확인하세요. Wave가 CRD Mode로 재시작하는 순간, CR로 뒷받침되지 않는 설정은 모두 기본값으로 되돌아갑니다. Switching modes 참고.
1단계: CRD는 기본으로 설치됩니다.
Helm chart는 wavek8s.com CRD 14개를 자동으로 설치합니다(crds.install: true). helm upgrade를 실행하면 CRD 스키마가 갱신됩니다. helm uninstall을 실행해도 CRD와 여러분의 CR은 그대로 남습니다(각 CRD는 helm.sh/resource-policy: keep을 갖고 있습니다). 그래서 chart를 제거해도 설정은 유지됩니다.
팀에서 CRD를 별도로 관리한다면, 예를 들어 클러스터 admin이 미리 설치해 두었거나 ArgoCD가 따로 적용한다면, values 파일에서 crds.install: false로 설정해서 chart가 CRD를 건드리지 않게 하세요.
2단계: WA_CONFIG_MODE를 crd로 설정하고 upgrade합니다.
values 파일의 기존 spec.core.env 목록에 이 환경 변수를 추가하세요. 이 목록에는 필수 기본값(WA_API_SERVER_HOST, WA_LICENSE 등)이 이미 들어 있으니, 목록을 통째로 바꾸지 말고 새 항목만 추가하세요.
spec:
core:
env:
# ...keep the existing entries...
- name: WA_CONFIG_MODE
value: "crd"그다음 적용합니다:
helm upgrade wave-autoscale wave-autoscale/wave-autoscale \
-n wave-autoscale \
-f wa-values.yaml전체 helm upgrade 명령과 필수 values는 기본 설치 가이드를 참고하세요.
3단계: RBAC는 자동으로 설정됩니다.
chart는 Wave에게 자신의 CR에 대한 읽기 권한과 .status 서브리소스에 대한 쓰기 권한을 부여합니다. 추가로 설정할 것은 없습니다.
The 14 kinds
모든 kind는 apiVersion: wavek8s.com/v1alpha1 아래에 있습니다.
| Kind | Scope | Configures | Reference |
|---|---|---|---|
WaveAutopilotPolicy | namespaced | 워크로드 하나에 대한 Autopilot 스케일링 정책 | Wave Autoscale CRDs |
WaveAutopilotPreset | cluster | 일정에 재사용할 수 있는 스케일링 프리셋 | Wave Autoscale CRDs |
WaveAutopilotSchedule | cluster | 일정 기반 스케일링 구간 | Wave Autoscale CRDs |
WaveSmartSizingPolicy | namespaced | 컨테이너별 Smart Sizing 범위 및 자동 적용 | Wave Sizing CRDs |
WaveFlowPolicy | cluster | 우선순위 기반 트래픽 차단(load-shedding) 정책 | Wave Flow CRDs |
WaveNetfunnelMapping | namespaced | 워크로드 ↔ NetFunnel project/segment 매핑 | Wave Flow CRDs |
WaveNetfunnelConnection | cluster | NetFunnel 엔드포인트 및 자격 증명 | Wave Flow CRDs |
WaveDiagnosisConfig | cluster | 진단 작업 (메모리 이상 탐지, PV 예측, PV cleanup) | Wave Diagnosis CRDs |
WaveKarpenterNodeWarmup | cluster | Karpenter NodePool warm-up | Wave Karpenter CRDs |
WaveKarpenterSpotPlacement | namespaced | 워크로드 하나에 대한 spot 배치 | Wave Karpenter CRDs |
WaveAlertChannel | cluster | 알림 전송 채널 (HTTP/Slack) | Alerts CRDs |
WaveAlert | cluster | 알림 규칙 | Alerts CRDs |
WavePvcAutoExpansion | namespaced | PVC 자동 확장 규칙 | PV Lifecycle CRDs |
WaveLabelGroup | cluster | 레이블 기반 워크로드 그룹화 | WaveLabelGroup |
핵심 동작
선언적 소유권과 pruning. 설정이 존재하는 이유는 CR이 그것을 선언했기 때문입니다. CR을 삭제하면 다음 reconcile 때 Wave가 해당 설정을 기본값으로 되돌립니다. Wave는 CR을 계속 감시하므로, 삭제 후 몇 초 안에 되돌아갑니다.
예외: WaveNetfunnelConnection. 이 CR을 삭제하면 연결 정보가 지워지는 게 아니라 비활성화됩니다. Wave Flow CRDs 참고.
이름 기반의 이식 가능한 참조. CR은 targetRef.kind + targetRef.name, 또는 (channel, preset 등에서는) 단순한 name으로 서로를 참조합니다. 내부 ID가 노출되지 않으므로, 같은 YAML을 모든 클러스터에 동일하게 적용할 수 있습니다.
Namespace 적용 범위. 워크로드 단위 kind(WaveAutopilotPolicy, WaveSmartSizingPolicy, WaveNetfunnelMapping, WaveKarpenterSpotPlacement, WavePvcAutoExpansion)는 namespaced이며 대상 워크로드와 같은 namespace에 만들어야 합니다. 전역 kind는 cluster-scoped입니다.
Secret. 자격 증명을 담는 것은 WaveAlertChannel과 WaveNetfunnelConnection뿐입니다. 둘 다 wave-autoscale namespace의 Kubernetes Secret을 {name, key}로 참조합니다. Wave는 CR 자체에 자격 증명을 저장하지 않습니다.
적용 순서는 상관없습니다. 아직 존재하지 않는 target을 참조하는 CR도 kubectl apply 시점에는 성공합니다. Wave는 .status에 TargetNotFound 또는 RefNotFound를 표시하고, target이 나타나면 자동으로 reconcile합니다. 순서를 신경 쓰지 않고 CR이 담긴 디렉터리 전체를 한 번에 적용해도 됩니다.
Sync status and health
모든 kind는 .status.conditions에 단일 Synced condition을 갖습니다. 아래 명령에서 리소스 이름은 여러분의 kind를 소문자 복수형으로 바꿔서 사용하세요. kubectl api-resources | grep wavek8s로 전체 목록을 볼 수 있습니다. 확인 방법:
kubectl get waveautopilotpolicies -n payment my-policy \
-o jsonpath='{.status.conditions[?(@.type=="Synced")].reason}'| Reason | Synced | Meaning | What to do |
|---|---|---|---|
AsExpected | True | Wave가 CR을 성공적으로 적용함 | - |
RefInUse | True | 참조된 리소스가 사용 중이라 제거되지 않음 | - |
TargetNotFound | False | 대상 워크로드가 아직 존재하지 않음 | 워크로드를 적용하거나 targetRef를 수정하세요. 자동으로 해결됩니다. |
RefNotFound | False | 참조하는 preset, channel 등이 아직 존재하지 않음 | 참조 대상 CR을 적용하세요. 자동으로 해결됩니다. |
SecretNotFound | False | 참조하는 Kubernetes Secret이 없음 | wave-autoscale에 Secret을 생성하세요. 자동으로 해결됩니다. |
PartiallyApplied | False | CR의 일부 항목만 적용되고 나머지는 적용되지 않음 | 자세한 내용은 .status.message를 확인하세요. 조건이 해소되면 자동으로 해결됩니다. |
Conflicted | False | CR이 다른 리소스나 불변 필드와 충돌함 | .status.message를 확인하고 직접 수정해야 합니다. |
ReconcileError | False | Wave에서 예기치 않은 오류가 발생함 | 자동으로 재시도됩니다. 계속되면 Wave 로그를 확인하세요. |
ValidationFailed | False | 시맨틱 규칙 위반 (필드 간 검증 실패) | CR spec을 수정하고 다시 적용하세요. |
web console은 CRD Mode 상태를 세 곳에서 보여줍니다. 사이드바의 CRD Mode 표시, 모든 CR의 상태와 reason을 보여주는 Admin → CRD Status 페이지, 그리고 같은 페이지의 reconciler health 카드입니다.
ArgoCD 연동
ArgoCD는 기본적으로 알 수 없는 custom resource를 Healthy로 표시합니다. Wave는 각 CR의 .status를 올바른 ArgoCD health 상태로 매핑하는 health check를 함께 제공합니다.
.status reason | ArgoCD health |
|---|---|
AsExpected, RefInUse | Healthy |
TargetNotFound, RefNotFound, SecretNotFound, PartiallyApplied | Progressing |
ValidationFailed, Conflicted, ReconcileError | Degraded |
설정 방법: Wave의 Helm chart는 wave-autoscale namespace에 health check Lua 스크립트를 담은 argocd-resource-customizations-example이라는 ConfigMap을 렌더링합니다. 이를 추출해서 검토한 다음, resource.customizations 항목을 argocd namespace의 argocd-cm ConfigMap에 병합하세요.
# Extract the example ConfigMap
kubectl get cm argocd-resource-customizations-example \
-n wave-autoscale -o yaml
# Merge its entries into argocd-cm in your argocd namespace
kubectl edit cm argocd-cm -n argocd이 ConfigMap의 data key는 resource.customizations.health.wavek8s.com_<Kind> 형식을 따릅니다(예: resource.customizations.health.wavek8s.com_WaveAutopilotPolicy). 이 key들을 argocd-cm의 같은 경로에 그대로 복사하세요. 전체 사양은 ArgoCD custom health check format (opens in a new tab)을 참고하세요. argocd-cm이 잘못되면 클러스터 전체의 모든 ArgoCD sync에 영향을 주므로, 적용하기 전에 diff를 꼼꼼히 검토하세요.
병합하고 나면 ArgoCD는 재시작 없이 즉시 모든 Wave CR의 실제 reconcile 상태를 UI와 sync 상태에 반영합니다.
Switching modes
Console Mode → CRD Mode: 자동으로 내보내는 기능은 없습니다. Wave가 CRD Mode로 재시작하는 순간, CR로 뒷받침되지 않는 운영 설정은 모두 기본값으로 되돌아갑니다. CR을 먼저 작성하고 적용하거나, 콘솔에서 아무것도 설정하기 전에 설치 시점부터 CRD Mode를 채택하세요.
CRD Mode → Console Mode: 안전합니다. WA_CONFIG_MODE를 다시 console로 설정하거나(또는 env var를 제거하고) helm upgrade를 실행하세요. 마지막으로 동기화된 설정이 즉시 콘솔에서 편집 가능한 baseline이 되며, 데이터 손실은 없습니다. CR은 클러스터에 그대로 남아 있지만 이 시점부터 Wave는 이를 무시합니다. 삭제되지는 않습니다.
WaveLabelGroup
용도: WaveLabelGroup은 label과 namespace 필터를 기준으로 이름이 붙은 워크로드 또는 노드 그룹을 정의합니다. 이 그룹은 cluster overview 필터링과 workload report에서, 클러스터의 의미 있는 부분 집합별로 메트릭을 나눠 보는 데 사용됩니다.
Scope: cluster-scoped (metadata.namespace가 필요 없습니다).
예시
apiVersion: wavek8s.com/v1alpha1
kind: WaveLabelGroup
metadata:
name: prod-backend-label-group
spec:
context: workload_report
description: "Production backend services across prod and staging namespaces."
labelFilters:
conditions:
- key: app.kubernetes.io/component
operator: in
values:
- backend
- api
- key: app.kubernetes.io/managed-by
operator: exists
logic: and
namespaceFilters:
- prod
- staging노드 레이블로 필터링하고 싶다면 cluster_overview를 사용하세요. 예를 들어 클러스터 수준 대시보드를 위해 Spot 인스턴스나 특정 가용 영역(availability zone)의 노드를 그룹화할 때 씁니다. 워크로드 레이블과 namespace로 메트릭을 나누고 싶다면 workload_report를 사용하세요. 다음은 노드 레이블을 매칭하는 cluster_overview 그룹 예시입니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveLabelGroup
metadata:
name: spot-nodes-label-group
spec:
context: cluster_overview
description: "EKS Spot m5 nodes with an availability-zone label."
labelFilters:
conditions:
- key: eks.amazonaws.com/capacityType
operator: equals
value: SPOT
- key: node.kubernetes.io/instance-type
operator: in
values:
- m5.large
- m5.xlarge
- key: topology.kubernetes.io/zone
operator: exists
logic: andSpec fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
context | string (enum) | Yes | - | 이 그룹을 사용하는 기능입니다. cluster_overview(노드 레이블 매칭) 또는 workload_report(워크로드 레이블 + namespace 매칭) 중 하나입니다. 생성 후에는 변경할 수 없습니다(Immutable). |
description | string | No | - | 콘솔에 표시되는, 사람이 읽기 위한 설명입니다. |
labelFilters | object | No* | - | 레이블 기반 필터 조건입니다. namespaceFilters를 설정하지 않으면 필수입니다. |
labelFilters.conditions | array | Yes (labelFilters 설정 시) | - | 하나 이상의 레이블 매치 조건입니다. |
labelFilters.conditions[].key | string | Yes | - | 매칭할 레이블 key입니다. |
labelFilters.conditions[].operator | string | Yes | - | 매치 연산자입니다: equals, in, exists 중 하나. |
labelFilters.conditions[].value | string | No | - | equals 연산자에 사용하는 단일 값입니다. |
labelFilters.conditions[].values | string[] | No | - | in 연산자에 사용하는 값 목록입니다. |
labelFilters.logic | string | Yes (runtime) | "" | 여러 조건을 묶는 방식입니다: and 또는 or. 생략하면 스키마가 빈 문자열을 주입하는데, Wave는 이를 ValidationFailed로 거부합니다. 반드시 명시적으로 설정하세요. |
namespaceFilters | string[] | No* | - | 포함할 namespace 목록입니다. workload_report에서는 labelFilters와 함께 평가됩니다. cluster_overview에서는 무시됩니다(노드에는 namespace가 없습니다). labelFilters를 설정하지 않으면 필수입니다. |
*labelFilters와 namespaceFilters 중 최소 하나는 반드시 지정해야 합니다.
참고 사항
context는 변경할 수 없습니다(immutable). 생성 후 변경을 시도하면 Wave가 거부하며, CR은Conflicted로 표시됩니다. context를 바꾸려면 CR을 삭제하고 원하는 값으로 새로 만드세요.- 런타임에는 필터가 최소 하나 필요합니다.
labelFilters와namespaceFilters가 모두 없는 CR은 CRD 스키마 검증은 통과하지만 Wave가ValidationFailed로 거부합니다. cluster_overview그룹은 노드 레이블을 매칭합니다. 노드에는 namespace가 없으므로 이 context에서는namespaceFilters가 무시됩니다.workload_report그룹은 워크로드 레이블과 namespace를 매칭합니다.labelFilters와namespaceFilters가 함께 평가됩니다(두 필터 유형 사이는 AND 조건입니다).- Operator 값은 reconcile 시점에 대소문자를 구분하지 않습니다.
Equals,equals,EQUALS는 모두 동일하게 처리됩니다. 인식할 수 없는 operator 값은ValidationFailed를 일으킵니다.