Add VictoriaMetrics observability stack + sync catalog for monitoring test

- VM stack 10 charts: victoria-metrics-cluster/auth, victoria-logs-cluster,
  victoria-metrics-agent/alert, opentelemetry-collector, kube-state-metrics,
  prometheus-node-exporter, alertmanager, perses (JWT/OIDC, Infisical-ready)
- ArgoCD ApplicationSet (syncWave) + per-chart dip-values overlays
- doc/victoria-metrics-architecture.md, define-chart-resources updates
- includes pending working-tree changes (mlflow, kubeflow, apisix, CLAUDE.md)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
wbsong111
2026-06-25 11:10:51 +09:00
parent a55427730e
commit 6290322f1b
514 changed files with 68103 additions and 40 deletions
@@ -0,0 +1,36 @@
# VictoriaMetrics 스택 ArgoCD ApplicationSet
VM 옵저버빌리티 스택(10개 차트)을 ArgoCD ApplicationSet으로 배포한다. 전체 아키텍처는 [doc/victoria-metrics-architecture.md](../../../../doc/victoria-metrics-architecture.md) 12장 참조.
## 구성
- **`applicationset.yaml`** — list generator로 10개 Application 생성. element마다 `chartPath`/`baseValues`/`valuesPath`/`syncWave`.
- **`*-values.yaml`** — 차트별 **환경 오버레이 템플릿**. dip-console이 `$VAR`(도메인/Keycloak/Infisical)를 렌더해 값 repo(`dip/values-*`)의 `victoria-metrics/<chart>-values.yaml`로 커밋한다.
## 값 적용 순서 (2단)
각 Application은 두 values 파일을 병합한다(나중 파일 우선).
1. **베이스**: 카탈로그 차트의 `custom-values.yaml`(또는 otelcol-events는 `custom-values-events.yaml`) — 큰 정적 설정(스크레이프/파이프라인/알림 규칙 등) 재사용.
2. **환경 오버레이**: `$values/victoria-metrics/<chart>-values.yaml` — 도메인/시크릿/issuer 등 환경 고유값만.
> Helm 병합 규칙: map은 병합, **배열은 교체**. 그래서 `config.users`(vmauth)·`oidc`(perses)·`extraSecretMounts`(alertmanager)처럼 배열을 바꿀 땐 오버레이에 해당 배열 전체를 재정의한다.
## syncWave 순서
| wave | 차트 |
|------|------|
| 0 | vmcluster, vlogs, kube-state-metrics, node-exporter, alertmanager |
| 1 | vmauth, vmagent, otelcol, otelcol-events, vmalert |
| 2 | perses |
## 사전 준비 (배포 전, ArgoCD 밖)
- **dip-console**: Keycloak(`vm-access` scope, `perses`/`perses-vmauth` client) · Infisical 시크릿(`$INFISICAL_*`) · `root-ca-cert` 복사 · `vmagent-relabel-configs` 테넌트 ConfigMap.
- **플랫폼 기본**: StorageClass(longhorn), Ingress controller + cert-manager(`root-ca-issuer`), DNS.
- **GitOps**: ArgoCD에 카탈로그 repo·값 repo 등록, 값 repo에 렌더된 `victoria-metrics/*-values.yaml`.
- **대시보드**: perses 대시보드 ConfigMap은 별도 경로 소스로 적용(아래).
## perses 대시보드
`manifests/helm/perses/0.21.0/files/perses-dashboards.yaml`(정적 대시보드 ConfigMap)를 별도 ArgoCD Application(directory 소스)으로 배포하면 사이드카가 자동 로드한다. 데이터소스/시크릿(`perses-provisioning.yaml`의 datasource/secret)은 환경별이라 dip-console/Infisical로 관리한다.
@@ -0,0 +1,22 @@
# 환경 오버레이 — alertmanager/1.37.0/custom-values.yaml 위에 적용
# 알림 채널 자격증명은 Infisical 동기화 Secret을 파일로 마운트(평문 금지).
# 채널 교체/추가 방법은 alertmanager/1.37.0/CUSTOM-README.md 참조.
# (Helm 배열 교체: extraSecretMounts 전체를 여기서 재정의)
extraSecretMounts:
- name: alertmanager-notify
mountPath: /etc/alertmanager/secrets
subPath: ""
secretName: "$INFISICAL_ALERTMANAGER_SECRET" # external-secrets가 monitoring ns에 동기화
readOnly: true
# 기본은 베이스(custom-values)의 discord receiver를 사용.
# 채널을 바꾸려면 dip-console이 아래 config.receivers/route를 렌더해 덮어쓴다.
# config:
# route:
# receiver: slack
# receivers:
# - name: slack
# slack_configs:
# - api_url_file: /etc/alertmanager/secrets/slack-webhook
# channel: "#alerts"
@@ -0,0 +1,108 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: victoria-metrics
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- list:
# 각 element: 차트 경로 + 베이스값(카탈로그 custom-values 재사용) + 환경 오버레이(값 repo) + syncWave
elements:
# ── syncWave 0: 저장소·무의존 ────────────────────────────────────
- name: vmcluster
chartPath: manifests/helm/victoria-metrics-cluster/0.43.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/vmcluster-values.yaml
syncWave: "0"
- name: vlogs
chartPath: manifests/helm/victoria-logs-cluster/0.1.5
baseValues: custom-values.yaml
valuesPath: victoria-metrics/vlogs-values.yaml
syncWave: "0"
- name: kube-state-metrics
chartPath: manifests/helm/kube-state-metrics/7.4.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/kube-state-metrics-values.yaml
syncWave: "0"
- name: node-exporter
chartPath: manifests/helm/prometheus-node-exporter/4.55.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/node-exporter-values.yaml
syncWave: "0"
- name: alertmanager
chartPath: manifests/helm/alertmanager/1.37.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/alertmanager-values.yaml
syncWave: "0"
# ── syncWave 1: 저장소·alertmanager 의존 ─────────────────────────
- name: vmauth
chartPath: manifests/helm/victoria-metrics-auth/0.33.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/vmauth-values.yaml
syncWave: "1"
- name: vmagent
chartPath: manifests/helm/victoria-metrics-agent/0.40.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/vmagent-values.yaml
syncWave: "1"
- name: otelcol
chartPath: manifests/helm/opentelemetry-collector/0.156.2
baseValues: custom-values.yaml
valuesPath: victoria-metrics/otelcol-values.yaml
syncWave: "1"
- name: otelcol-events
chartPath: manifests/helm/opentelemetry-collector/0.156.2
baseValues: custom-values-events.yaml
valuesPath: victoria-metrics/otelcol-events-values.yaml
syncWave: "1"
- name: vmalert
chartPath: manifests/helm/victoria-metrics-alert/0.41.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/vmalert-values.yaml
syncWave: "1"
# ── syncWave 2: vmauth 의존 ──────────────────────────────────────
- name: perses
chartPath: manifests/helm/perses/0.21.0
baseValues: custom-values.yaml
valuesPath: victoria-metrics/perses-values.yaml
syncWave: "2"
template:
metadata:
name: "{{ .name }}"
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "{{ .syncWave }}"
spec:
project: default
sources:
# Source 1: 카탈로그 repo (Helm 차트)
- repoURL: https://gitea.example.org/dip/catalog-test
targetRevision: main
path: "{{ .chartPath }}"
helm:
releaseName: "{{ .name }}"
valueFiles:
- "{{ .baseValues }}" # 카탈로그 차트의 정적 베이스값(custom-values)
- $values/{{ .valuesPath }} # Source 2의 환경 오버레이 (나중 = 우선)
# Source 2: 값(values) repo — dip-console이 렌더한 환경별 값
- repoURL: https://gitea.example.org/dip/values-test
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 10s
factor: 2
maxDuration: 3m
@@ -0,0 +1,3 @@
# 환경 오버레이 — kube-state-metrics/7.4.0/custom-values.yaml 위에 적용
# 환경 고유값 없음. 베이스(custom-values)로 충분. (필요 시 리소스 등 override)
{}
@@ -0,0 +1,3 @@
# 환경 오버레이 — prometheus-node-exporter/4.55.0/custom-values.yaml 위에 적용
# 환경 고유값 없음. 베이스(custom-values)로 충분.
{}
@@ -0,0 +1,3 @@
# 환경 오버레이 — opentelemetry-collector/0.156.2/custom-values-events.yaml (Deployment) 위에 적용
# K8s 이벤트 수집. 환경 고유값 없음.
{}
@@ -0,0 +1,3 @@
# 환경 오버레이 — opentelemetry-collector/0.156.2/custom-values.yaml (DaemonSet) 위에 적용
# 로그 파이프라인 설정은 베이스 재사용. 환경 고유값 없음.
{}
@@ -0,0 +1,34 @@
# 환경 오버레이 — perses/0.21.0/custom-values.yaml 위에 적용
# 환경별: OIDC issuer/redirect_uri, ingress(베이스에 없음 → 추가), client_secret(Infisical).
# dip-console이 $VAR를 Infisical/환경값으로 렌더해 값 repo에 커밋한다.
# (Helm 배열 교체: config.security.authentication.providers.oidc 전체 재정의)
config:
security:
enable_auth: true
authentication:
providers:
oidc:
- slug_id: keycloak
name: Keycloak
client_id: perses
client_secret: "$INFISICAL_PERSES_CLIENT_SECRET" # Infisical 출처(평문 커밋 금지)
issuer: "$KEYCLOAK_URL/realms/$KEYCLOAK_REALM"
redirect_uri: "https://perses.$DOMAIN/api/auth/providers/oidc/keycloak/callback"
scopes: [openid, profile, email]
# 외부 노출 (베이스 custom-values엔 ingress 없음)
ingress:
enabled: true
ingressClassName: "apisix"
annotations:
cert-manager.io/cluster-issuer: "root-ca-issuer"
hosts:
- host: "perses.$DOMAIN"
paths:
- path: /
pathType: Prefix
tls:
- secretName: perses-tls
hosts:
- "perses.$DOMAIN"
@@ -0,0 +1,5 @@
# 환경 오버레이 — victoria-logs-cluster/0.1.5/custom-values.yaml 위에 적용
vlstorage:
persistentVolume:
storageClass: "$STORAGE_CLASS"
@@ -0,0 +1,4 @@
# 환경 오버레이 — victoria-metrics-agent/0.40.0/custom-values.yaml 위에 적용
# 스크레이프 설정은 베이스 재사용. 테넌트별 remoteWrite/relabel은 dip-console이
# vmagent-relabel-configs ConfigMap으로 관리(차트 밖). 환경 고유값 없으면 비움.
{}
@@ -0,0 +1,3 @@
# 환경 오버레이 — victoria-metrics-alert/0.41.0/custom-values.yaml 위에 적용
# datasource(vmselect multitenant)·알림 규칙은 베이스 재사용. 내부 서비스라 환경 고유값 없음.
{}
@@ -0,0 +1,20 @@
# 환경 오버레이 — victoria-metrics-auth/0.33.0/custom-values.yaml 위에 적용
# Keycloak issuer만 환경별로 치환($VAR 문자열 치환). (Helm 배열 교체: config.users 전체를 재정의)
# 주의: {{.MetricsAccountID}}/{{.LogsAccountID}}는 vmauth 런타임 플레이스홀더이므로
# 그대로 보존되어야 한다($VAR 치환만 하고 Go 템플릿 렌더는 하지 않음).
config:
users:
- jwt:
oidc:
issuer: "$KEYCLOAK_URL/realms/$KEYCLOAK_REALM"
url_map:
- src_paths: ["/api/v1/.*"]
url_prefix: "http://vmcluster-victoria-metrics-cluster-vmselect.monitoring.svc.cluster.local:8481/select/{{.MetricsAccountID}}/prometheus"
- src_paths: ["/select/logsql/.*"]
url_prefix: "http://vlogs-victoria-logs-cluster-vlselect.monitoring.svc.cluster.local:9471"
headers:
- "AccountID: {{.LogsAccountID}}"
- "ProjectID: 0"
unauthorized_user:
url_prefix: "http://vmcluster-victoria-metrics-cluster-vmselect.monitoring.svc.cluster.local:8481/select/0/prometheus"
@@ -0,0 +1,8 @@
# 환경 오버레이 — victoria-metrics-cluster/0.43.0/custom-values.yaml 위에 적용
# dip-console이 환경값을 렌더해 값 repo(victoria-metrics/vmcluster-values.yaml)에 커밋한다.
# (Helm: map은 병합, 배열은 교체)
vmstorage:
persistentVolume:
# 기본 StorageClass를 쓰면 생략 가능. 명시 시 dip-console이 치환.
storageClass: "$STORAGE_CLASS"