NetApp Tech Blog에 갔다가 흥미로운 주제의 글이 보여서 AI 번역(+약간 수정)의 힘을 빌려 읽어보았습니다.
출처: https://community.netapp.com/t5/Tech-ONTAP-Blogs/NetApp-Trident-protect-metrics-and-monitoring/ba-p/463692
NetApp® Trident™ Protect는 NetApp ONTAP 스토리지 시스템과 NetApp Trident Container Storage Interface(CSI) 스토리지 프로비저너가 지원하는 상태 저장 Kubernetes 애플리케이션의 기능과 가용성을 향상시키는 고급 애플리케이션 데이터 관리 기능을 제공합니다. 다양한 완전 관리형 및 자체 관리형 Kubernetes 솔루션(지원되는 Kubernetes 배포판 및 스토리지 백엔드 참조)과 호환되므로 다양한 플랫폼과 리전에서 Kubernetes 서비스를 보호하는 데 최적의 솔루션입니다.
이 블로그 게시물에서는 널리 사용되는 오픈소스 모니터링 및 시각화 프레임워크인 Prometheus와 Grafana를 사용하여 Trident와 Trident Protect가 제공하는 메트릭을 스크래핑하고 시각화하는 방법을 보여드리겠습니다.
필수 조건
이 가이드를 따라가려면 다음 사항이 있는지 확인하세요.
- 최신 버전의 Trident 및 Trident Protect가 설치된 Kubernetes 클러스터와 관련 kubeconfig 파일
- 구성된 스토리지 백엔드, 스토리지 클래스 및 볼륨 스냅샷 클래스가 있는 NetApp ONTAP 스토리지 백엔드 및 Trident
- 백업 및 메타데이터 정보를 저장하기 위한 구성된 개체 스토리지 버킷, 버킷 복제 구성
- kubeconfig를 사용하도록 구성된 kubectl이 있는 워크스테이션
- 워크스테이션에 설치된 Trident protect의 tridentctl-protect CLI
- Kubernetes 클러스터에 대한 관리자 권한
테스트 환경 준비
먼저, 블로그 전체에서 사용한 테스트 환경의 설정을 간략히 살펴보겠습니다.
샘플 애플리케이션
모니터링 테스트를 위한 샘플 애플리케이션으로 Azure NetApp Files(ANF)에 영구 볼륨이 있는 간단한 MinIO 애플리케이션을 사용하겠습니다. MinIO 애플리케이션은 NetApp Trident 25.06.0이 설치 및 구성된 Azure Kubernetes Service(AKS) 클러스터에 배포됩니다.
$ kubectl get all,pvc -n minio NAME READY STATUS RESTARTS AGE pod/minio-67dffb8bbd-5rfpm 1/1 Running 0 14m pod/minio-console-677bd9ddcb-27497 1/1 Running 0 14m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/minio ClusterIP 172.16.61.243 <none> 9000/TCP 14m service/minio-console ClusterIP 172.16.95.239 <none> 9090/TCP 14m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/minio 1/1 1 1 14m deployment.apps/minio-console 1/1 1 1 14m NAME DESIRED CURRENT READY AGE replicaset.apps/minio-67dffb8bbd 1 1 1 14m replicaset.apps/minio-console-677bd9ddcb 1 1 1 14m NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE persistentvolumeclaim/minio Bound pvc-ec50d895-4048-4a51-a651-5439b2a5ba2a 50Gi RWO azure-netapp-files-standard <unset> 14m
Trident Protect 애플리케이션 만들기
Trident protect CLI를 사용하여 minio 네임스페이스를 기반으로 Trident protect 애플리케이션 minio를 만듭니다 .
$ tridentctl-protect create application minio --namespaces minio -n minio Application "minio" created.
스냅샷 minio-snap 과 백업 minio-bkp를 생성합니다 .
$ tridentctl-protect create snapshot minio-snap --app minio --appvault demo -n minio Snapshot "minio-snap" created. $ tridentctl-protect create backup minio-bkp --app minio --appvault demo -n minio Backup "minio-bkp" created.
kube-state-metrics 설치
Trident Protect는 kube-state-metrics(KSM)를 활용하여 리소스 상태 정보를 제공합니다. Kube-state-metrics는 Kubernetes용 오픈소스 애드온으로, Kubernetes API 서버의 요청을 수신하고 다양한 Kubernetes 객체의 상태에 대한 메트릭을 생성합니다.
Prometheus ServiceMonitor CRD 설치
먼저 Helm을 사용하여 Prometheus ServiceMonitor용 사용자 지정 리소스 정의(CRD)를 설치합니다. Prometheus-community helm 저장소를 추가합니다.
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts $ helm repo update
kube-state-metrics 설치 및 구성
이제 Kubernetes API 통신에서 메트릭을 생성하기 위해 kube-state-metrics를 설치하고 구성합니다. Trident Protect와 함께 사용하면 환경 내 Trident Protect 커스텀 리소스의 상태에 대한 유용한 정보를 얻을 수 있습니다.
Trident Protect CR을 모니터링하기 위해 KSM 헬름 차트에 대한 구성 파일을 만들어 보겠습니다.
- 스냅샷
- 백업
- 실행 후크 실행
- AppVaults(나중 단계에서 추가됨)
앞서 만든 스냅샷 CR minio-snap을 자세히 살펴보겠습니다 .
$ k -n minio get snapshot minio-snap -o yaml
apiVersion: protect.trident.netapp.io/v1
kind: Snapshot
metadata:
annotations:
protect.trident.netapp.io/correlationid: 42111244-fdb7-41f1-af39-7b61fdb0c7e1
creationTimestamp: "2025-08-18T15:25:40Z"
...
name: minio-snap
namespace: minio
ownerReferences:
- apiVersion: protect.trident.netapp.io/v1
kind: Application
name: minio
uid: efc8cdd4-8b20-48e0-8944-eeee8aba98f9
resourceVersion: "14328"
uid: c569472c-ae13-4d30-bffd-98acef304abc
spec:
appVaultRef: demo
applicationRef: minio
cleanupSnapshot: false
completionTimeout: 0s
reclaimPolicy: Delete
volumeSnapshotsCreatedTimeout: 0s
volumeSnapshotsReadyToUseTimeout: 0s
status:
appArchivePath: minio_efc8cdd4-8b20-48e0-8944-eeee8aba98f9/snapshots/20250818152540_minio-snap_c569472c-ae13-4d30-bffd-98acef304abc
appVaultRef: demo
completionTimestamp: "2025-08-18T15:25:58Z"
...
postSnapshotExecHooksRunResults: []
preSnapshotExecHooksRunResults: []
state: Completed
volumeSnapshots:
- name: snapshot-c569472c-ae13-4d30-bffd-98acef304abc-pvc-ec50d895-4048-4a51-a651-5439b2a5ba2a
namespace: minio메타데이터 섹션에서는 스냅샷의 name , UID , creationTimestamp를 Prometheus에 공개하고, spec 및 status 필드에서는 appVautlRef , applicationRef , state 메트릭을 공개하려고 합니다 . 해당 KSM 구성 항목은 다음과 같습니다.
resources:
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Snapshot"
version: "v1"
labelsFromPath:
snapshot_uid: [metadata, uid]
snapshot_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: snapshot_info
help: "Exposes details about the Snapshot state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]스냅샷 CR과 동일한 구조를 가진 백업 CR에서 이 KSM 구성 항목을 사용하여 동일한 정보를 수집할 수 있습니다.
resources:
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Backup"
version: "v1"
labelsFromPath:
backup_uid: [metadata, uid]
backup_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: backup_info
help: "Exposes details about the Backup state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]이러한 CR 필드에 액세스하려면 KSM에 모든 네임스페이스의 스냅샷 및 백업 CR에 대한 액세스를 허용하는 해당 RBAC 권한이 있어야 합니다(Trident Protect CR은 애플리케이션 네임스페이스에 생성되므로). 따라서 KSM 구성 파일에 다음 매개변수를 추가합니다.
rbac:
extraRules:
- apiGroups: ["protect.trident.netapp.io"]
resources: ["snapshots", "backups"]
verbs: ["list", "watch"]
# collect metrics from ALL namespaces
namespaces: ""executionHooksRuns에 대한 세부 정보 수집은 스냅샷 및 백업과 동일한 방식으로 진행되므로 여기서는 세부 정보를 표시하지 않습니다. 모든 것을 종합하면 첫 번째 KSM 설정 파일은 다음과 같습니다.
$ cat metrics-config-backup-snapshot-hooks.yaml
extraArgs:
# collect only our metrics, not the defaults ones (deployments etc.)
- --custom-resource-state-only=true
customResourceState:
enabled: true
config:
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Snapshot"
version: "v1"
labelsFromPath:
snapshot_uid: [metadata, uid]
snapshot_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: snapshot_info
help: "Exposes details about the Snapshot state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Backup"
version: "v1"
labelsFromPath:
backup_uid: [metadata, uid]
backup_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: backup_info
help: "Exposes details about the Backup state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Exechooksruns"
version: "v1"
labelsFromPath:
ehr_uid: [metadata, uid]
ehr_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: ehr_info
help: "Exposes details about the Exec Hook state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
stage: ["spec", stage]
action: ["spec", action]
status: [status, state]
rbac:
extraRules:
- apiGroups: ["protect.trident.netapp.io"]
resources: ["snapshots"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["backups"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["exechooksruns"]
verbs: ["list", "watch"]
# collect metrics from ALL namespaces
namespaces: ""
# deploy a ServiceMonitor so the metrics are collected by Prometheus
prometheus:
monitor:
enabled: true
additionalLabels:
release: prometheus이제 Helm을 사용하여 KSM을 설치할 수 있습니다.
$ helm install trident-protect -f ./metrics-config-backup-snapshot-hooks.yaml prometheus-community/kube-state-metrics --version 5.21.0 -n prometheus NAME: trident-protect LAST DEPLOYED: Tue Aug 19 17:54:22 2025 NAMESPACE: prometheus STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: kube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. The exposed metrics can be found here: https://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics The metrics are exported on the HTTP endpoint /metrics on the listening port. In your case, trident-protect-kube-state-metrics.prometheus.svc.cluster.local:8080/metrics They are served either as plaintext or protobuf depending on the Accept header. They are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint.
KSM ServiceMonitor가 prometheus 네임스페이스에 올바르게 배포되었는지 확인합니다.
$ kubectl -n prometheus get smon -l app.kubernetes.io/instance=trident-protect NAME AGE trident-protect-kube-state-metrics 90s $ kubectl get all -n prometheus NAME READY STATUS RESTARTS AGE pod/trident-protect-kube-state-metrics-94d55666c-69j6n 1/1 Running 0 105s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/trident-protect-kube-state-metrics ClusterIP 172.16.88.31 <none> 8080/TCP 105s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/trident-protect-kube-state-metrics 1/1 1 1 105s NAME DESIRED CURRENT READY AGE replicaset.apps/trident-protect-kube-state-metrics-94d55666c 1 1 1 105s
프로메테우스 설치
이제 클러스터에 Prometheus를 설치해 보겠습니다. 설치하기 전에 Prometheus 서버가 Kubernetes API에 액세스할 수 있는지 확인해야 합니다.
RBAC 권한
Prometheus 서버는 대상을 스크래핑하기 위해 Kubernetes API에 액세스해야 합니다. 따라서 이러한 리소스에 대한 액세스를 제공하기 위해 ServiceAccount가 필요하며, ServiceAccount는 생성되어 ClusterRole에 바인딩되어야 합니다. 아래 yaml 파일을 적용하여 ServiceAccount인 prometheus 와 필요한 권한을 가진 ClusterRole 인 prometheus를 생성하고 , 이 ClusterRole을 ServiceAccount에 바인딩합니다.
$ cat ./rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: name: prometheus namespace: prometheus --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus namespace: prometheus rules: - apiGroups: [""] resources: - nodes - nodes/metrics - services - endpoints - pods verbs: ["get", "list", "watch"] - apiGroups: [""] resources: - configmaps verbs: ["get"] - apiGroups: - networking.k8s.io resources: - ingresses verbs: ["get", "list", "watch"] - nonResourceURLs: ["/metrics"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: prometheus namespace: prometheus roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus subjects: - kind: ServiceAccount name: prometheus namespace: prometheus $ kubectl apply -f ./rbac.yaml serviceaccount/prometheus created clusterrole.rbac.authorization.k8s.io/prometheus created clusterrolebinding.rbac.authorization.k8s.io/prometheus created
이제 Prometheus를 설치할 준비가 되었습니다.
Prometheus 배포
Prometheus ServiceAccount를 생성하고 Kubernetes API에 대한 액세스 권한을 부여하면 Prometheus 인스턴스를 배포할 수 있습니다.
설치에는 Prometheus 오퍼레이터를 사용하겠습니다 . Prometheus 네임스페이스에 오퍼레이터를 설치하는 지침을 따르면 몇 분 안에 K8s 클러스터에 오퍼레이터가 설치됩니다.
이 매니페스트는 serviceMonitor, NamespaceSelector, serviceMonitorSelector, podMonitorSelector 필드를 정의하여 포함할 CR을 지정합니다. 이 예에서는 {} 값을 사용하여 모든 기존 CR을 일치시킵니다.
$ cat ./prometheus.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorSelector: {}
resources:
requests:
memory: 400Mi매니페스트를 적용하고 Prometheus 인스턴스가 결국 Running 상태에 도달하고 Prometheus에서 운영하는 서비스가 생성되었는지 확인합니다.
$ kubectl apply -f ./prometheus.yaml prometheus.monitoring.coreos.com/prometheus created $ kubectl get prometheus -n prometheus NAME VERSION DESIRED READY RECONCILED AVAILABLE AGE prometheus 1 True True 42s $ kubectl get services -n prometheus NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE prometheus-operated ClusterIP None <none> 9090/TCP 103s prometheus-operator ClusterIP None <none> 8080/TCP 7m44s trident-protect-kube-state-metrics ClusterIP 172.16.88.31 <none> 8080/TCP 17h $ kubectl get all -n prometheus NAME READY STATUS RESTARTS AGE pod/prometheus-operator-5d697c648f-22lrz 1/1 Running 0 6m21s pod/prometheus-prometheus-0 2/2 Running 0 20s pod/trident-protect-kube-state-metrics-94d55666c-69j6n 1/1 Running 0 17h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/prometheus-operated ClusterIP None <none> 9090/TCP 20s service/prometheus-operator ClusterIP None <none> 8080/TCP 6m21s service/trident-protect-kube-state-metrics ClusterIP 172.16.88.31 <none> 8080/TCP 17h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/prometheus-operator 1/1 1 1 6m21s deployment.apps/trident-protect-kube-state-metrics 1/1 1 1 17h NAME DESIRED CURRENT READY AGE replicaset.apps/prometheus-operator-5d697c648f 1 1 1 6m21s replicaset.apps/trident-protect-kube-state-metrics-94d55666c 1 1 1 17h NAME READY AGE statefulset.apps/prometheus-prometheus 1/1 20s
Prometheus 설치를 빠르게 테스트하기 위해 포트 포워딩을 사용해 보겠습니다.
$ kubectl -n prometheus port-forward svc/prometheus-operated 9090:9090 Forwarding from 127.0.0.1:9090 -> 9090 Forwarding from [::1]:9090 -> 9090
웹 브라우저에서 http://localhost:9090을 입력하면 Prometheus 콘솔을 볼 수 있습니다.
모니터링 도구를 함께 작동하도록 구성
모든 모니터링 도구를 설치했으니 이제 서로 연동되도록 구성해야 합니다. kube-state-metrics를 Prometheus와 통합하려면 Prometheus 설정 파일( prometheus.yaml) 을 편집 하고 kube-state-metrics 서비스 정보를 추가한 후 prometheus-ksm.yaml 로 저장합니다 .
$ cat ./prometheus-ksm.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
podMonitorSelector: {}
resources:
requests:
memory: 400Mi
---
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: trident-protect
data:
prometheus.yaml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'kube-state-metrics'
static_configs:
- targets: ['kube-state-metrics.trident-protect.svc:8080']
$ diff ./prometheus.yaml ./prometheus-ksm.yaml
13a14,27
> ---
> apiVersion: v1
> kind: ConfigMap
> metadata:
> name: prometheus-config
> namespace: trident-protect
> data:
> prometheus.yaml: |
> global:
> scrape_interval: 15s
> scrape_configs:
> - job_name: 'kube-state-metrics'
> static_configs:
> - targets: ['kube-state-metrics.trident-protect.svc:8080']매니페스트를 적용한 후 prometheus-config 구성 맵이 trident-protect 네임스페이스에 생성되었는지 확인합니다.
$ kubectl apply -f ./prometheus-ksm.yaml prometheus.monitoring.coreos.com/prometheus unchanged configmap/prometheus-config created $ kubectl -n trident-protect get cm NAME DATA AGE kube-root-ca.crt 1 46h prometheus-config 1 59s trident-protect-env-config 15 46h
이제 Prometheus에서 백업, 스냅샷 및 실행 후크 실행 정보를 쿼리할 수 있습니다.
이는 Trident Protect에 있는 두 개의 스냅샷과 하나의 백업, 그리고 여섯 개의 실행 후크 실행과 일치합니다.
$ tridentctl-protect get snapshot -A +-----------+---------------------------------------------+-------+----------------+-----------+-------+-------+ | NAMESPACE | NAME | APP | RECLAIM POLICY | STATE | ERROR | AGE | +-----------+---------------------------------------------+-------+----------------+-----------+-------+-------+ | minio | backup-3473b771-caa5-48d2-a9b6-41f4448a049d | minio | Delete | Completed | | 1d22h | | minio | minio-snap | minio | Delete | Completed | | 1d22h | +-----------+---------------------------------------------+-------+----------------+-----------+-------+-------+ $ tridentctl-protect get backup -A +-----------+--------------+-------+----------------+-----------+-------+-------+ | NAMESPACE | NAME | APP | RECLAIM POLICY | STATE | ERROR | AGE | +-----------+--------------+-------+----------------+-----------+-------+-------+ | minio | minio-backup | minio | Retain | Completed | | 1d22h | +-----------+--------------+-------+----------------+-----------+-------+-------+ $ kubectl get ehr -A NAMESPACE NAME STATE STAGE ACTION ERROR APP AGE minio post-backup-3473b771-caa5-48d2-a9b6-41f4448a049d Completed Post Backup minio 46h minio post-snapshot-7e7934a4-b51a-4bc4-a981-28a8ba137ff6 Completed Post Snapshot minio 46h minio post-snapshot-c569472c-ae13-4d30-bffd-98acef304abc Completed Post Snapshot minio 46h minio pre-backup-3473b771-caa5-48d2-a9b6-41f4448a049d Completed Pre Backup minio 46h minio pre-snapshot-7e7934a4-b51a-4bc4-a981-28a8ba137ff6 Completed Pre Snapshot minio 46h minio pre-snapshot-c569472c-ae13-4d30-bffd-98acef304abc Completed Pre Snapshot minio 46h
2번째 백업을 만들어 보겠습니다.
$ tridentctl-protect create backup minio-bkp-2 --app minio --appvault demo --reclaim-policy Delete -n minio Backup "minio-bkp-2" created.
Prometheus는 백업을 빠르게 실행 상태로 전환하고, 백업이 완료되면 완료 상태로 전환합니다.
추가 메트릭 및 정보 추가
이제 Prometheus에 추가 사용자 지정 리소스에 대한 메트릭을 추가하고 모니터링된 사용자 지정 리소스의 오류 상태(있는 경우)가 Prometheus에 반영되는지 확인하고 싶습니다.
AppVault 메트릭 및 오류 세부 정보
AppVault CR과 오류 세부 정보에 대한 메트릭을 포함하려면 아래 항목을 KSM 구성 파일에 추가합니다.
- groupVersionKind:
group: protect.trident.netapp.io
kind: "AppVault"
version: "v1"
labelsFromPath:
appvault_uid: [metadata, uid]
appvault_name: [metadata, name]
metricsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]
metrics:
- name: appvault_info
help: "Exposes details about the AppVault state"
each:
type: Info
info:
labelsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]스냅샷, 백업, execHooksRun 및 appVault CR에서 메트릭과 오류 세부 정보를 포착하기 위한 전체 구성 파일은 다음과 같습니다.
$ cat ./metrics-config-backup-snapshot-hooks-appvault.yaml
extraArgs:
# collect only our metrics, not the defaults ones (deployments etc.)
- --custom-resource-state-only=true
customResourceState:
enabled: true
config:
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Snapshot"
version: "v1"
labelsFromPath:
snapshot_uid: [metadata, uid]
snapshot_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: snapshot_info
help: "Exposes details about the Snapshot state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Backup"
version: "v1"
labelsFromPath:
backup_uid: [metadata, uid]
backup_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: backup_info
help: "Exposes details about the Backup state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Exechooksruns"
version: "v1"
labelsFromPath:
ehr_uid: [metadata, uid]
ehr_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: ehr_info
help: "Exposes details about the Exec Hook state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
stage: ["spec", stage]
action: ["spec", action]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "AppVault"
version: "v1"
labelsFromPath:
appvault_uid: [metadata, uid]
appvault_name: [metadata, name]
metricsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]
metrics:
- name: appvault_info
help: "Exposes details about the AppVault state"
each:
type: Info
info:
labelsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]
rbac:
extraRules:
- apiGroups: ["protect.trident.netapp.io"]
resources: ["snapshots"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["backups"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["exechooksruns"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["appvaults"]
verbs: ["list", "watch"]
# collect metrics from ALL namespaces
namespaces: ""
# deploy a ServiceMonitor so the metrics are collected by Prometheus
prometheus:
monitor:
enabled: true
additionalLabels:
release: prometheusKSM 구성을 업데이트합니다.
$ helm upgrade trident-protect prometheus-community/kube-state-metrics -f ./metrics-config-backup-snapshot-hooks-appvault.yaml -n prometheus Release "trident-protect" has been upgraded. Happy Helming! NAME: trident-protect LAST DEPLOYED: Wed Aug 20 16:47:06 2025 NAMESPACE: prometheus STATUS: deployed REVISION: 2 TEST SUITE: None NOTES: kube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. The exposed metrics can be found here: https://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics The metrics are exported on the HTTP endpoint /metrics on the listening port. In your case, trident-protect-kube-state-metrics.prometheus.svc.cluster.local:8080/metrics They are served either as plaintext or protobuf depending on the Accept header. They are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint.
이제 AppVault CR에 대한 정보를 Prometheus에서 사용할 수 있습니다.
AppVault 테스트 실패
Prometheus의 모니터링 및 오류 인식을 테스트하기 위해 AppVault CR의 실패를 테스트합니다. AppVault CR 뒤에 있는 객체 스토리지 버킷에 대한 접근 권한을 잃는 상황을 시뮬레이션하기 위해, trident-protect 네임스페이스에서 액세스 자격 증명이 포함된 비밀을 삭제합니다.
$ kubectl -n trident-protect delete secret puneptunetest secret "puneptunetest" deleted
몇 초 후, AppVault CR이 오류 상태로 전환됩니다.
$ tridentctl-protect get appvault +------+----------+-------+--------------------------------+---------+-----+ | NAME | PROVIDER | STATE | ERROR | MESSAGE | AGE | +------+----------+-------+--------------------------------+---------+-----+ | demo | Azure | Error | failed to resolve value for | | 2d | | | | | accountKey: unable to ... | | | +------+----------+-------+--------------------------------+---------+-----+
그리고 appVault CR의 오류는 Prometheus에도 반영됩니다.
AppMirrorRelationship 메트릭
Trident Protect를 사용하면 NetApp SnapMirror 기술의 비동기 복제 기능을 사용하여 동일한 클러스터 또는 서로 다른 클러스터 간에 한 스토리지 백엔드에서 다른 스토리지 백엔드로 데이터 및 애플리케이션 변경 사항을 복제할 수 있습니다. AppMirrorRelationship(AMR) CR은 NetApp Snapmirror의 애플리케이션 보호와 Trident Protect의 복제 관계를 제어하므로 Prometheus를 사용하여 상태를 모니터링하는 것이 필수적입니다.
이 예제 구성에는 스냅샷, 백업, execHooksRun, AppVault 및 AMR 메트릭이 포함되어 있습니다.
$ cat ./metrics-config-backup-snapshot-hooks-appvault-amr.yaml
extraArgs:
# collect only our metrics, not the defaults ones (deployments etc.)
- --custom-resource-state-only=true
customResourceState:
enabled: true
config:
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Snapshot"
version: "v1"
labelsFromPath:
snapshot_uid: [metadata, uid]
snapshot_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: snapshot_info
help: "Exposes details about the Snapshot state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Backup"
version: "v1"
labelsFromPath:
backup_uid: [metadata, uid]
backup_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: backup_info
help: "Exposes details about the Backup state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "Exechooksruns"
version: "v1"
labelsFromPath:
ehr_uid: [metadata, uid]
ehr_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: ehr_info
help: "Exposes details about the Exec Hook state"
each:
type: Info
info:
labelsFromPath:
appVaultReference: ["spec", "appVaultRef"]
appReference: ["spec", "applicationRef"]
stage: ["spec", stage]
action: ["spec", action]
status: [status, state]
error: [status, error]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "AppVault"
version: "v1"
labelsFromPath:
appvault_uid: [metadata, uid]
appvault_name: [metadata, name]
metricsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]
metrics:
- name: appvault_info
help: "Exposes details about the AppVault state"
each:
type: Info
info:
labelsFromPath:
state: [status, state]
error: [status, error]
message: [status, message]
- groupVersionKind:
group: protect.trident.netapp.io
kind: "AppMirrorRelationship"
version: "v1"
labelsFromPath:
amr_uid: [metadata, uid]
amr_name: [metadata, name]
creation_time: [metadata, creationTimestamp]
metrics:
- name: app_mirror_relationship_info
help: "Exposes details about the AppMirrorRelationship state"
each:
type: Info
info:
labelsFromPath:
desiredState: ["spec", "desiredState"]
destinationAppVaultRef: ["spec", "destinationAppVaultRef"]
sourceAppVaultRef: ["spec", "sourceAppVaultRef"]
sourceApplicationName: ["spec", "sourceApplicationName"]
sourceApplicationUID: ["spec", "sourceApplicationUID"]
state: ["status", "state"]
error: ["status", "error"]
lastTransferStartTimestamp: ["status", "lastTransfer", "startTimestamp"]
lastTransferCompletionTimestamp: ["status", "lastTransfer", "completionTimestamp"]
lastTransferredSnapshotName: ["status", "lastTransferredSnapshot", "name"]
lastTransferredSnapshotCompletionTimestamp: ["status", "lastTransferredSnapshot", "completionTimestamp"]
destinationApplicationRef: ["status", "destinationApplicationRef"]
destinationNamespaces: ["status", "destinationNamespaces"]
promotedSnapshot: ["spec", "promotedSnapshot"]
recurrenceRule: ["spec", "recurrenceRule"]
storageClassName: ["spec", "storageClassName"]
namespaceMapping: ["spec", "namespaceMapping"]
conditions: ["status", "conditions"]
rbac:
extraRules:
- apiGroups: ["protect.trident.netapp.io"]
resources: ["snapshots"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["backups"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["exechooksruns"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["appvaults"]
verbs: ["list", "watch"]
- apiGroups: ["protect.trident.netapp.io"]
resources: ["appmirrorrelationships"]
verbs: ["list", "watch"]
# collect metrics from ALL namespaces
namespaces: ""
# deploy a ServiceMonitor so the metrics are collected by Prometheus
prometheus:
monitor:
enabled: true
additionalLabels:
release: prometheus트라이던트 메트릭
Trident가 제공하는 측정항목을 사용하면 다음 작업을 수행할 수 있습니다.
- Trident의 상태와 구성을 지속적으로 확인하세요. 작업의 성공 여부와 백엔드와 예상대로 통신하는지 확인할 수 있습니다.
- 백엔드 사용 정보를 검토하고 백엔드에 프로비저닝된 볼륨 수와 사용된 공간의 양 등을 파악합니다.
- 사용 가능한 백엔드에 프로비저닝된 볼륨 수의 매핑을 유지합니다.
- 성능 추적. Trident가 백엔드와 통신하고 작업을 수행하는 데 걸리는 시간을 확인할 수 있습니다.
기본적으로 Trident의 메트릭은 /metrics 엔드포인트 의 대상 포트 8001에 노출됩니다. 이러한 메트릭은 Trident 설치 시 기본적으로 활성화 됩니다.
Trident 메트릭에 대한 Prometheus ServiceMonitor 만들기
Prometheus는 이전 섹션에서 이미 설정되었으므로, Trident 메트릭을 사용하기 위해 trident-csi 서비스를 감시하고 메트릭 포트 에서 수신 대기하는 또 다른 Prometheus ServiceMonitor를 만듭니다 . ServiceMonitor 구성의 예는 다음과 같습니다.
$ cat ./prometheus-trident-sm.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: trident-sm
namespace: prometheus
labels:
release: prom-operator
spec:
jobLabel: trident
selector:
matchLabels:
app: controller.csi.trident.netapp.io
namespaceSelector:
matchNames:
- trident
endpoints:
- port: metrics
interval: 15sprometheus 네임스페이스 에 새로운 ServiceMonitor를 배포해 보겠습니다 .
$ kubectl apply -f Prometheus/prometheus-trident-sm.yaml servicemonitor.monitoring.coreos.com/trident-sm created
이제 새로운 ServiceMonitor trident-sm 이 prometheus 네임스페이스 에서 실행 중인 것을 볼 수 있습니다 .
$ kubectl -n prometheus get all,ServiceMonitor,cm NAME READY STATUS RESTARTS AGE pod/prometheus-operator-5d697c648f-22lrz 1/1 Running 0 6h1m pod/prometheus-prometheus-0 2/2 Running 0 5h55m pod/trident-protect-kube-state-metrics-99476b548-cv9ff 1/1 Running 0 28m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/prometheus-operated ClusterIP None <none> 9090/TCP 5h55m service/prometheus-operator ClusterIP None <none> 8080/TCP 6h1m service/trident-protect-kube-state-metrics ClusterIP 172.16.88.31 <none> 8080/TCP 23h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/prometheus-operator 1/1 1 1 6h1m deployment.apps/trident-protect-kube-state-metrics 1/1 1 1 23h NAME DESIRED CURRENT READY AGE replicaset.apps/prometheus-operator-5d697c648f 1 1 1 6h1m replicaset.apps/trident-protect-kube-state-metrics-94d55666c 0 0 0 23h replicaset.apps/trident-protect-kube-state-metrics-99476b548 1 1 1 28m NAME READY AGE statefulset.apps/prometheus-prometheus 1/1 5h55m NAME AGE servicemonitor.monitoring.coreos.com/trident-protect-kube-state-metrics 23h servicemonitor.monitoring.coreos.com/trident-sm 32s NAME DATA AGE configmap/kube-root-ca.crt 1 24h configmap/prometheus-prometheus-rulefiles-0 0 5h55m configmap/trident-protect-kube-state-metrics-customresourcestate-config 1 23h
Prometheus UI( http://localhost:9090/targets )에서 사용 가능한 대상을 확인하면 이제 Trident 메트릭을 Prometheus에서 사용할 수 있음을 확인할 수 있습니다.
Trident 메트릭 쿼리
이제 Prometheus에서 사용 가능한 Trident 메트릭을 쿼리할 수 있습니다.
예를 들어, Prometheus UI에서 Trident 볼륨에 의해 할당된 Trident 스냅샷, 볼륨 및 바이트 수를 쿼리할 수 있습니다.
Grafana 대시보드
이제 모니터링 시스템이 제대로 작동하므로, 모니터링 결과를 시각화하는 방법을 알려드리겠습니다. Grafana 대시보드를 살펴보겠습니다!
Grafana 설치
Grafana helm 차트를 사용하여 Grafana를 설치하고 먼저 Grafana helm 저장소를 추가합니다.
$ helm repo add grafana https://grafana.github.io/helm-charts
그런 다음 먼저 생성한 네임스페이스 grafana 에 Grafana를 설치할 수 있습니다.
$ kubectl create ns grafana
namespace/grafana created
$ helm install my-grafana grafana/grafana --namespace grafana
NAME: my-grafana
LAST DEPLOYED: Thu Aug 21 14:28:14 2025
NAMESPACE: grafana
STATUS: deployed
REVISION: 1
NOTES:
1. Get your 'admin' user password by running:
kubectl get secret --namespace grafana my-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster:
my-grafana.grafana.svc.cluster.local
Get the Grafana URL to visit by running these commands in the same shell:
export POD_NAME=$(kubectl get pods --namespace grafana -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=my-grafana" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace grafana port-forward $POD_NAME 3000
3. Login with the password from step 1 and the username: admin
#################################################################################
###### WARNING: Persistence is disabled!!! You will lose your data when #####
###### the Grafana pod is terminated. #####
#################################################################################
$ helm list -n grafana
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
my-grafana grafana 1 2025-08-21 14:28:14.772879 +0200 CEST deployed grafana-9.3.2 12.1.0위의 지침에 따라 Grafana 관리자 비밀번호를 검색하고 포트 포워딩을 설정합니다.
$ kubectl get secret --namespace grafana my-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
<REDACTED>
$ kubectl -n grafana port-forward svc/my-grafana 3000:80
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000이제 http://localhost:3000 에서 Grafana UI에 대한 액세스와 로그인을 테스트할 수 있습니다 . 정상적으로 작동합니다.
Grafana에 대한 영구 저장소 활성화
기본적으로 Grafana는 임시 저장소만 사용하며 모든 데이터는 컨테이너의 파일 시스템에 저장됩니다. 따라서 컨테이너가 중지되면 데이터가 손실됩니다. Grafana에서 영구 저장소를 활성화하는 방법 은 Grafana 설명서 의 단계를 따르세요.
값 파일을 다운로드 하고 지속성 섹션에서 값을 편집하여 활성화 플래그를 false에서 true로 변경합니다.
$ diff Grafana/values.yaml Grafana/values-persistence.yaml 418c418 < enabled: false --- > enabled: true
그런 다음 helm upgrade를 실행하여 변경 사항을 적용합니다.
$ helm upgrade my-grafana grafana/grafana -f Grafana/values-persistence.yaml -n grafana
Release "my-grafana" has been upgraded. Happy Helming!
NAME: my-grafana
LAST DEPLOYED: Thu Aug 21 14:37:24 2025
NAMESPACE: grafana
STATUS: deployed
REVISION: 2
NOTES:
1. Get your 'admin' user password by running:
kubectl get secret --namespace grafana my-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster:
my-grafana.grafana.svc.cluster.local
Get the Grafana URL to visit by running these commands in the same shell:
export POD_NAME=$(kubectl get pods --namespace grafana -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=my-grafana" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace grafana port-forward $POD_NAME 3000
Azure NetApp Files에서 지원하는 PVC가 grafana 네임스페이스에 생성되었음을 확인했습니다.
$ kubectl get all,pvc -n grafana NAME READY STATUS RESTARTS AGE pod/my-grafana-6d5b96b7d7-fqq7d 1/1 Running 0 5m18s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-grafana ClusterIP 172.16.9.115 <none> 80/TCP 14m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/my-grafana 1/1 1 1 14m NAME DESIRED CURRENT READY AGE replicaset.apps/my-grafana-6ccff48567 0 0 0 14m replicaset.apps/my-grafana-6d5b96b7d7 1 1 1 5m18s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE persistentvolumeclaim/my-grafana Bound pvc-5a1844c6-3a9f-4f1d-9d94-caa1666ded3e 50Gi RWO azure-netapp-files-standard <unset> 5m19s
포트 포워딩을 다시 시작한 후 Grafana에 다시 로그인하여 영구 저장소를 활성화한 상태로 작업을 계속할 수 있습니다.
데이터 소스 추가
다음으로, Grafana에 Prometheus 인스턴스를 데이터 소스로 추가해야 합니다. 이를 위해 Prometheus의 서비스 이름과 포트가 필요합니다. 일반적으로 Prometheus Operator를 사용할 때 서비스 이름은 prometheus-operated와 비슷하므로 클러스터를 확인합니다.
$ kubectl -n prometheus get svc | grep operated prometheus-operated ClusterIP None <none> 9090/TCP 27h
이제 Grafana에서 Prometheus 인스턴스를 데이터 소스로 추가할 수 있습니다. Kubernetes DNS를 사용하여 Prometheus 서비스를 참조합니다. 다음과 같은 형식이어야 합니다. http://prometheus-operated.prometheus.svc.cluster.local:9090
Grafana 대시보드에서 Menu -> Drilldown으로 이동하면 Trident와 KSM Trident Protect 메트릭을 쉽게 볼 수 있습니다.
Trident Protect 메트릭에 대한 대시보드 추가
Grafana 대시보드 생성에 대한 내용은 이 블로그 게시물의 범위를 벗어납니다. 예시와 영감을 위해, Yves Weisser가 GitHub에서 강력 추천하는 Trident 랩 시나리오 모음집 에서 스냅샷 및 백업 메트릭을 시각화하는 대시보드 예시를 활용합니다 .
GitHub에서 대시보드 JSON 파일을 다운로드한 후 , “실패” 옵션 값을 “오류”로 변경하여 대시보드에서 실패한 스냅샷과 백업을 빨간색으로 표시합니다.
$ diff Grafana/dashboard.json Grafana/dashboard_v2.json
365c365
< "Failed": {
---
> "Error": {
562c562
< "Failed": {
---
> "Error": {
709c709,710
< "25.02"
---
> "25.02",
> "25.06"
724c725
< }
\ No newline at end of file
---
> }이제 대시보드 JSON 파일을 Grafana로 가져올 수 있습니다.
대시보드 JSON 파일을 가져오면 Grafana에서 “Trident Protect Global View” 대시보드를 사용할 수 있습니다. 다음은 실행 중인 Trident Protect 백업과 실패한 Trident Protect 백업을 시각화하는 예시입니다.
결론 및 행동 촉구
이 블로그를 팔로우하시면 Prometheus와 Grafana를 사용하여 NetApp Trident 및 Trident Protect에 대한 모니터링 및 시각화를 성공적으로 설정하셨습니다. 이 설정을 통해 Trident 및 Trident Protect 리소스의 상태와 성능을 지속적으로 모니터링하여 Kubernetes 애플리케이션을 안전하게 보호하고 효율적으로 관리할 수 있습니다.
즐거운 모니터링 되세요!