docs: formalize monitoring deploy runbook; move test record to issue #2
배포 라이프사이클 3단계(배포 전 사전조건 / 배포 시 ApplicationSet / 배포 후 테넌트 관리)로 운영 런북(monitoring-deploy-guide.md) 신규 작성. 테스트 검증 기록(monitoring-deploy-test.md)은 GitHub 이슈 #2로 분리 후 close, 레포에서는 삭제. 아키텍처 문서에 런북 링크 추가. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,235 @@
|
|||||||
|
# VictoriaMetrics 모니터링 스택 배포 가이드 (운영 런북)
|
||||||
|
|
||||||
|
VM 옵저버빌리티 스택을 **처음 배포하는 운영자**를 위한 절차 문서. 배포 라이프사이클을 세 단계로 나눠 정리한다.
|
||||||
|
|
||||||
|
1. [배포 전 세팅](#1-배포-전-세팅-사전조건) — ArgoCD 동기화 전에 갖춰야 할 사전조건
|
||||||
|
2. [배포 시 세팅 및 배포 방법](#2-배포-시-필요한-세팅-및-배포-방법) — ApplicationSet 배포
|
||||||
|
3. [배포 후 테넌트 관리 변경 사항](#3-배포-후-테넌트-관리에-따라-수정되어야-하는-사항) — 운영 중 테넌트 추가/변경 시 수정 대상
|
||||||
|
|
||||||
|
> 관련 문서
|
||||||
|
> - [victoria-metrics-architecture.md](victoria-metrics-architecture.md) — 구성·데이터 흐름·멀티테넌시·인증 **상세**(why)
|
||||||
|
> - [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) — ArgoCD 배포 **검증 기록**(테스트 결과·수동 설정 backlog)
|
||||||
|
> - 차트별 설정: 각 `manifests/helm/<chart>/<ver>/CUSTOM-README.md`
|
||||||
|
|
||||||
|
## 구성 요약
|
||||||
|
|
||||||
|
| 항목 | 값 |
|
||||||
|
|---|---|
|
||||||
|
| 차트 / Application | 10 Helm 차트 → **11 Application** (opentelemetry-collector가 로그용·이벤트용 2개) |
|
||||||
|
| 네임스페이스 | `monitoring` (전 컴포넌트 공통) |
|
||||||
|
| 배포 방식 | ArgoCD **ApplicationSet** (list generator + goTemplate) |
|
||||||
|
| 소스 | **이중 소스** — 카탈로그(`service-catalog`, Helm 차트+베이스값) + 값 repo(`tenant-catalog`, 환경 오버레이) |
|
||||||
|
| 배포 순서 | syncWave **0 → 1 → 2** (저장소 → 수집·인증 → perses) |
|
||||||
|
| 인증 | Keycloak `paasup` realm JWT/OIDC, vmauth가 검증·테넌트 라우팅 |
|
||||||
|
|
||||||
|
매니페스트: [manifests/applicationset/victoria-metrics/1.0.0/](../manifests/applicationset/victoria-metrics/1.0.0/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 배포 전 세팅 (사전조건)
|
||||||
|
|
||||||
|
ArgoCD가 동기화를 시작하기 **전에** 반드시 준비되어야 한다. 누락 시 해당 컴포넌트가 기동/인증에 실패한다. 정식 환경에서 1.2~1.5는 **dip-console**이 오케스트레이션하고, 1.1은 플랫폼 기본 배포가 담당한다.
|
||||||
|
|
||||||
|
### 1.1 플랫폼 기본 (전제)
|
||||||
|
|
||||||
|
| 항목 | 요구 | 누락 시 |
|
||||||
|
|---|---|---|
|
||||||
|
| StorageClass | `longhorn` (기본) | vmstorage/vlstorage/perses **PVC Pending** |
|
||||||
|
| Ingress controller | `apisix` | perses 외부 노출 불가 |
|
||||||
|
| cert-manager | `root-ca-issuer` (ClusterIssuer) | perses TLS 발급 실패 |
|
||||||
|
| DNS | `perses.<domain>` 등 | 콜백/접속 실패 |
|
||||||
|
|
||||||
|
### 1.2 Keycloak (`paasup` realm)
|
||||||
|
|
||||||
|
> **realm 신규 생성 금지.** 배포 환경에 항상 존재하는 `paasup` realm에 아래 리소스를 추가한다.
|
||||||
|
|
||||||
|
| 리소스 | 용도 |
|
||||||
|
|---|---|
|
||||||
|
| Client Scope `vm-access` (+ User Attribute 매퍼 2종) | 토큰에 `vm_access.metrics_account_id` / `vm_access.logs_account_id` 클레임 주입 (점 표기 → 중첩 JSON) |
|
||||||
|
| Client `perses` | Perses UI OIDC 로그인 (standard flow) |
|
||||||
|
| Client `perses-vmauth` | 데이터소스 service-account (client_credentials), `vm-access` scope 연결 + SA attribute(`vm_*_account_id`) |
|
||||||
|
|
||||||
|
생성 절차(Admin API curl)는 [victoria-metrics-auth CUSTOM-README](../manifests/helm/victoria-metrics-auth/0.33.0/CUSTOM-README.md) 3장 / [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §3.2 참조.
|
||||||
|
|
||||||
|
### 1.3 시크릿 (Infisical → external-secrets)
|
||||||
|
|
||||||
|
차트는 인라인 시크릿을 두지 않고 `existingSecret`만 참조한다. dip-console이 Infisical에 등록 → external-secrets가 `monitoring` ns에 Secret을 동기화한다.
|
||||||
|
|
||||||
|
| Secret (ns=monitoring) | 키 | 사용처 |
|
||||||
|
|---|---|---|
|
||||||
|
| `root-ca-cert` | `ca.crt` | **vmauth·perses** 양쪽 마운트 (Keycloak OIDC TLS 검증) |
|
||||||
|
| `alertmanager-notify` | `webhook-url` 등 | alertmanager 알림 채널 자격증명 (파일 마운트) |
|
||||||
|
| perses OIDC client_secret | — | perses `config.security.authentication`(`secret.create=false`) |
|
||||||
|
|
||||||
|
> ⚠️ **사내 CA 신뢰 필수 (중대)**
|
||||||
|
> Keycloak이 사내 CA로 서명된 경우, JWT/OIDC 소비자는 issuer의 `.well-known/openid-configuration`(OIDC discovery)·JWKS를 HTTPS로 가져올 때 그 CA를 신뢰해야 한다. **vmauth·perses 모두** `root-ca-cert`를 마운트하고 `SSL_CERT_FILE=/ca/ca.crt`를 설정한다(custom-values에 반영됨).
|
||||||
|
> - 누락 시 vmauth는 OIDC verifier 초기화 실패(`x509: certificate signed by unknown authority`) → **모든 JWT 검증 불가(401)**. perses는 OAuth 토큰 발급/콜백 실패.
|
||||||
|
> - 실제 본 스택 배포 테스트에서 발생했고(perses 대시보드 unauthorized), `unauthorized_user` 폴백이 한동안 이를 가렸다. 자세한 경위는 [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §8.
|
||||||
|
> - 퍼블릭 CA(Let's Encrypt 등)면 시스템 신뢰 저장소로 충분 → 불필요.
|
||||||
|
|
||||||
|
### 1.4 relabel ConfigMap
|
||||||
|
|
||||||
|
vmagent base custom-values가 `vmagent-relabel-configs` ConfigMap을 마운트한다(테넌트별 키: `demo01.yaml` / `demo02.yaml` / `platform.yaml`).
|
||||||
|
|
||||||
|
- 초기 배포 시엔 빈 규칙(`[]`)으로도 기동 가능.
|
||||||
|
- 테넌트별 keep 필터 채우기는 **§3(배포 후 테넌트 관리)** 에서 다룬다. dip-console이 테넌트 온보딩 시 갱신.
|
||||||
|
|
||||||
|
### 1.5 값(values) repo
|
||||||
|
|
||||||
|
`tenant-catalog` repo의 `victoria-metrics/<chart>-values.yaml` 11종에 환경 오버레이를 둔다. dip-console이 `$VAR`(도메인/Keycloak URL/realm/StorageClass/시크릿명)를 치환해 렌더·push한다.
|
||||||
|
|
||||||
|
- 환경 고유값이 있는 차트만 실제 내용: **vmauth**(issuer), **perses**(OIDC·ingress·globalAdminUsers), **alertmanager**(시크릿 마운트), **vmcluster·vlogs**(storageClass).
|
||||||
|
- 나머지 6종(kube-state-metrics/node-exporter/otelcol/otelcol-events/vmagent/vmalert)은 `{}` — 베이스 custom-values만 사용.
|
||||||
|
- 주의: vmauth 오버레이의 `{{.MetricsAccountID}}` / `{{.LogsAccountID}}`는 **vmauth 런타임 플레이스홀더**다. `$VAR` 문자열 치환만 하고 Go 템플릿 렌더는 하지 않는다.
|
||||||
|
|
||||||
|
### 사전조건 체크리스트
|
||||||
|
|
||||||
|
| # | 항목 | 담당 | 누락 시 실패 지점 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | StorageClass / Ingress / cert-manager / DNS | 플랫폼 기본 | PVC Pending, ingress/TLS 실패 |
|
||||||
|
| 2 | Keycloak `vm-access` scope + `perses`/`perses-vmauth` client | dip-console | vmauth JWT·perses 로그인 실패 |
|
||||||
|
| 3 | `root-ca-cert` Secret (+ SSL_CERT_FILE) | dip-console | **vmauth 전체 JWT 401**, perses OAuth 실패 |
|
||||||
|
| 4 | `alertmanager-notify` Secret | dip-console / Infisical | alertmanager 기동 실패 |
|
||||||
|
| 5 | perses OIDC client_secret | dip-console / Infisical | perses 로그인 실패 |
|
||||||
|
| 6 | `vmagent-relabel-configs` ConfigMap | dip-console | vmagent 기동 실패 |
|
||||||
|
| 7 | 값 repo `<chart>-values.yaml` 렌더·push | dip-console | ArgoCD 동기화 실패(`$values` 참조 불가) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 배포 시 필요한 세팅 및 배포 방법
|
||||||
|
|
||||||
|
### 2.1 ArgoCD repo 등록
|
||||||
|
|
||||||
|
이중 소스이므로 두 repo가 ArgoCD에 등록돼야 한다.
|
||||||
|
|
||||||
|
- `service-catalog` (카탈로그) — Helm 차트·베이스 custom-values.
|
||||||
|
- `tenant-catalog` (값 repo) — `$values` ref로 참조하는 환경 오버레이.
|
||||||
|
|
||||||
|
사내 gitea는 TLS 신뢰 문제로 repo secret에 `insecure: true` 또는 CA를 지정한다(기존 repo secret 복제 방식 가능). 절차/명령 예시는 [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §4.
|
||||||
|
|
||||||
|
### 2.2 ApplicationSet 조정 포인트
|
||||||
|
|
||||||
|
[applicationset.yaml](../manifests/applicationset/victoria-metrics/1.0.0/applicationset.yaml)에서 환경에 맞춰 확인/수정한다.
|
||||||
|
|
||||||
|
| 위치 | 의미 | 비고 |
|
||||||
|
|---|---|---|
|
||||||
|
| `metadata.namespace` / `template.metadata.namespace` | **ArgoCD 설치 ns** | 본 환경은 `platform`(ArgoCD가 거기 설치됨) |
|
||||||
|
| `sources[].repoURL` / `targetRevision` | 카탈로그·값 repo URL·브랜치 | 예시 도메인 `gitea.example.org` → 실제 git로 |
|
||||||
|
| `destination.namespace` | 배포 대상 ns | `monitoring` 고정 |
|
||||||
|
|
||||||
|
**이중 소스 2단 valueFiles** (나중 파일이 우선):
|
||||||
|
```yaml
|
||||||
|
sources:
|
||||||
|
- repoURL: .../service-catalog # Source 1: 차트
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- "{{ .baseValues }}" # custom-values.yaml (정적 베이스)
|
||||||
|
- $values/{{ .valuesPath }} # tenant-catalog 오버레이 (우선)
|
||||||
|
- repoURL: .../tenant-catalog # Source 2: 값 repo
|
||||||
|
ref: values
|
||||||
|
```
|
||||||
|
> Helm 값 병합 규칙: **맵은 merge, 배열은 replace**. 예) vmauth `config.users`(배열)는 오버레이가 전체를 교체한다.
|
||||||
|
|
||||||
|
### 2.3 배포 실행
|
||||||
|
|
||||||
|
```sh
|
||||||
|
kubectl apply -f manifests/applicationset/victoria-metrics/1.0.0/applicationset.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
ApplicationSet이 11개 Application을 생성하고 syncWave 순서로 동기화한다.
|
||||||
|
|
||||||
|
```
|
||||||
|
wave 0 : vmcluster · vlogs · kube-state-metrics · node-exporter · alertmanager
|
||||||
|
wave 1 : vmauth · vmagent · otelcol · otelcol-events · vmalert
|
||||||
|
wave 2 : perses ← vmauth 기동 후
|
||||||
|
```
|
||||||
|
|
||||||
|
`syncPolicy.automated{prune,selfHeal}` + `CreateNamespace=true` + `ServerSideApply=true`, retry 5회.
|
||||||
|
|
||||||
|
### 2.4 알려진 drift 처리 (이미 반영됨)
|
||||||
|
|
||||||
|
vmstorage/vlstorage의 StatefulSet `volumeClaimTemplates`는 immutable이고 K8s가 `volumeMode` 등 기본값을 자동 주입해 **영구 OutOfSync**가 발생한다. ApplicationSet에 `ignoreDifferences`로 해소되어 있다.
|
||||||
|
```yaml
|
||||||
|
ignoreDifferences:
|
||||||
|
- group: apps
|
||||||
|
kind: StatefulSet
|
||||||
|
jsonPointers: [/spec/volumeClaimTemplates]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5 배포 후 검증 (요약)
|
||||||
|
|
||||||
|
| 확인 | 기대값 |
|
||||||
|
|---|---|
|
||||||
|
| Application | 11개 **Synced + Healthy** |
|
||||||
|
| 파드 | `monitoring` 전 파드 Running |
|
||||||
|
| 메트릭 | vmselect `count(up)` > 0 |
|
||||||
|
| 인증 라우팅 | 유효 Keycloak JWT → vmauth `/api/v1/query` **200**, 무토큰 **401** |
|
||||||
|
| perses | OIDC 로그인 성공 (식별자 = `preferred_username`) |
|
||||||
|
|
||||||
|
상세 검증 절차·결과는 [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §5.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 배포 후 테넌트 관리에 따라 수정되어야 하는 사항
|
||||||
|
|
||||||
|
운영 중 **테넌트 추가/권한 변경** 시 무엇을 바꿔야 하고 무엇은 무변경인지. 설계 배경은 [architecture §5·§5.1·§6](victoria-metrics-architecture.md#5-멀티테넌시).
|
||||||
|
|
||||||
|
### 3.1 변경 매트릭스
|
||||||
|
|
||||||
|
| 시나리오 | Keycloak | vmagent (값 repo) | relabel ConfigMap | otelcol | 재배포 |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 같은 테넌트의 **새 네임스페이스**(`demo01-*`) | — | — | — (prefix 정규식이 커버) | — | **불필요** |
|
||||||
|
| **새 테넌트**(새 accountID) | group + user attribute(`vm_*_account_id`) 추가 | remoteWrite `/insert/{N}/` + `urlRelabelConfig` keep 추가 | 키(`<tenant>.yaml`) 추가 | AccountID 헤더 필터 추가 | **vmagent 재배포** |
|
||||||
|
| 기존 사용자에게 **조회 권한만** 부여 | user attribute 설정 | — | — | — | 불필요(토큰 재발급만) |
|
||||||
|
|
||||||
|
> 핵심: **vmauth는 테넌트 추가로 재배포할 필요가 없다.** vmauth는 JWT의 `vm_access` 클레임으로 동적 라우팅하므로 Keycloak attribute만 바뀌면 된다. 재배포가 필요한 건 **쓰기(write) 경로의 vmagent**다(per-URL 라우팅 채택 결과).
|
||||||
|
|
||||||
|
### 3.2 per-URL 라우팅을 쓰는 이유 (요약)
|
||||||
|
|
||||||
|
새 테넌트(새 accountID) 추가가 ConfigMap 한 줄이 아니라 **vmagent 값 변경 → Git/PR**을 거치는 이유:
|
||||||
|
- **스푸핑 차단** — 테넌시가 URL(`/insert/{accountID}/`)로 고정되어 스크레이프 대상이 `vm_account_id` 라벨을 노출해도 위장 불가.
|
||||||
|
- **변경 통제** — 새 테넌트 추가가 PR 리뷰·승인을 거침.
|
||||||
|
- **장애 격리** — remoteWrite 큐가 테넌트별로 분리되어 cross-tenant 파급 제한.
|
||||||
|
|
||||||
|
대안(multitenant+라벨)과의 비교는 [architecture §5.1](victoria-metrics-architecture.md#51-메트릭-쓰기-경로-테넌트-라우팅-결정-per-url).
|
||||||
|
|
||||||
|
### 3.3 메트릭 vs 로그 격리 차이
|
||||||
|
|
||||||
|
하나의 토큰(`vm_access` 클레임)이 두 차원을 함께 담는다.
|
||||||
|
|
||||||
|
| 시그널 | 격리 방식 | vmauth 동작 | 클레임 필드 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 메트릭 | URL **경로** `/select/{accountID}/prometheus` | url_prefix 경로 치환 `{{.MetricsAccountID}}` | `metrics_account_id` |
|
||||||
|
| 로그 | HTTP **헤더** `AccountID` / `ProjectID` | 헤더 주입 `AccountID: {{.LogsAccountID}}` | `logs_account_id` |
|
||||||
|
|
||||||
|
> 메트릭은 `/select/multitenant/`로 전체 집계가 가능하나, VictoriaLogs는 합산 엔드포인트가 없어 `(AccountID, ProjectID)` 단위로만 조회된다.
|
||||||
|
|
||||||
|
### 3.4 Perses 권한 관리
|
||||||
|
|
||||||
|
- Perses는 OIDC group 자동 동기화를 지원하지 않는다 → **Project별 Role/RoleBinding을 수동 관리**.
|
||||||
|
- 로그인 식별자는 OIDC **`preferred_username`**(v0.53.1 실측, sub UUID 아님).
|
||||||
|
- global-admin은 `sidecar.globalAdminUsers`에 username을 지정(GlobalRole/GlobalRoleBinding 부트스트랩).
|
||||||
|
|
||||||
|
### 3.5 알림 채널 교체
|
||||||
|
|
||||||
|
Alertmanager `config.receivers`는 채널 무관하게 작성하고 자격증명은 Infisical 시크릿을 파일로 마운트한다(평문 금지).
|
||||||
|
|
||||||
|
**새 채널 추가 3단계**: ① Infisical에 자격증명 등록 → ② 값 repo의 `config.receivers`(+ 시크릿 마운트) 추가, `route.receiver` 지정 → ③ ArgoCD 재동기화.
|
||||||
|
|
||||||
|
| 채널 | receiver 키 | 자격증명(파일 마운트) |
|
||||||
|
|---|---|---|
|
||||||
|
| Discord | `discord_configs.webhook_url_file` | webhook URL |
|
||||||
|
| Slack | `slack_configs.api_url_file` | webhook URL |
|
||||||
|
| Email | `email_configs`(smarthost/from/to) | `auth_password_file` |
|
||||||
|
|
||||||
|
상세: [architecture §12.5](victoria-metrics-architecture.md#125-알림-채널-교체-가능-구조) / [alertmanager CUSTOM-README](../manifests/helm/alertmanager/1.37.0/CUSTOM-README.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 미완 / Backlog
|
||||||
|
|
||||||
|
- **perses 데이터소스 GitOps 편입** — `perses-provisioning`(데이터소스+OAuth 시크릿)을 ArgoCD directory 소스로 포함(현재 수동 apply).
|
||||||
|
- **멀티테넌시 음성검증** — demo01/demo02 워크로드 + 실제 keep relabel 규칙으로 cross-tenant 차단 확인.
|
||||||
|
- **teardown 절차** — [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §6.
|
||||||
|
|
||||||
|
테스트에서 수동 실행한 설정 목록(dip-console 자동화 후보)은 [배포 테스트 기록 #2](https://github.com/paasup/dip-catalog/issues/2) §7.
|
||||||
@@ -1,344 +0,0 @@
|
|||||||
# VictoriaMetrics 모니터링 스택 배포 테스트
|
|
||||||
|
|
||||||
카탈로그의 VM 옵저버빌리티 스택(11개 Application)을 **ArgoCD 전체 GitOps 경로**로 배포·검증하는 절차와 기록 문서. 테스트 완료 후 본 문서를 바탕으로 이슈에 결과를 정리한다.
|
|
||||||
|
|
||||||
- 아키텍처: [victoria-metrics-architecture.md](victoria-metrics-architecture.md)
|
|
||||||
- ApplicationSet: [manifests/applicationset/victoria-metrics/1.0.0/](../manifests/applicationset/victoria-metrics/1.0.0/)
|
|
||||||
- 카탈로그(테스트 업로드): `https://gitea.example.org/dip/service-catalog` (branch `master`)
|
|
||||||
|
|
||||||
## 표기 규칙 (중요)
|
|
||||||
|
|
||||||
> 🔧 **수동 설정** — dip-console/ArgoCD가 아니라 **사람이 스크립트·명령어로 직접 설정**한 항목. 이 마커가 붙은 내용은 모두 **[§7 수동 설정 목록](#7-수동-설정-목록-이슈자동화-backlog)**에 모이며, 이슈 정리 + 향후 dip-console 자동화 대상이다. 새 수동 작업이 생기면 같은 마커로 표기하고 §7에 추가한다.
|
|
||||||
|
|
||||||
테스트 중 각 단계의 `[ ]` 체크박스와 결과란을 채운다.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. 테스트 환경 / 전제
|
|
||||||
|
|
||||||
| 항목 | 값 / 상태 |
|
|
||||||
|------|-----------|
|
|
||||||
| 클러스터 | (기입: context / API 도달 여부) |
|
|
||||||
| ArgoCD | (기입: 버전 / namespace) |
|
|
||||||
| StorageClass | longhorn (전제) |
|
|
||||||
| Ingress / cert-manager | apisix / `root-ca-issuer` (전제) |
|
|
||||||
| Keycloak | `paasup` realm, 도달 URL (기입) |
|
|
||||||
| 카탈로그 repo | `gitea.example.org/dip/service-catalog` @ `master` |
|
|
||||||
| 값(values) repo | (기입: URL @ branch) |
|
|
||||||
| 사전조건 준비 방식 | **수동 목(mock)** — dip-console 미사용 |
|
|
||||||
|
|
||||||
> 경로: ArgoCD ApplicationSet 이중 소스(카탈로그 + 값 repo) + syncWave 0→1→2. 사전조건은 수동 목으로 준비한다.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. 0단계 — 로컬 정적 검증 (클러스터 불필요)
|
|
||||||
|
|
||||||
- [x] 오버레이 `$VAR`를 테스트값으로 치환 후 2단 병합 렌더 확인 — **11/11 PASS**
|
|
||||||
```sh
|
|
||||||
# 차트마다: 베이스(custom-values) + 렌더된 오버레이
|
|
||||||
helm template <release> manifests/helm/<chart>/<ver> \
|
|
||||||
-f manifests/helm/<chart>/<ver>/custom-values.yaml \
|
|
||||||
-f /tmp/<chart>-overlay-rendered.yaml > /dev/null
|
|
||||||
```
|
|
||||||
- [x] vmauth 렌더 config에 issuer·`{{.MetricsAccountID}}`·로그 `AccountID` 헤더 포함 확인 — **PASS**
|
|
||||||
- [x] `applicationset.yaml` / `perses-dashboards.yaml` / `perses-provisioning.yaml` YAML 유효성 — **PASS**
|
|
||||||
|
|
||||||
결과: ✅ **0단계 통과 (2026-06-25)**
|
|
||||||
- 2단 병합 렌더 11/11 OK (vmcluster·vlogs·ksm·node-exporter·alertmanager·vmauth·vmagent·otelcol·otelcol-events·vmalert·perses). otelcol 로그전용(trace 포트 0), perses ingress 포함(docs=14).
|
|
||||||
- vmauth 렌더 `auth.yml`: issuer `realms/paasup`, 메트릭 경로 `{{.MetricsAccountID}}`, 로그 헤더 `AccountID: {{.LogsAccountID}}`, `unauthorized_user` accountID 0 모두 확인($VAR 치환 후에도 vmauth 플레이스홀더 보존).
|
|
||||||
- 매니페스트 3종 YAML 유효(applicationset / perses-dashboards / perses-provisioning).
|
|
||||||
- 테스트 치환값: `$STORAGE_CLASS=longhorn`, `$KEYCLOAK_URL=https://keycloak.example.org`, `$KEYCLOAK_REALM=paasup`, `$DOMAIN=example.org` (검증용 임시값, 실제 배포는 dip-console 렌더).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. 1단계 — 사전조건 수동 목 준비
|
|
||||||
|
|
||||||
> 🔧 **수동 설정** — 이 단계 전체가 수동 목. dip-console이 대신할 작업들이다. **3.1~3.5 모두 실행 완료(2026-06-25)**. 명령·결과는 각 절 + §7에 집계.
|
|
||||||
>
|
|
||||||
> 테스트 환경값: `DOMAIN=example.org`, `KEYCLOAK_URL=https://keycloak.example.org`, `KEYCLOAK_REALM=paasup`, `STORAGE_CLASS=longhorn`. `root-ca-cert` 소스 = `cert-manager/root-ca-secret`(`ca.crt`).
|
|
||||||
|
|
||||||
### 3.1 값(values) repo — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
- [x] 오버레이 11종을 `$VAR` 치환(문자열 치환만, `{{.MetricsAccountID}}` 등 보존) → `~/project/tenant-catalog/victoria-metrics/`에 생성 후 push
|
|
||||||
```sh
|
|
||||||
# dip-catalog 오버레이 → tenant-catalog 렌더 (sed 문자열 치환)
|
|
||||||
for f in manifests/applicationset/victoria-metrics/1.0.0/*-values.yaml; do
|
|
||||||
sed -e 's#$STORAGE_CLASS#longhorn#g' -e 's#$KEYCLOAK_URL#https://keycloak.example.org#g' \
|
|
||||||
-e 's#$KEYCLOAK_REALM#paasup#g' -e 's#$DOMAIN#example.org#g' \
|
|
||||||
-e 's#$INFISICAL_PERSES_CLIENT_SECRET#perses-mock-secret-changeme#g' \
|
|
||||||
-e 's#$INFISICAL_ALERTMANAGER_SECRET#alertmanager-notify#g' "$f" \
|
|
||||||
> ~/project/tenant-catalog/victoria-metrics/$(basename "$f")
|
|
||||||
done
|
|
||||||
cd ~/project/tenant-catalog && git add -A && git commit -m "Add victoria-metrics values (mock)" && git push origin master
|
|
||||||
```
|
|
||||||
결과: `dip/tenant-catalog` @ master `510aa8e`, `victoria-metrics/*-values.yaml` 11개.
|
|
||||||
|
|
||||||
**생성된 값 파일 내용** (환경 고유값 있는 차트만; 나머지 6종 `kube-state-metrics`/`node-exporter`/`otelcol`/`otelcol-events`/`vmagent`/`vmalert`-values.yaml = `{}` — 베이스 custom-values만 사용)
|
|
||||||
|
|
||||||
`vmauth-values.yaml`
|
|
||||||
```yaml
|
|
||||||
config:
|
|
||||||
users:
|
|
||||||
- jwt:
|
|
||||||
oidc:
|
|
||||||
issuer: "https://keycloak.example.org/realms/paasup"
|
|
||||||
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"
|
|
||||||
```
|
|
||||||
|
|
||||||
`perses-values.yaml`
|
|
||||||
```yaml
|
|
||||||
config:
|
|
||||||
security:
|
|
||||||
enable_auth: true
|
|
||||||
authentication:
|
|
||||||
providers:
|
|
||||||
oidc:
|
|
||||||
- slug_id: keycloak
|
|
||||||
name: Keycloak
|
|
||||||
client_id: perses
|
|
||||||
client_secret: "perses-mock-secret-changeme"
|
|
||||||
issuer: "https://keycloak.example.org/realms/paasup"
|
|
||||||
redirect_uri: "https://perses.example.org/api/auth/providers/oidc/keycloak/callback"
|
|
||||||
scopes: [openid, profile, email]
|
|
||||||
ingress:
|
|
||||||
enabled: true
|
|
||||||
ingressClassName: "apisix"
|
|
||||||
annotations:
|
|
||||||
cert-manager.io/cluster-issuer: "root-ca-issuer"
|
|
||||||
hosts:
|
|
||||||
- host: "perses.example.org"
|
|
||||||
paths: [{ path: /, pathType: Prefix }]
|
|
||||||
tls:
|
|
||||||
- secretName: perses-tls
|
|
||||||
hosts: ["perses.example.org"]
|
|
||||||
```
|
|
||||||
|
|
||||||
`alertmanager-values.yaml`
|
|
||||||
```yaml
|
|
||||||
extraSecretMounts:
|
|
||||||
- name: alertmanager-notify
|
|
||||||
mountPath: /etc/alertmanager/secrets
|
|
||||||
subPath: ""
|
|
||||||
secretName: "alertmanager-notify"
|
|
||||||
readOnly: true
|
|
||||||
```
|
|
||||||
|
|
||||||
`vmcluster-values.yaml` / `vlogs-values.yaml`
|
|
||||||
```yaml
|
|
||||||
# vmcluster
|
|
||||||
vmstorage: { persistentVolume: { storageClass: "longhorn" } }
|
|
||||||
# vlogs
|
|
||||||
vlstorage: { persistentVolume: { storageClass: "longhorn" } }
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.2 Keycloak (paasup realm) — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
확인됨: `paasup` realm 존재(HTTP 200), `perses`/`perses-vmauth` client·`vm-access` scope **없음**(신규 생성 대상).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# ── 관리자 토큰 (platform Keycloak) ──
|
|
||||||
KC=https://keycloak.example.org; REALM=paasup
|
|
||||||
PW=$(kubectl get secret -n platform keycloak -o jsonpath='{.data.admin-password}' | base64 -d)
|
|
||||||
TOKEN=$(curl -sk -X POST "$KC/realms/master/protocol/openid-connect/token" \
|
|
||||||
-d grant_type=password -d client_id=admin-cli -d username=admin --data-urlencode "password=$PW" | jq -r .access_token)
|
|
||||||
H="Authorization: Bearer $TOKEN"; JSON="Content-Type: application/json"
|
|
||||||
|
|
||||||
# ── 1) Client Scope vm-access + 매퍼 2종 ──
|
|
||||||
curl -sk -X POST "$KC/admin/realms/$REALM/client-scopes" -H "$H" -H "$JSON" \
|
|
||||||
-d '{"name":"vm-access","protocol":"openid-connect"}'
|
|
||||||
SID=$(curl -sk "$KC/admin/realms/$REALM/client-scopes" -H "$H" | jq -r '.[]|select(.name=="vm-access").id')
|
|
||||||
for m in metrics logs; do
|
|
||||||
curl -sk -X POST "$KC/admin/realms/$REALM/client-scopes/$SID/protocol-mappers/models" -H "$H" -H "$JSON" \
|
|
||||||
-d "{\"name\":\"vm-$m-account\",\"protocol\":\"openid-connect\",\"protocolMapper\":\"oidc-usermodel-attribute-mapper\",\"config\":{\"user.attribute\":\"vm_${m}_account_id\",\"claim.name\":\"vm_access.${m}_account_id\",\"jsonType.label\":\"int\",\"access.token.claim\":\"true\",\"id.token.claim\":\"false\"}}"
|
|
||||||
done
|
|
||||||
|
|
||||||
# ── 2) Client perses (로그인) — secret은 perses-values.yaml의 client_secret과 일치 ──
|
|
||||||
curl -sk -X POST "$KC/admin/realms/$REALM/clients" -H "$H" -H "$JSON" -d '{
|
|
||||||
"clientId":"perses","enabled":true,"publicClient":false,"standardFlowEnabled":true,
|
|
||||||
"secret":"perses-mock-secret-changeme",
|
|
||||||
"redirectUris":["https://perses.example.org/api/auth/providers/oidc/keycloak/callback"]}'
|
|
||||||
|
|
||||||
# ── 3) Client perses-vmauth (datasource service-account) ──
|
|
||||||
curl -sk -X POST "$KC/admin/realms/$REALM/clients" -H "$H" -H "$JSON" -d '{
|
|
||||||
"clientId":"perses-vmauth","enabled":true,"publicClient":false,
|
|
||||||
"standardFlowEnabled":false,"serviceAccountsEnabled":true,"secret":"perses-vmauth-secret-changeme"}'
|
|
||||||
CID=$(curl -sk "$KC/admin/realms/$REALM/clients?clientId=perses-vmauth" -H "$H" | jq -r '.[0].id')
|
|
||||||
curl -sk -X PUT "$KC/admin/realms/$REALM/clients/$CID/default-client-scopes/$SID" -H "$H" # vm-access 연결
|
|
||||||
SAU=$(curl -sk "$KC/admin/realms/$REALM/clients/$CID/service-account-user" -H "$H" | jq -r .id)
|
|
||||||
curl -sk -X PUT "$KC/admin/realms/$REALM/users/$SAU" -H "$H" -H "$JSON" \
|
|
||||||
-d '{"attributes":{"vm_metrics_account_id":["0"],"vm_logs_account_id":["0"]}}' # 플랫폼 조회(account 0)
|
|
||||||
|
|
||||||
# ── (선택) 테스트 유저 attribute: 테넌트 격리 검증용 ──
|
|
||||||
# UID=$(curl -sk "$KC/admin/realms/$REALM/users?username=<user>" -H "$H" | jq -r '.[0].id')
|
|
||||||
# curl -sk -X PUT "$KC/admin/realms/$REALM/users/$UID" -H "$H" -H "$JSON" \
|
|
||||||
# -d '{"attributes":{"vm_metrics_account_id":["1"],"vm_logs_account_id":["1"]}}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 시크릿 (평문 목 — external-secrets/Infisical 대체) — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
> `monitoring` ns 선생성 필요(ArgoCD `CreateNamespace`는 sync 시점 → 사전 생성). perses OIDC `client_secret`은 perses-values.yaml에 인라인이라 별도 Secret 불필요(목). `root-ca-cert`·`alertmanager-notify`만 필요.
|
|
||||||
>
|
|
||||||
> ⚠️ `root-ca-cert`는 **vmauth·perses 양쪽**이 마운트(SSL_CERT_FILE)해 Keycloak OIDC TLS 검증에 사용. **누락 시 vmauth가 JWT 검증 불가(x509)** — 본 테스트에서 실제 발생(§8 참조).
|
|
||||||
|
|
||||||
```sh
|
|
||||||
kubectl create namespace monitoring --dry-run=client -o yaml | kubectl apply -f -
|
|
||||||
|
|
||||||
# alertmanager 알림 자격증명 (base custom-values가 /etc/alertmanager/secrets/webhook-url 참조)
|
|
||||||
kubectl create secret generic alertmanager-notify -n monitoring \
|
|
||||||
--from-literal=webhook-url='https://discord.com/api/webhooks/<MOCK>'
|
|
||||||
|
|
||||||
# Keycloak TLS 신뢰용 CA (perses base custom-values가 secretName: root-ca-cert, key ca.crt 마운트)
|
|
||||||
# 사내 CA 소스: cert-manager/root-ca-secret (ca.crt, 1261 bytes)
|
|
||||||
kubectl get secret root-ca-secret -n cert-manager -o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/ca.crt
|
|
||||||
kubectl create secret generic root-ca-cert -n monitoring --from-file=ca.crt=/tmp/ca.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
**생성된 Secret** (ns=monitoring)
|
|
||||||
|
|
||||||
| Secret | 키 | 값 / 출처 |
|
|
||||||
|--------|-----|-----------|
|
|
||||||
| `alertmanager-notify` | `webhook-url` | `https://discord.com/api/webhooks/MOCK/MOCK` (mock) |
|
|
||||||
| `root-ca-cert` | `ca.crt` | `cert-manager/root-ca-secret`의 `ca.crt` 복사 (1261 bytes) |
|
|
||||||
|
|
||||||
### 3.4 ConfigMap — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
vmagent base custom-values가 `vmagent-relabel-configs`(테넌트별 demo01/demo02/platform) 마운트. 목은 빈 규칙으로도 기동 가능.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# 테넌트별 write_relabel_configs (예: 최소 빈 규칙). 실제 규칙은 dip-console이 테넌트 온보딩 시 채움.
|
|
||||||
for t in demo01 demo02 platform; do echo "[]" > /tmp/$t.yaml; done
|
|
||||||
kubectl create configmap vmagent-relabel-configs -n monitoring \
|
|
||||||
--from-file=demo01.yaml=/tmp/demo01.yaml --from-file=demo02.yaml=/tmp/demo02.yaml --from-file=platform.yaml=/tmp/platform.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
**생성된 ConfigMap `vmagent-relabel-configs`** — 3개 키, 각 내용(mock):
|
|
||||||
```yaml
|
|
||||||
# demo01.yaml
|
|
||||||
[]
|
|
||||||
# demo02.yaml
|
|
||||||
[]
|
|
||||||
# platform.yaml
|
|
||||||
[]
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.5 대시보드 — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
정적 대시보드 ConfigMap(사이드카 로드). 테스트에선 임시 apply, 정식은 ArgoCD directory 소스 Application.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
kubectl apply -n monitoring -f manifests/helm/perses/0.21.0/files/perses-dashboards.yaml
|
|
||||||
# (데이터소스/시크릿은 perses-provisioning.yaml — 환경별이라 dip-console/Infisical 관리)
|
|
||||||
```
|
|
||||||
|
|
||||||
**생성된 ConfigMap `perses-dashboards`** — label `perses.dev/resource: "true"`, data 키 4종(대시보드 JSON): `dashboard-k8s-nodes.json`, `dashboard-k8s-pod-diagnostics.json`, `dashboard-k8s-pod-history.json`, `dashboard-k8s-workloads.json`. 원본: [perses-dashboards.yaml](../manifests/helm/perses/0.21.0/files/perses-dashboards.yaml).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. 2단계 — ArgoCD 배포 — ✅ 실행 완료 (2026-06-25)
|
|
||||||
|
|
||||||
> ArgoCD는 `platform` ns에 설치(release `argo-cd`). ApplicationSet도 `platform` ns에 apply.
|
|
||||||
|
|
||||||
- [x] repo 등록: `service-catalog`는 기등록(insecure=true). `tenant-catalog`는 기존 repo secret 복제로 신규 등록
|
|
||||||
> 🔧 **수동 설정**: `kubectl get secret repo-3724134660 -n platform -o json | jq '.metadata.name="repo-tenant-catalog" | .data.url=("https://gitea.example.org/dip/tenant-catalog"|@base64)' | kubectl apply -f -` → §7
|
|
||||||
- [x] `applicationset.yaml` 조정: ns `argocd`→`platform`, repoURL `service-catalog`/`tenant-catalog`, `targetRevision: master`
|
|
||||||
- [x] 로컬 변경분 `service-catalog` push (`d1f7c77`) 후 `kubectl apply -f .../applicationset.yaml`
|
|
||||||
- [x] wave 0→1→2 순서 동기화, perses(wave2) vmauth 이후 기동 확인
|
|
||||||
|
|
||||||
결과: **15/15 파드 Running, PVC 3개 Bound, 11 Application 전부 Healthy**(9 Synced + 2 OutOfSync).
|
|
||||||
|
|
||||||
| Application | wave | Sync | Health |
|
|
||||||
|-------------|------|------|--------|
|
|
||||||
| vmcluster | 0 | ✅ Synced¹ | ✅ Healthy |
|
|
||||||
| vlogs | 0 | ✅ Synced¹ | ✅ Healthy |
|
|
||||||
| kube-state-metrics | 0 | ✅ Synced | ✅ Healthy |
|
|
||||||
| node-exporter | 0 | ✅ Synced | ✅ Healthy |
|
|
||||||
| alertmanager | 0 | ✅ Synced | ✅ Healthy |
|
|
||||||
| vmauth | 1 | ✅ Synced | ✅ Healthy |
|
|
||||||
| vmagent | 1 | ✅ Synced | ✅ Healthy |
|
|
||||||
| otelcol | 1 | ✅ Synced | ✅ Healthy |
|
|
||||||
| otelcol-events | 1 | ✅ Synced | ✅ Healthy |
|
|
||||||
| vmalert | 1 | ✅ Synced | ✅ Healthy |
|
|
||||||
| perses | 2 | ✅ Synced | ✅ Healthy |
|
|
||||||
|
|
||||||
> ¹ **vmcluster/vlogs (해결됨)** — 초기엔 `vmstorage`/`vlstorage` **StatefulSet `volumeClaimTemplates`**의 K8s 자동 기본값(`volumeMode`) diff로 영구 OutOfSync였음(immutable). **개선 반영**: ApplicationSet `ignoreDifferences`(StatefulSet `/spec/volumeClaimTemplates`) 추가 → **11/11 Synced** 확인(2026-06-25).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. 3단계 — E2E 기능 검증 — ✅ 핵심 통과 (2026-06-25)
|
|
||||||
|
|
||||||
vm-stack `test/` 패턴(port-forward + curl) 적응.
|
|
||||||
|
|
||||||
| # | 항목 | 결과 |
|
|
||||||
|---|------|------|
|
|
||||||
| 1 | 파드 | ✅ **15/15 Running** |
|
|
||||||
| 2 | 메트릭 | ✅ `count(up)`=**9**(acct0)/**36**(multitenant), status=success. vmagent 스크레이프→vminsert 적재 정상 |
|
|
||||||
| 3 | 인증 라우팅 | ✅ (CA 수정 후 재검증) Keycloak `perses-vmauth` 토큰 `vm_access:{...:0}` → vmauth가 **실제 JWT 검증** 후 acct0 라우팅(count=9), 무토큰 401. ※ 초기엔 vmauth CA 미신뢰로 검증 실패→`unauthorized_user` 폴백이 가렸음(아래 발견사항) |
|
|
||||||
| 4 | 로그 | ✅ vlselect `logsql`(AccountID:0) 데이터 존재. otelcol→vlinsert 적재 확인 |
|
|
||||||
| 5 | 멀티테넌시 | ◐ 부분 — acct0/multitenant 라우팅 확인. demo01/demo02(acct1/2)는 워크로드 없어 데이터 없음 → 격리 양성검증만, 음성검증(타 테넌트 차단)은 워크로드 필요 |
|
|
||||||
| 6 | perses | ◐ 로그인(`paasup`, global-admin)✅ + 대시보드 4종·데이터소스(victoriametrics/victorialogs) provisioning 적용✅. 인터랙티브 패널 렌더는 브라우저 로그인 필요(미실시) |
|
|
||||||
| 7 | 알림 | ✅ vmalert 규칙 **8개**(cluster-health) 로드, alertmanager Running. Discord는 **mock**이라 실발송 미검증 |
|
|
||||||
|
|
||||||
**발견사항 (E2E)**
|
|
||||||
- ✅ **`unauthorized_user` 폴백 → 제거 완료(해결)**: 초기엔 무토큰/무효토큰도 acct0 200이었음. vmalert는 vmselect 직결이라 폴백 불필요 → **`unauthorized_user` 제거 반영**. 재검증: 무토큰/무효토큰 **모두 401**, 유효 JWT는 정상(2026-06-25).
|
|
||||||
- perses 데이터소스/시크릿(`perses-provisioning`)은 §3.5에서 누락했다가 E2E 중 적용 → 정식 배포 시 ArgoCD 경로 또는 dip-console로 포함 필요.
|
|
||||||
|
|
||||||
> 🔧 **수동 설정**(E2E 일회성): perses-provisioning apply(`kubectl apply -n monitoring -f .../perses-provisioning.yaml`), 검증 토큰 발급(perses-vmauth client_credentials), port-forward 다수 → §7
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. 4단계 — 정리 (teardown)
|
|
||||||
|
|
||||||
- [ ] ArgoCD Application/ApplicationSet 삭제(또는 prune)
|
|
||||||
- [ ] 비-helm CR(있다면) → helm/Application → `monitoring` ns
|
|
||||||
- [ ] longhorn PV/volume 명시 삭제(Retain)
|
|
||||||
- [ ] Keycloak 목 리소스(perses client·테스트 그룹) 삭제
|
|
||||||
> 🔧 **수동 설정**: 삭제 명령 기록 → §7
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. 수동 설정 목록 (이슈/자동화 backlog)
|
|
||||||
|
|
||||||
> 위 🔧 항목에서 **실제 실행한 명령·스크립트**를 여기에 모은다. 이슈 정리 시 이 표를 그대로 사용하고, 각 항목은 dip-console 자동화 후보다.
|
|
||||||
|
|
||||||
| # | 단계 | 대상 | 상태 | 명령 위치 | dip-console 이관 |
|
|
||||||
|---|------|------|------|-----------|------------------|
|
|
||||||
| 1 | 3.1 | 값 repo 렌더·push | ✅ 실행(2026-06-25) `tenant-catalog@510aa8e` | [§3.1](#31-값values-repo--✅-실행-완료-2026-06-25) | ✅ 예정 |
|
|
||||||
| 2 | 3.2 | Keycloak vm-access scope(+매퍼2) + perses/perses-vmauth client + SA attr(acct 0) | ✅ 실행(2026-06-25) `paasup` realm | §3.2 | ✅ 예정 |
|
|
||||||
| 3 | 3.3 | `monitoring` ns + `alertmanager-notify` + `root-ca-cert`(←cert-manager/root-ca-secret) | ✅ 실행(2026-06-25) | §3.3 | ✅ 예정(Infisical) |
|
|
||||||
| 4 | 3.4 | `vmagent-relabel-configs`(demo01/demo02/platform, 빈 규칙) | ✅ 실행(2026-06-25) | §3.4 | ✅ 예정 |
|
|
||||||
| 5 | 3.5 | `perses-dashboards` ConfigMap apply | ✅ 실행(2026-06-25) | §3.5 | (ArgoCD 경로) |
|
|
||||||
| 6 | 4 | ArgoCD `tenant-catalog` repo secret 등록 + ApplicationSet apply(platform ns) | ✅ 실행(2026-06-25) | §4 | - |
|
|
||||||
| 7 | 6 | teardown | ⬜ 미수행 | §6 | - |
|
|
||||||
|
|
||||||
> 진행 메모(2026-06-25): **0~2단계 완료.** 1단계 mock 값(perses=`perses-mock-secret-changeme`, perses-vmauth=`perses-vmauth-secret-changeme`, alertmanager webhook·relabel placeholder). 2단계: ArgoCD=`platform` ns, `service-catalog`@`d1f7c77`/`tenant-catalog`@`510aa8e`, 11 App Healthy(15/15 파드). 남은 것: 3단계 E2E, 4단계 정리.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. 테스트 결과 요약 (이슈용)
|
|
||||||
|
|
||||||
테스트 완료 후 채운다.
|
|
||||||
|
|
||||||
- **일시 / 수행자**: (기입)
|
|
||||||
- **환경**: (클러스터/ArgoCD/Keycloak)
|
|
||||||
- **일시 / 수행자**: 2026-06-25
|
|
||||||
- **환경**: dev 클러스터(192.168.1.101), ArgoCD=`platform` ns, Keycloak `paasup` realm
|
|
||||||
- **결과**: 0~3단계 통과 + 개선 반영. **11/11 Application Synced + Healthy**, **15/15 파드 Running**, E2E 핵심 항목 PASS(메트릭·로그·JWT 라우팅·알림 규칙), perses 로그인/admin OK
|
|
||||||
- **발견 이슈 / 개선사항 (반영 결과)**:
|
|
||||||
- ✅ **vmcluster/vlogs OutOfSync 해결** — ApplicationSet `ignoreDifferences`(StatefulSet `/spec/volumeClaimTemplates`) 추가 → 11/11 Synced.
|
|
||||||
- ✅ **`unauthorized_user` 제거 완료** — vmauth 미인증 접근 차단(무토큰/무효토큰 401). vmalert는 vmselect 직결.
|
|
||||||
- 🔴→✅ **vmauth가 JWT를 검증 못 하던 문제(중대)** — vmauth가 Keycloak OIDC discovery를 사내 CA 미신뢰로 가져오지 못해(x509) **OIDC verifier 초기화 실패 → 모든 JWT 검증 불가**. `unauthorized_user`가 이를 가려 그동안 acct0 폴백으로만 동작(=JWT 인증 실효 없음). **수정**: vmauth에 `root-ca-cert` 마운트 + `SSL_CERT_FILE=/ca/ca.crt` → OIDC verifier 정상, 유효 JWT 검증 성공·무토큰 401 재확인. (Perses 대시보드 unauthorized도 이 때문이었음)
|
|
||||||
→ **교훈**: Keycloak이 사내 CA면 **vmauth·perses 등 JWT/OIDC 소비자 모두 CA 신뢰 설정 필수**.
|
|
||||||
- ◐ **perses 데이터소스/시크릿** — E2E 중 `perses-provisioning` 수동 apply. 정식 배포 시 ArgoCD 경로(또는 dip-console)로 포함 필요 (남은 backlog).
|
|
||||||
- **Perses OIDC login = `preferred_username`** (v0.53.1 실측) — globalAdminUsers/RoleBinding은 username 기준(앞서 "sub UUID" 가정은 오류, 정정함).
|
|
||||||
- ArgoCD 설치 위치 `platform` ns — ApplicationSet ns를 `platform`으로 조정함.
|
|
||||||
- **자동화 backlog**: §7 수동 설정 목록 참조 (1단계 전부 dip-console 이관 대상)
|
|
||||||
- **미완**: 4단계 정리(teardown), 멀티테넌시 음성검증(테넌트 워크로드 필요), perses 인터랙티브 렌더(브라우저)
|
|
||||||
@@ -261,6 +261,8 @@ flowchart TB
|
|||||||
|
|
||||||
## 12. 배포 아키텍처 (ArgoCD + dip-console)
|
## 12. 배포 아키텍처 (ArgoCD + dip-console)
|
||||||
|
|
||||||
|
> 단계별 **운영 배포 절차**(배포 전/배포 시/배포 후 테넌트 관리)는 [monitoring-deploy-guide.md](monitoring-deploy-guide.md) 참조. 본 장은 배포 모델·책임 분담의 설계 배경(why)을 다룬다.
|
||||||
|
|
||||||
### 12.1 배포 모델
|
### 12.1 배포 모델
|
||||||
|
|
||||||
GitOps 기반. 역할을 4개로 분리한다.
|
GitOps 기반. 역할을 4개로 분리한다.
|
||||||
|
|||||||
Reference in New Issue
Block a user