Kubernetes에 Grafana 배포

Kubernetes에 Grafana 배포 (Deploy Grafana on Kubernetes)

이 페이지는 Kubernetes 매니페스트를 사용해 Kubernetes에 Grafana를 설치하고 실행하는 지침을 제공해요. Helm을 선호한다면 Grafana Helm 커뮤니티 차트를 참고하세요.

출처: 문서

본문

시작하기 전에

  • 공개 또는 비공개 클라우드에서 로컬 또는 원격으로 실행되는 최신 버전의 Kubernetes.
  • 로컬 환경에서는 minikube, kind, Docker Desktop 등 다양한 옵션 사용 가능.
  • 프로덕션에서는 Google Kubernetes Engine(GKE), Amazon Elastic Kubernetes Service(EKS), Azure Kubernetes Service(AKS) 같은 관리형 클라우드 서비스 권장.

시스템 요구 사항

최소 하드웨어: 디스크 1GB, 메모리 750MiB(약 750MB), CPU 250m(약 0.25코어).

지원 데이터베이스와 지원 웹 브라우저는 해당 문서를 참고하세요.

Note: Grafana 기본 포트인 3000번을 네트워크 환경에서 활성화하세요.

Kubernetes에 Grafana OSS 배포

Kubernetes에 애플리케이션을 배포하면 기본 네임스페이스를 사용하는데, 여기엔 이미 다른 애플리케이션이 실행 중일 수 있어 충돌이 발생할 수 있어요. 클러스터 리소스를 더 잘 관리·구성하려면 새 네임스페이스를 만드는 것이 권장돼요.

  1. 네임스페이스를 만들어요:
kubectl create namespace my-grafana
  1. 네임스페이스 생성을 확인해요:
kubectl get namespace my-grafana
  1. grafana.yaml이라는 YAML 매니페스트 파일을 만들어요:
touch grafana.yaml

이 파일에 세 가지 객체를 정의해요: | Object | Description | | --- | --- | | Persistent Volume Claim (PVC) | 데이터를 저장하는 객체. | | Service | 배포의 Pod에 네트워크 접근을 제공하는 객체. | | Deployment | Pod를 만들고 최신 상태를 유지하며 Replicaset·Rolling update를 관리하는 객체. |

  1. 다음 내용을 복사해 grafana.yaml에 저장해요:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: grafana
  name: grafana
spec:
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      securityContext:
        fsGroup: 472
        supplementalGroups:
          - 0
      containers:
        - name: grafana
          image: grafana/grafana:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3000
              name: http-grafana
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /robots.txt
              port: 3000
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 30
            successThreshold: 1
            timeoutSeconds: 2
          livenessProbe:
            failureThreshold: 3
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 3000
            timeoutSeconds: 1
          resources:
            requests:
              cpu: 250m
              memory: 750Mi
          volumeMounts:
            - mountPath: /var/lib/grafana
              name: grafana-pv
      volumes:
        - name: grafana-pv
          persistentVolumeClaim:
            claimName: grafana-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
spec:
  ports:
    - port: 3000
      protocol: TCP
      targetPort: http-grafana
  selector:
    app: grafana
  sessionAffinity: None
  type: LoadBalancer
  1. 매니페스트를 Kubernetes API 서버로 전송해요:
kubectl apply -f grafana.yaml --namespace=my-grafana
  1. 각 객체의 배포 상태를 확인해요:
kubectl get pvc --namespace=my-grafana -o wide
kubectl get deployments --namespace=my-grafana -o wide
kubectl get svc --namespace=my-grafana -o wide

관리형 K8s 공급자에서 Grafana 접근

  1. 배포 정보를 얻으려면:
kubectl get all --namespace=my-grafana
  1. 출력에서 EXTERNAL-IP 값을 확인해 브라우저에 입력해요. Grafana 로그인 화면이 나타나요.
  2. username과 password 모두 admin을 입력해 로그인해요.
  3. EXTERNAL-IP가 보이지 않으면 포트 포워딩을 해요:
kubectl port-forward service/grafana 3000:3000 --namespace=my-grafana

그리고 브라우저에서 localhost:3000으로 이동해요.

minikube로 Grafana 접근

옵션 1: 서비스 노출 — grafana.yaml 서비스 매니페스트의 type: LoadBalancer를 사용:

minikube service grafana --namespace=my-grafana

반환된 URL로 브라우저에서 Grafana UI에 접근하고 admin/admin으로 로그인해요.

옵션 2: 포트 포워딩:

minikube ip
kubectl get pods --namespace=my-grafana
kubectl port-forward pod/grafana-58445b6986-dxrrw --namespace=my-grafana --address 0.0.0.0 3000:3000

minikube IP와 포워딩된 포트(예: 192.168.122.144:3000)로 접근해요.

롤링 업데이트 전략으로 기존 배포 업데이트

롤링 업데이트는 새 Pod를 점진적으로 교체해 다운타임 없이 배포 업데이트를 수행해요.

  1. 롤아웃 상태 보기:
kubectl rollout history deployment/grafana --namespace=my-grafana
  1. 처음 배포 기록용 메타데이터 추가:
kubectl annotate deployment/grafana kubernetes.io/change-cause='deployed the default base yaml file' --namespace=my-grafana

Grafana 이미지 버전 변경

kubectl edit deployment grafana --namespace=my-grafana

kind: Deployment 섹션에서 컨테이너 이미지를 변경하고(예: grafana/grafana:12.1.0grafana/grafana-dev:12.2.0-17161637292) 저장해요. 성공 여부는 kubectl rollout status deployment grafana --namespace=my-grafana로 확인해요.

배포 롤백

배포가 크래시 루프·버그 등으로 불안정해지면 이전 버전(REVISION)으로 롤백할 수 있어요.

kubectl rollout history deployment grafana --namespace=my-grafana
kubectl rollout undo deployment grafana --to-revision=1 --namespace=my-grafana

구성 파일로 Grafana 리소스 프로비저닝

프로비저닝은 Grafana 시작 시 구성 파일에 지정된 리소스를 추가·업데이트·삭제할 수 있어요. 여기서는 영구 볼륨으로 구성 파일을 Grafana pod에 공급하는 방법을 안내해요.

  1. grafana.yaml에 새 PersistentVolumeClaim을 추가해요:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana-provisioning-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Mi
  1. grafana.yaml에서 영구 볼륨을 /etc/grafana/provisioning에 마운트해요.
  2. 프로비저닝할 리소스를 만들거나 찾아요. 예를 들어 mute timing(알림 리소스)을 추가하는 alerting.yaml 파일:
apiVersion: 1
muteTimes:
  - orgId: 1
    name: MuteWeekends
    time_intervals:
      - weekdays: [saturday, sunday]
  1. 알림 리소스 구성 파일은 기본적으로 provisioning/alerting 디렉터리에 배치해야 해요. alerting 디렉터리(alerting.yaml 포함)를 Grafana pod의 /etc/grafana/provisioning/에 복사해요:
kubectl exec -n my-grafana <pod_name> -- ls /etc/grafana/provisioning/
kubectl cp alerting my-grafana/<pod_name>:/etc/grafana/provisioning/

같은 과정으로 provisioning/dashboards, provisioning/datasources, provisioning/plugins 폴더를 공급할 수 있어요. 5. 리소스를 프로비저닝하려면 Grafana pod를 재시작해요:

kubectl rollout restart -n my-grafana deployment --selector=app=grafana

문제 해결

로그 수집:

kubectl logs --namespace=my-grafana deploy/grafana

로그 레벨을 debug 모드로 증가:

  1. grafana.ini 파일을 만들고 다음을 추가해요:
[log]
level = debug
  1. ConfigMap 객체로 클러스터에 추가해요:
kubectl create configmap ge-config --from-file=/path/to/file/grafana.ini --namespace=my-grafana
  1. grafana.yaml의 Deployment 섹션에서 커스텀 구성(/etc/grafana)에 마운트 경로를 제공하고 새 ConfigMap을 참조해요:
kubectl apply -f grafana.yaml --namespace=my-grafana
  1. Server Admin > Settings에서 수준이 debug 모드인지 확인해요.

--dry-run 명령 사용: grafana.yaml에 변경(새 이미지 버전, 새 라벨 등)을 가할 때 문법 오류나 충돌이 있는지 확인하기 위해 dry-run을 수행할 수 있어요:

kubectl apply -f grafana.yaml --dry-run=server --namespace=grafana

Grafana 제거

kubectl delete -f grafana.yaml --namespace=my-grafana
kubectl delete configmap ge-config --namespace=my-grafana

Kubernetes에 Grafana Enterprise 배포

Grafana Enterprise 배포 절차는 라이선스 파일 추가에 필요한 추가 단계를 제외하면 앞선 과정과 거의 동일해요.

Grafana Enterprise 라이선스 획득

Grafana Enterprise를 실행하려면 유효한 라이선스가 필요해요. 라이선스를 얻으려면 Grafana Labs 담당자에게 문의하세요. 이 문서는 license.jwt 파일에 유효한 라이선스가 있다고 가정해요.

라이선스 시크릿 생성

kubectl create secret generic ge-license --from-file=/path/to/your/license.jwt

Grafana Enterprise 구성 생성

  1. grafana.ini 구성 파일을 만들고 다음 YAML을 붙여넣어요:
[enterprise]
license_path = /etc/grafana/license/license.jwt
[server]
root_url =/your/license/root/url
  1. root_url을 받은 라이선스와 연결된 URL로 업데이트해요.

Grafana Enterprise 구성 Configmap 생성

kubectl create configmap ge-config --from-file=/path/to/your/grafana.ini

Grafana Enterprise Kubernetes 매니페스트 생성

grafana.yaml에 Grafana 설치용 YAML과 동일하지만, Grafana 구성 파일을 담은 ConfigMap과 라이선스가 있는 시크릿에 대한 참조가 추가된 내용을 붙여넣어요. 이미지는 grafana/grafana-enterprise:latest를 사용하고, /etc/grafana에 ge-config를, /etc/grafana/license에 ge-license를 마운트해요:

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: grafana
  name: grafana
spec:
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      securityContext:
        fsGroup: 472
        supplementalGroups:
          - 0
      containers:
        - image: grafana/grafana-enterprise:latest
          imagePullPolicy: IfNotPresent
          name: grafana
          ports:
            - containerPort: 3000
              name: http-grafana
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /robots.txt
              port: 3000
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 30
            successThreshold: 1
            timeoutSeconds: 2
          resources:
            limits:
              memory: 4Gi
            requests:
              cpu: 100m
              memory: 2Gi
          volumeMounts:
            - mountPath: /var/lib/grafana
              name: grafana-pv
            - mountPath: /etc/grafana
              name: ge-config
            - mountPath: /etc/grafana/license
              name: ge-license
      volumes:
        - name: grafana-pv
          persistentVolumeClaim:
            claimName: grafana-pvc
        - name: ge-config
          configMap:
            name: ge-config
        - name: ge-license
          secret:
            secretName: ge-license
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
spec:
  ports:
    - port: 3000
      protocol: TCP
      targetPort: http-grafana
  selector:
    app: grafana
  sessionAffinity: None
  type: LoadBalancer

Caution: Service에 LoadBalancer를 쓰면 클라우드 플랫폼과 네트워크 구성에 따라 Grafana 인스턴스가 인터넷에 노출될 수 있어요. 이 위험을 없애려면 ClusterIP를 사용해 Grafana가 배포된 클러스터 내에서만 접근을 제한하세요.

매니페스트를 전송하고 확인:

kubectl apply -f grafana.yaml
kubectl port-forward service/grafana 3000:3000

localhost:3000에서 로그인 페이지를 확인하고 admin/admin으로 로그인해요. 페이지 하단에 Enterprise (Licensed)가 보이면 Enterprise 라이선스로 실행 중인 것이에요.

더 알아보기 (Learn more)