Alert CRD
이 종류(kind)들은 CRD Mode에서 Alerts를 설정합니다. 채널과 규칙에 대한 소개는 Alerts 개요를 참고하세요. WaveAlertChannel은 알림을 어디로 보낼지 정의하고, WaveAlert는 무엇을 모니터링하고 언제 알림을 발생시킬지 정의합니다.
WaveAlertChannel
WaveAlertChannel은 알림 대상을 정의합니다. HTTP endpoint, Slack Webhook, 또는 Slack Web API 채널이 될 수 있습니다. Alert 규칙은 이름으로 채널을 참조합니다. 모든 자격 증명, URL, 헤더, 프록시 설정은 Kubernetes Secret에 저장되며 CR 자체에는 기록되지 않습니다.
적용 범위: cluster-scoped이며 metadata.namespace가 필요하지 않습니다.
먼저 wave-autoscale namespace에 Secret을 생성합니다.
apiVersion: v1
kind: Secret
metadata:
name: http-endpoint
namespace: wave-autoscale
type: Opaque
stringData:
url: "https://hooks.example.com/webhook"
---
apiVersion: v1
kind: Secret
metadata:
name: http-headers
namespace: wave-autoscale
type: Opaque
stringData:
# Must be a JSON object string — key/value pairs of HTTP headers.
headers: '{"Authorization":"Bearer <token>","Content-Type":"application/json"}'그다음 채널 CR을 생성합니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlertChannel
metadata:
name: oncall-http
spec:
http:
urlSecretRef:
name: http-endpoint
key: url
method: POST
headersSecretRef:
name: http-headers
key: headersSpec 필드
http, slackWebhook, slackWebApi 중 정확히 하나만 설정해야 합니다. 0개 또는 2개 이상 설정하면 .status.conditions에 ValidationFailed가 표시됩니다.
| 필드 | 타입 | 필수 여부 | 기본값 | 설명 |
|---|---|---|---|---|
http | object | 조건부 | - | HTTP 채널 variant입니다. slackWebhook, slackWebApi와는 함께 사용할 수 없습니다. |
slackWebhook | object | 조건부 | - | Slack Incoming Webhook variant입니다. http, slackWebApi와는 함께 사용할 수 없습니다. |
slackWebApi | object | 조건부 | - | Slack Web API variant입니다. http, slackWebhook과는 함께 사용할 수 없습니다. |
http 필드
| 필드 | 타입 | 필수 여부 | 기본값 | 설명 |
|---|---|---|---|---|
http.urlSecretRef | object | 예 | - | 대상 URL 값을 담고 있는 Secret 키에 대한 참조입니다. |
http.urlSecretRef.name | string | 예 | - | wave-autoscale namespace에 있는 Secret의 이름입니다. |
http.urlSecretRef.key | string | 예 | - | URL 값을 담고 있는 Secret 내부의 키입니다. |
http.method | string | 예 (런타임) | - | HTTP 메서드입니다. 유효한 값: POST, PUT, PATCH, DELETE. |
http.headersSecretRef | object | 아니오 | - | HTTP 헤더 key/value 쌍을 담은 JSON 객체 값을 가진 Secret 키에 대한 참조입니다 (예: {"Authorization":"Bearer ...","Content-Type":"application/json"}). |
http.headersSecretRef.name | string | 예 (설정 시) | - | Secret의 이름입니다. |
http.headersSecretRef.key | string | 예 (설정 시) | - | Secret 내부의 키입니다. |
http.proxySecretRef | object | 아니오 | - | HTTPS 프록시 URL 값을 가진 Secret 키에 대한 참조입니다. |
http.proxySecretRef.name | string | 예 (설정 시) | - | Secret의 이름입니다. |
http.proxySecretRef.key | string | 예 (설정 시) | - | Secret 내부의 키입니다. |
slackWebhook 필드
| 필드 | 타입 | 필수 여부 | 기본값 | 설명 |
|---|---|---|---|---|
slackWebhook.webhookUrlSecretRef | object | 예 | - | Slack Webhook URL 값을 가진 Secret 키에 대한 참조입니다. |
slackWebhook.webhookUrlSecretRef.name | string | 예 | - | wave-autoscale namespace에 있는 Secret의 이름입니다. |
slackWebhook.webhookUrlSecretRef.key | string | 예 | - | Secret 내부의 키입니다. |
slackWebhook.proxySecretRef | object | 아니오 | - | HTTPS 프록시 URL 값을 가진 Secret 키에 대한 참조입니다. |
slackWebhook.proxySecretRef.name | string | 예 (설정 시) | - | Secret의 이름입니다. |
slackWebhook.proxySecretRef.key | string | 예 (설정 시) | - | Secret 내부의 키입니다. |
예시:
apiVersion: v1
kind: Secret
metadata:
name: slack-webhook-url
namespace: wave-autoscale
type: Opaque
stringData:
url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX"
---
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlertChannel
metadata:
name: oncall-slack-webhook
spec:
slackWebhook:
webhookUrlSecretRef:
name: slack-webhook-url
key: urlslackWebApi 필드
| 필드 | 타입 | 필수 여부 | 기본값 | 설명 |
|---|---|---|---|---|
slackWebApi.tokenSecretRef | object | 예 | - | Slack Bot token 값(예: xoxb-...)을 가진 Secret 키에 대한 참조입니다. |
slackWebApi.tokenSecretRef.name | string | 예 | - | wave-autoscale namespace에 있는 Secret의 이름입니다. |
slackWebApi.tokenSecretRef.key | string | 예 | - | Secret 내부의 키입니다. |
slackWebApi.channel | string | 예 | - | 대상 Slack 채널입니다. 채널 ID 또는 #channel-name 형식입니다. |
slackWebApi.proxySecretRef | object | 아니오 | - | HTTPS 프록시 URL 값을 가진 Secret 키에 대한 참조입니다. |
slackWebApi.proxySecretRef.name | string | 예 (설정 시) | - | Secret의 이름입니다. |
slackWebApi.proxySecretRef.key | string | 예 (설정 시) | - | Secret 내부의 키입니다. |
예시:
apiVersion: v1
kind: Secret
metadata:
name: slack-bot-token
namespace: wave-autoscale
type: Opaque
stringData:
token: "xoxb-your-bot-token-here"
---
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlertChannel
metadata:
name: oncall-slack-webapi
spec:
slackWebApi:
tokenSecretRef:
name: slack-bot-token
key: token
channel: "#alerts"http.method는 필수입니다. 생략하면 .status.conditions에 ValidationFailed가 표시되고 채널이 실패합니다. 유효한 값은 POST, PUT, PATCH, DELETE입니다. 인식되지 않는 값(GET 포함)은 거부되지 않고 조용히 POST로 처리됩니다. method 값의 철자를 다시 확인하세요.
참고 사항
- Cluster-scoped이며
metadata.namespace가 필요하지 않습니다. http/slackWebhook/slackWebApi중 정확히 하나의 variant만 설정해야 합니다. 이는kubectl apply시점이 아니라 Wave가 reconcile 시점에 검증하며,.status.conditions에ValidationFailed로 표시됩니다.- 모든 자격 증명, URL, 헤더, 프록시 설정은 Secret 참조입니다. Wave는 reconcile 시점에
wave-autoscalenamespace에서 Secret 값을 읽으며 CR에는 기록하지 않습니다. Secret이나 키가 없으면.status.conditions에SecretNotFound가 표시되고, Secret이 나타나면 자동으로 복구됩니다. headersSecretRef값은 JSON 객체 문자열이어야 합니다. 형식이 잘못된 값은 현재SecretNotFound로 처리됩니다.- 채널은
WaveAlert.spec.alertMessages[].channelRef에서 이름으로 참조됩니다.WaveAlertChannelCR 삭제는 Kubernetes에서 절대 차단되지 않습니다. 기존WaveAlert가 여전히 참조하고 있는 동안에는 Wave가 채널 설정을 계속 활성 상태로 유지하며.status.conditions에RefInUse를 표시합니다. 참조하던 Alert가 모두 사라지면 정리됩니다.
WaveAlert
WaveAlert는 Alert 규칙을 정의합니다. 어떤 이벤트 유형을 평가할지, 어떤 표현식으로 Alert 발생 여부를 결정할지, 어떤 타겟으로 범위를 제한할지, 어떤 채널로 알림을 전달할지를 정의합니다.
적용 범위: cluster-scoped이며 metadata.namespace가 필요하지 않습니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: high-cpu-prod-api
spec:
title: High CPU/memory on prod/api
eventType: deployment_workload_metrics
eventTargets:
specific:
- resourceType: Deployment
namespace: prod
name: api
eventRuleExpression: "evaluation_period_minutes >= 1 && ( max(cpu_utilization_arr) >= 80 || avg(memory_utilization_arr) >= 80 )"
eventRuleCheckIntervalMin: 5
alertMessages:
- channelRef: oncall-http
message: "${namespace}/${workload_name} CPU/memory exceeded 80% over the evaluation window"Spec 필드
| 필드 | 타입 | 필수 여부 | 기본값 | 설명 |
|---|---|---|---|---|
title | string | 예 | - | Wave 콘솔에 표시되는, 이 Alert 규칙의 사람이 읽기 쉬운 이름입니다. |
eventType | string | 예 | - | 평가할 이벤트 유형입니다. deployment_workload_metrics, deployment_scheduling_phase, autopilot_logs_missing, pending_pod_duration, pod_container_failure, pv_usage, smart_sizing_recommendation, oom_kill_risk 중 하나입니다. 인식되지 않는 값은 ValidationFailed를 표시합니다. |
eventTargets | object | 예 | - | 규칙의 범위를 특정 리소스 또는 특정 유형의 모든 리소스로 제한합니다. 아래를 참고하세요. CRD 레이어에서는 free-form 필드이며(x-kubernetes-preserve-unknown-fields: true), 구조적 오류는 kubectl apply가 아니라 Wave를 통해 드러납니다. |
eventRuleExpression | string | 예 | - | 이벤트 변수를 대상으로 평가되는 JavaScript 표현식입니다. 표현식이 true로 평가되면 Alert가 발생합니다. 정의되지 않은 변수를 참조하는 표현식은 ValidationFailed를 표시하며 Alert가 활성화되지 않습니다. |
eventRuleCheckIntervalMin | integer | 아니오 | 1 | Wave가 규칙을 평가하는 주기(분)입니다. 최소 1분으로 제한되며, 0이나 음수를 넣어도 평가기를 과도하게 돌리지 않고 1로 처리합니다. |
alertMessages | array | 아니오 | [] | 규칙이 발생했을 때 전달할 채널과 메시지 템플릿입니다. 생략할 수 있습니다. 이 경우에도 규칙은 계속 평가되지만, 항목이 하나 이상 추가되기 전까지는 어떤 채널에도 전달되지 않습니다. |
alertMessages[].channelRef | string | 예 (항목별) | - | WaveAlertChannel CR의 이름입니다. 채널이 없으면 .status.conditions에 RefNotFound가 표시되고, 채널 CR이 나타나면 자동으로 복구됩니다. |
alertMessages[].message | string | 예 (항목별) | - | JavaScript template literal로 렌더링되는 메시지 템플릿입니다. ${varName} 문법으로 컨텍스트 변수를 보간합니다. 사용 가능한 변수는 eventType에 따라 다릅니다. 아래 표를 참고하세요. |
eventTargets 구조
eventTargets는 다음 두 형태 중 하나만 사용합니다.
# Target all resources of a given type:
eventTargets:
all:
resourceType: Deployment
# Target specific named resources:
eventTargets:
specific:
- resourceType: Deployment
namespace: prod
name: api
# 대상이 없는(targetless) 이벤트 유형은 빈 specific 목록을 사용합니다:
eventTargets:
specific: []| 필드 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
all.resourceType | string | 예 (all 사용 시) | 모니터링할 리소스 유형입니다. Deployment, StatefulSet, DaemonSet, Pvc 중 하나이며, 어떤 값이 의미가 있는지는 eventType에 따라 다릅니다(아래 표 참고). |
specific[].resourceType | string | 예 (항목별) | 리소스 유형입니다. all.resourceType과 같은 값을 받습니다. |
specific[].namespace | string | 아니오 | 대상 리소스의 namespace입니다. 생략하면 모든 namespace에서 리소스를 매칭합니다. |
specific[].name | string | 아니오 | 대상 리소스의 이름입니다. 생략하면 유형(및 설정된 경우 namespace)만으로 매칭합니다. |
대상이 없는 이벤트 유형. pending_pod_duration, pod_container_failure, oom_kill_risk, deployment_scheduling_phase는 클러스터 전역 이벤트라 특정 워크로드에 묶이지 않습니다. 그래도 eventTargets는 필수 필드이므로 specific: []로 두세요. 해당 worker는 대상 목록을 무시하고 조건에 맞는 클러스터 이벤트마다 발생합니다.
eventType별 지원 대상 유형
eventType | 지원하는 resourceType |
|---|---|
deployment_workload_metrics | Deployment |
deployment_scheduling_phase | 없음 - targetless, specific: [] 사용 |
autopilot_logs_missing | Deployment |
pending_pod_duration | 없음 - targetless, specific: [] 사용 |
pod_container_failure | 없음 - targetless, specific: [] 사용 |
pv_usage | Pvc |
smart_sizing_recommendation | Deployment, StatefulSet, DaemonSet |
oom_kill_risk | 없음 - targetless, specific: [] 사용 |
eventType별 규칙 표현식 변수
각 이벤트 유형은 서로 다른 변수 집합을 노출합니다. eventRuleExpression은 ${} 래핑 없이 변수 이름 그대로를 사용합니다. alertMessages[].message는 ${varName} JavaScript template-literal 문법을 사용합니다.
eventType | 표현식 변수 | 메시지 전용 추가 변수 |
|---|---|---|
deployment_workload_metrics | evaluation_period_minutes, cpu_utilization_arr, memory_utilization_arr. 배열 변수는 max() / min() / avg() 헬퍼를 지원합니다 | ${namespace}, ${workload_name}, ${alert_title}, ${alert_time} |
deployment_scheduling_phase | phase ("START" 또는 "END"), deployment_count | ${scheduling_title}, ${occurred_at}, ${alert_title}, ${alert_time} |
autopilot_logs_missing | missing_duration_minutes, error_duration_minutes | ${namespace}, ${workload_name}, ${alert_title}, ${alert_time} |
pending_pod_duration | pending_duration_minutes, reason_category | ${namespace}, ${pod_name}, ${workload_name}, ${alert_title}, ${alert_time} |
pod_container_failure | transition_type, workload_kind | ${namespace}, ${pod_name}, ${container_name}, ${workload_name}, ${alert_title}, ${alert_time} |
pv_usage | usage_percent, used_bytes, capacity_bytes, available_bytes, minutes_since_last_alert | ${namespace}, ${pvc_name}, ${alert_title}, ${alert_time} |
smart_sizing_recommendation | cpu_request_delta_abs_percent, memory_request_delta_abs_percent, recommended_cpu_request, recommended_memory_request, current_cpu_request, current_memory_request | ${workload_type}, ${namespace}, ${workload_name}, ${container_name}, ${alert_title}, ${alert_time} |
oom_kill_risk | utilization, minutes_since_last_alert | ${namespace}, ${workload_type}, ${workload_name}, ${pod_name}, ${container_name}, ${alert_title}, ${alert_time} |
autopilot_logs_missing 아래의 다섯 가지 이벤트 유형은 Wave 3.4.0에서 추가되었습니다. 그 이전 버전의 Core에서는 .status.conditions에 ValidationFailed로 보고됩니다.
이벤트 유형 레퍼런스
pending_pod_duration - Pod가 임계 시간보다 오래 Pending 상태에 머물러 있습니다. reason_category가 스케줄러의 사유를 묶어주므로(예: 리소스 부족 vs 볼륨 미바인딩), 용량 문제와 스토리지 문제를 서로 다른 채널로 나눠 보낼 수 있습니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: pods-stuck-pending
spec:
title: Pending 5분 초과 Pod
eventType: pending_pod_duration
eventTargets:
specific: []
eventRuleExpression: "pending_duration_minutes >= 5"
alertMessages:
- channelRef: oncall-slack-webhook
message: "Pod ${namespace}/${pod_name}이(가) ${pending_duration_minutes}분째 Pending 상태입니다"pod_container_failure - 컨테이너가 장애 상태로 전환됐습니다. transition_type은 전환 종류(CrashLoopBackOff, OOMKilled, ImagePullBackOff 등)이고, workload_kind는 Deployment, StatefulSet, DaemonSet 중 하나입니다. 기본 표현식은 true라서 모든 장애 이벤트에 발생하며, transition_type 조건으로 범위를 좁혀 씁니다. WaveDiagnosisConfig.spec.podContainerFailures.excludedWorkloads에 있는 워크로드는 여기서 이벤트를 만들지 않습니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: crashloop-only
spec:
title: CrashLoopBackOff
eventType: pod_container_failure
eventTargets:
specific: []
eventRuleExpression: "transition_type == 'CrashLoopBackOff'"
alertMessages:
- channelRef: oncall-slack-webhook
message: "Pod ${namespace}/${pod_name}의 컨테이너 ${container_name} 장애 발생: ${transition_type}"pv_usage - PersistentVolumeClaim이 사용량 임계값을 넘었습니다. 감지는 1분마다 돌기 때문에, 임계값과 함께 minutes_since_last_alert 조건을 걸어 재알림 쿨다운으로 쓰세요. 이 조건이 없으면 임계값을 계속 넘고 있는 PVC가 매분 알림을 보냅니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: pvc-nearly-full
spec:
title: PVC 사용량 80% 초과
eventType: pv_usage
eventTargets:
all:
resourceType: Pvc
eventRuleExpression: "usage_percent >= 80 && minutes_since_last_alert >= 30"
alertMessages:
- channelRef: oncall-slack-webhook
message: "PVC ${namespace}/${pvc_name} 사용량: ${usage_percent}%"smart_sizing_recommendation - Smart Sizing이 현재 request와 의미 있게 차이 나는 추천을 만들었습니다. *_delta_abs_percent 변수는 절대값 퍼센트 차이라서, 임계값 하나로 과다 할당과 과소 할당을 모두 잡을 수 있습니다. CPU는 core, 메모리는 MiB 단위입니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: sizing-drift
spec:
title: Smart Sizing 추천 20% 이상 차이
eventType: smart_sizing_recommendation
eventTargets:
all:
resourceType: Deployment
eventRuleExpression: "cpu_request_delta_abs_percent >= 20 || memory_request_delta_abs_percent >= 20"
alertMessages:
- channelRef: oncall-slack-webhook
message: "Smart Sizing - ${namespace}/${workload_name}/${container_name}: CPU ${current_cpu_request} -> ${recommended_cpu_request} cores, 메모리 ${current_memory_request} -> ${recommended_memory_request} MiB"oom_kill_risk - 컨테이너의 메모리 사용률이 OOM-kill 임계값에 도달했습니다. 실제로 kill이 일어나기 전에 실시간으로 알려줍니다. 임계값과 컨테이너별 쿨다운은 WaveDiagnosisConfig.spec.memoryAnomaly에서 설정합니다(oomkillUtilization 기본 95%, oomkillCooldownMinutes 기본 10분). 이 쿨다운이 이미 원천에서 반복을 눌러주므로, 규칙 표현식에는 보통 minutes_since_last_alert 가드만 있으면 됩니다.
apiVersion: wavek8s.com/v1alpha1
kind: WaveAlert
metadata:
name: oom-kill-risk
spec:
title: OOM-kill 위험
eventType: oom_kill_risk
eventTargets:
specific: []
eventRuleExpression: "minutes_since_last_alert >= 10"
alertMessages:
- channelRef: oncall-slack-webhook
message: "Pod ${namespace}/${pod_name}의 컨테이너 ${container_name} 메모리 ${utilization}% - OOM-kill 위험"참고 사항
- Cluster-scoped이며
metadata.namespace가 필요하지 않습니다. eventType은 Wave가 reconcile 시점에 검증합니다. 인식되지 않는 값은.status.conditions에ValidationFailed를 표시하며 Alert가 활성화되지 않습니다.eventRuleExpression은 Wave가 검증합니다. 설정된eventType에서 사용할 수 없는 변수를 참조하거나 형식이 잘못된 표현식은ValidationFailed를 표시하며 Alert가 활성화되지 않습니다. 표현식을 수정하면 규칙이 자동으로 복구됩니다.alertMessages는 선택 사항입니다. 메시지가 없는WaveAlert도 유효하며 규칙은 계속 평가됩니다. 다만 어떤 채널에도 전달되지 않습니다. 채널을 연결하기 전에 표현식을 테스트할 때 유용합니다.- 메시지 템플릿은 JavaScript template-literal 보간(
${varName})을 사용합니다. Go 스타일{{.var}}는 보간되지 않고 그대로 출력됩니다. - 각
channelRef는 기존WaveAlertChannelCR의metadata.name과 일치해야 합니다. 채널이 없으면.status.conditions에RefNotFound가 표시되고, 채널 CR이 나타나면 자동으로 수렴합니다. 모든 채널 참조가 해결될 때까지는 (누락된 항목뿐 아니라) Alert 전체가 스킵됩니다. eventTargets는 CRD 레이어에서 free-form 객체입니다(x-kubernetes-preserve-unknown-fields: true). 필드 이름 오타 같은 구조적 오류는kubectl apply에서 잡히지 않으며, Wave의 reconciler를 통해ValidationFailed로 드러납니다.WaveAlert가 여전히 참조하는WaveAlertChannel을 삭제하는 작업은 Kubernetes에서 절대 차단되지 않습니다. Wave는 참조하는 Alert CR이 제거될 때까지 채널 설정을 계속 활성 상태로 유지하며.status.conditions에RefInUse를 표시하고, 이후 정리됩니다.