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:
@@ -112,9 +112,11 @@ def get_user_workspaces(access_token: str) -> list:
|
||||
]
|
||||
```
|
||||
|
||||
플러그인 소스는 `files/mlflow_workspace_detector.py` 로 포함되어 있다.
|
||||
|
||||
```sh
|
||||
kubectl create configmap mlflow-workspace-plugin -n mlflow \
|
||||
--from-file=mlflow_workspace_detector.py=mlflow_workspace_detector.py
|
||||
--from-file=mlflow_workspace_detector.py=manifests/helm/mlflow/1.9.0/files/mlflow_workspace_detector.py
|
||||
```
|
||||
|
||||
---
|
||||
@@ -315,16 +317,21 @@ kubectl create configmap mlflow-hooks-patch -n mlflow \
|
||||
|
||||
---
|
||||
|
||||
### 3.8 Ingress 설정
|
||||
### 3.8 Ingress 설정 (APISIX)
|
||||
|
||||
> Kong → APISIX 마이그레이션(issue #139) 반영. ingress class 는 `apisix` 를 사용하고,
|
||||
> CORS·HTTPS redirect 는 별도 `ApisixPluginConfig`(아래 3.9)로 처리한다.
|
||||
|
||||
```yaml
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "kong"
|
||||
className: "apisix"
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "selfsigned-issuer"
|
||||
cert-manager.io/duration: 8760h
|
||||
cert-manager.io/renew-before: 720h
|
||||
# CORS + http→https 를 ApisixPluginConfig(mlflow-cors)로 연결
|
||||
k8s.apisix.apache.org/plugin-config-name: mlflow-cors
|
||||
hosts:
|
||||
- host: mlflow.example.org
|
||||
paths:
|
||||
@@ -336,7 +343,10 @@ ingress:
|
||||
- mlflow.example.org
|
||||
```
|
||||
|
||||
`mlflow.example.org`를 실제 도메인으로 변경한다.
|
||||
`mlflow.example.org`를 실제 도메인으로 변경한다. TLS 는 표준 Ingress `tls` 필드로 APISIX 가 termination 한다.
|
||||
|
||||
> **mlflow OIDC 는 앱 레벨**(`mlflow-oidc-auth`)에서 처리하므로, ingress 에는 `openid-connect`/`keycloak-authz`
|
||||
> 플러그인을 **추가하지 않는다.** 일반 서비스(jupyter 등)의 Kong→APISIX 전환과 다른 점이다.
|
||||
|
||||
---
|
||||
|
||||
@@ -359,45 +369,49 @@ extraArgs:
|
||||
corsAllowedOrigins: "https://mlflow.example.org,https://other.example.org"
|
||||
```
|
||||
|
||||
#### Kong Ingress CORS 플러그인
|
||||
#### APISIX Ingress CORS + HTTPS redirect (ApisixPluginConfig)
|
||||
|
||||
Kong이 CORS preflight(OPTIONS) 요청을 처리하고 응답 헤더를 보완하도록 KongPlugin을 추가한다.
|
||||
APISIX 가 CORS preflight(OPTIONS) 처리와 http→https redirect 를 수행하도록 `ApisixPluginConfig` 를 생성한다.
|
||||
(Kong 의 `KongPlugin(cors)` + `konghq.com/protocols: https` 조합 대체)
|
||||
|
||||
```sh
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: configuration.konghq.com/v1
|
||||
kind: KongPlugin
|
||||
kubectl apply -f manifests/helm/mlflow/1.9.0/files/mlflow-apisix-cors.yaml
|
||||
```
|
||||
|
||||
`files/mlflow-apisix-cors.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: apisix.apache.org/v2
|
||||
kind: ApisixPluginConfig
|
||||
metadata:
|
||||
name: mlflow-cors
|
||||
namespace: mlflow
|
||||
plugin: cors
|
||||
config:
|
||||
origins:
|
||||
- "https://mlflow.example.org"
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- OPTIONS
|
||||
- PATCH
|
||||
headers:
|
||||
- Accept
|
||||
- Authorization
|
||||
- Content-Type
|
||||
credentials: true
|
||||
max_age: 3600
|
||||
EOF
|
||||
spec:
|
||||
plugins:
|
||||
- name: redirect
|
||||
enable: true
|
||||
config:
|
||||
http_to_https: true
|
||||
- name: cors
|
||||
enable: true
|
||||
config:
|
||||
allow_origins: "https://mlflow.example.org"
|
||||
allow_methods: "GET,POST,PUT,DELETE,OPTIONS,PATCH"
|
||||
allow_headers: "Accept,Authorization,Content-Type"
|
||||
allow_credential: true
|
||||
max_age: 3600
|
||||
```
|
||||
|
||||
Ingress에 플러그인을 연결한다.
|
||||
Ingress 에 plugin-config 를 연결한다 (3.8 참조).
|
||||
|
||||
```yaml
|
||||
ingress:
|
||||
annotations:
|
||||
konghq.com/plugins: mlflow-cors
|
||||
k8s.apisix.apache.org/plugin-config-name: mlflow-cors
|
||||
```
|
||||
|
||||
> `allow_credential: true` 일 때 `allow_origins` 는 `*` 를 쓸 수 없으므로 명시적 origin 을 지정한다.
|
||||
|
||||
#### 동작 검증
|
||||
|
||||
```sh
|
||||
@@ -447,7 +461,21 @@ extraEnvVars:
|
||||
|
||||
---
|
||||
|
||||
### 3.11 S3 (MinIO) 설정
|
||||
### 3.11 S3 (rustfs) 설정
|
||||
|
||||
아티팩트 저장소로 클러스터의 rustfs(S3 호환)를 사용한다. 사전에 `mlflow` 버킷을 생성한다.
|
||||
|
||||
```sh
|
||||
# rustfs 자격증명 확인
|
||||
kubectl get secret rustfs-secret -n rustfs \
|
||||
-o jsonpath='{.data.RUSTFS_ACCESS_KEY}' | base64 -d; echo
|
||||
kubectl get secret rustfs-secret -n rustfs \
|
||||
-o jsonpath='{.data.RUSTFS_SECRET_KEY}' | base64 -d; echo
|
||||
|
||||
# mlflow 버킷 생성 (mc 사용 예시)
|
||||
mc alias set rfs http://rustfs-svc.rustfs.svc.cluster.local:9000 <ACCESS_KEY> <SECRET_KEY>
|
||||
mc mb -p rfs/mlflow
|
||||
```
|
||||
|
||||
```yaml
|
||||
artifactRoot:
|
||||
@@ -457,15 +485,15 @@ artifactRoot:
|
||||
enabled: true
|
||||
bucket: mlflow
|
||||
path: artifacts
|
||||
awsAccessKeyId: "adminuser" # MinIO access key
|
||||
awsSecretAccessKey: "adminuser" # MinIO secret key
|
||||
awsAccessKeyId: "adminuser" # rustfs access key
|
||||
awsSecretAccessKey: "adminuser" # rustfs secret key
|
||||
|
||||
extraEnvVars:
|
||||
MLFLOW_S3_ENDPOINT_URL: "http://minio.minio.svc.cluster.local:9000"
|
||||
MLFLOW_S3_ENDPOINT_URL: "http://rustfs-svc.rustfs.svc.cluster.local:9000"
|
||||
MLFLOW_S3_IGNORE_TLS: "true"
|
||||
```
|
||||
|
||||
외부 MinIO 사용 시 `MLFLOW_S3_ENDPOINT_URL`을 해당 엔드포인트로 변경한다.
|
||||
외부 S3/MinIO 사용 시 `MLFLOW_S3_ENDPOINT_URL` 과 자격증명을 해당 엔드포인트로 변경한다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ artifactRoot:
|
||||
|
||||
extraEnvVars:
|
||||
# --- 기본 설정 ---
|
||||
MLFLOW_S3_ENDPOINT_URL: "http://minio.minio.svc.cluster.local:9000"
|
||||
MLFLOW_S3_ENDPOINT_URL: "http://rustfs-svc.rustfs.svc.cluster.local:9000"
|
||||
MLFLOW_S3_IGNORE_TLS: "true"
|
||||
SSL_CERT_FILE: "/etc/ssl/certs/custom-ca.crt"
|
||||
|
||||
@@ -91,12 +91,17 @@ service:
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "kong"
|
||||
className: "apisix"
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "selfsigned-issuer"
|
||||
# root-ca-issuer 사용: selfsigned-issuer 는 subject 가 빈 자체서명 인증서를 발급하여
|
||||
# APISIX ingress controller 가 SSL 오브젝트로 동기화하지 않는다(TLS handshake 실패).
|
||||
# 클러스터의 다른 ingress 와 동일하게 CA 서명 issuer 를 사용한다.
|
||||
cert-manager.io/cluster-issuer: "root-ca-issuer"
|
||||
cert-manager.io/duration: 8760h
|
||||
cert-manager.io/renew-before: 720h
|
||||
konghq.com/plugins: mlflow-cors
|
||||
# APISIX: http→https redirect 를 ApisixPluginConfig 로 처리 (files/mlflow-apisix-redirect.yaml)
|
||||
# CORS 는 mlflow 앱 네이티브(extraArgs.corsAllowedOrigins)로 처리
|
||||
k8s.apisix.apache.org/plugin-config-name: https-redirect
|
||||
hosts:
|
||||
- host: mlflow.example.org
|
||||
paths:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# APISIX http→https redirect 플러그인 (클러스터의 다른 네임스페이스와 동일한 https-redirect 관례).
|
||||
# Ingress 의 annotation `k8s.apisix.apache.org/plugin-config-name: https-redirect` 가 이 리소스를 참조한다.
|
||||
#
|
||||
# CORS 는 mlflow 앱 네이티브 설정(extraArgs.corsAllowedOrigins)으로 처리하므로
|
||||
# ingress 레벨 cors 플러그인은 사용하지 않는다.
|
||||
#
|
||||
# 주의: mlflow-oidc-auth 는 *앱 레벨* 에서 OIDC 인증을 처리하므로
|
||||
# ingress 에 openid-connect / keycloak-authz 플러그인을 추가하지 않는다.
|
||||
apiVersion: apisix.apache.org/v2
|
||||
kind: ApisixPluginConfig
|
||||
metadata:
|
||||
name: https-redirect
|
||||
namespace: mlflow
|
||||
spec:
|
||||
plugins:
|
||||
- name: redirect
|
||||
enable: true
|
||||
config:
|
||||
http_to_https: true
|
||||
@@ -0,0 +1,23 @@
|
||||
import base64
|
||||
import json
|
||||
|
||||
|
||||
def get_user_workspaces(access_token: str) -> list:
|
||||
"""
|
||||
JWT access_token의 groups 클레임에서 mlflow-team-* 그룹을 읽어
|
||||
workspace 이름 목록을 반환한다.
|
||||
|
||||
예: ["mlflow-team-ds", "mlflow"] → ["team-ds"]
|
||||
"""
|
||||
try:
|
||||
payload = access_token.split(".")[1]
|
||||
payload += "=" * (4 - len(payload) % 4)
|
||||
claims = json.loads(base64.b64decode(payload))
|
||||
except Exception:
|
||||
return []
|
||||
groups = claims.get("groups", [])
|
||||
return [
|
||||
g[len("mlflow-"):]
|
||||
for g in groups
|
||||
if g.startswith("mlflow-team-")
|
||||
]
|
||||
Reference in New Issue
Block a user