레이블이 prometheus인 게시물을 표시합니다. 모든 게시물 표시
레이블이 prometheus인 게시물을 표시합니다. 모든 게시물 표시

argo-cd sync errror

# prometheus, grafana 버전업을 위해 다음과 같이 prometheus(operator) Chart.yaml > dependencies 버전업했다.
apiVersion: v2
name: ysoftman-prometheus
version: 0.0.1
description: Chart for ysoftman-prometheus
dependencies:
  - name: "kube-prometheus-stack"
    version: "65.3.2"
    repository: "https://prometheus-community.github.io/helm-charts"
  - name: "prometheus-adapter"
    version: "4.11.0"
    repository: "https://prometheus-community.github.io/helm-charts"

# Chart.lock 새로 생성
helm dependencies build

# 이제 git develop 브랜치에 커밋
# argocd 에서 해당 앱(prometheus operator)이 자동 싱크가 활성화 돼 있어 자동 싱크를 수행하는 중 다음과 같은 에러가 발생했다.

Failed to compare desired state to live state: failed to calculate diff: error calculating structured merge diff: error building typed value from config resource: .spec.scrapeConfigSelector: field not declared in schema

# 해결하기
# argocd 해당 application > detail > sync policy > automated 비활성화 상태에서 수동으로 싱크한다.
# 다시 automated 를 활성화하면 자동싱크시 에러가 발생하지 않는다.

# 버전 확인
http://ysoftman-prometheus.aaa.bbb/ > prometheus_build_info 메트릭으로 조회
http://ysoftman-grafana.aaa.bbb/api/health

# 기타 values spec 변경 사항 확인
Kind: Prometheus > spec
Kind: Alertmanger > spec

prometheus etcd-client-cert

https://prometheus-community.github.io/helm-charts/ 으로 prometheus 설치시
# prometheus pod 가 실행할때 etcd-client-cert secret 을 참조하도록 설정했다.
# values.yaml  
kube-prometheus-stack:
  prometheus:
    prometheusSpec:
      replicas: 2
      secrets:
        - etcd-client-cert

# etcd-client-cert secret 생성
# k8s master 마스터 서버 접속해 아래 위치에서 3개의 파일을 가져온다.
ssh ysoftman@ysoftman-master-1.server
sudo -i
cp -v /etc/kubernetes/pki/etcd/etcd-ca.crt /home/ysoftman/
cp -v /etc/kubernetes/pki/apiserver-etcd-client.crt /home/ysoftman/
cp -v /etc/kubernetes/pki/apiserver-etcd-client.key /home/ysoftamn/
exit; exit;

# 로컬로 3개의 파일을 복사해 온다.
rsync ysoftman@ysoftman-master-1.server:/home/ysoftman/etcd-ca.crt .
rsync ysoftman@ysoftman-master-1.server:/home/ysoftman/apiserver-etcd-client.crt .
rsync ysoftman@ysoftman-master-1.server:/home/ysoftman/apiserver-etcd-client.key .

# 이 파일로 secret 을 생성한다.
kubectl create secret generic etcd-client-cert -n prometheus \
--from-literal=etcd-ca="$(cat etcd-ca.crt)" \
--from-literal=etcd-client="$(cat apiserver-etcd-client.crt)" \
--from-literal=etcd-client-key="$(cat apiserver-etcd-client.key)"

backup grafana dashboard

# 다음과 같이 prometheus 를 설치하면
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install ysoftman-release prometheus-community/kube-prometheus-stack

# grafana 설치하면 기본으로 포함된 dashboard 들이 있다.
# sidecar.dashboards.folder: /tmp/dashboards
# grafana container > /tmp/dashboards 에는 기본 제공되는 dashboard json 파일들이 위치한다.

# 그런데 사용자가 생성한(import)한 경우 /var/lib/grafana/grafana.db 에 추가된다.

# grafana pod 의 grafana.db 를 로컬에 복사
kubectl cp ysoftman-grafana-123:/var/lib/grafana/grafana.db ./grafana.db

# sqlite 로 확인해보자
# 테이블 조회
sqlite3 ./grafana.db '.tables'

# import 했던 dashboard 를 확인할 수 있다.
sqlite3 ./grafana.db 'select * from dashboard' | grep -i 20211010

#####

# grafana in k8s 인 grafana 재시작시 db 파일 삭제로 어려움이 있다.
# 대신 api 를 이용해서 백업해보자.
# api 사용을 위해 서비스 계정 생성 및 토큰 생성한다.
grafana > administration > service accounts > add service account
이후 add service account token (no expiration) > 토큰 복사해두기

# backup / restore grafana dashboard script

prometheus "found duplicate series" error

# pod 기준으로 network 트래픽 쿼리를 다음과 같이 실행하면
avg_over_time(container_network_transmit_bytes_total{pod=~"ysoftman-.*", interface="eth0"}[1w:1m]) + on(pod) group_left avg_over_time(container_network_receive_bytes_total{pod=~"ysoftman-.*", interface="eth0"}[1w:1m])

# 특정 pod series 가 중복되어 하나로 그룹핑 되지 않아 다음과 같은 에러를 발생한다.
Error executing query: found duplicate series for the match group {pod="ysoftman-123"} on the right hand-side of the operation:

# ysoftman-123 pod 의 id 가 다르게 3개가 나와서 문제였다.
# 해당 series 는 데이터는 무의미한것으로 없어도 된다.

# 해결방법1
# prometheus 의 admin api가 활성화(--web.enable-admin-api) 되어 있다면 다음과 같이 삭제할 수 있다.
# 바로 삭제되지는 않고 다음 compaction 시 적용된다.
curl -X POST -g 'http://localhost:8090/api/v1/admin/tsdb/delete_series?match[]=container_network_transmit_bytes_total{pod=~"ysoftman-.*"}[1w]'
# 바로 삭제를 위해선 다음을 api 한번더 호출해 준다. 
curl -X POST -g 'http://localhost:8090/api/v1/admin/tsdb/clean_tombstones'

# 해결방법2
# on(pod, id) 로 pod, id 로 그룹핑되도록 한다.
avg_over_time(container_network_transmit_bytes_total{pod=~"ysoftman-.*", interface="eth0"}[1w:1m]) + on(pod, id) group_left avg_over_time(container_network_receive_bytes_total{pod=~"ysoftman-.*", interface="eth0"}[1w:1m])

kubectl top node error

# 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# node 를 조회하면 다음 에러가 발생한다.(kubectl top pods 는 정상동작)
kubectl top node
error: metrics not available yet

# kube-system > metrics-server deployment 가 제대로 동작하고 있지 않았다.
kubectl get deployment metrics-server -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   0/1     1            0           26h

# 이슈1 - 이미지 다운로드 실패
# 원인은 registry.k8s.io 에 대해서 방화벽 설정으로 이미지를 받아오지 못해서였다.
Pulling image "registry.k8s.io/metrics-server/metrics-server:v0.6.3"

# 우선 로컬에 이미지를 다운로드 받자.
docker pull registry.k8s.io/metrics-server/metrics-server:v0.6.3

# 이미지를 tar 로 만든다.
docker save -o metrics-server-v0.6.3.tar registry.k8s.io/metrics-server/metrics-server:v0.6.3

# 워커 노드에 tar 파일 전송
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker1/home/ysoftman/
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker2/home/ysoftman/
rsync -avz ./metrics-server-v0.6.3.tar ysoftman@worker3/home/ysoftman/

# 노드의 tar 이미지 파일을 로딩한다.
ssh ysoftman@worker1 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"
ssh ysoftman@worker2 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"
ssh ysoftman@worker3 "sudo docker load -i /home/ysoftman/metrics-server-v0.6.3.tar"

# metrics-server deployment 명세에 다음이 설정되어 있기 때문에
# imagePullPolicy: IfNotPresent
# pod 가 running 된다.

# 이슈2 - tls 비활성화
# metrics 로그를 보면 아래와같이 노드(kubelet)의 메트릭 수집시 실패한다고 나온다.
scraper.go:140] "Failed to scrape node" err="Get \"https://10.10.10.100:10250/metrics/resource\": read tcp 10.10.1.10:40752->10.10.10.100:10250: read: connection reset by peer" node="ysoftman-cpu1"

# metrics-server deployment> containers args 에 다음을 추가하면 위 에러는 발행하지 않고 정상 동작(scraping node ... scrap finished)한다.
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls  # 추가옵션
- --v=6 # 추가옵션 (Scraping node "node=xxxx" 노드 수집 성공 메시지 확인용)

# 이슈3 - apiservice 적용 안되는 이슈
# 아직도 error:metrics not available yet 이 발생한다.
# 찾아보니 kubectl 에서 top 커맨드 사용시 발생하는 에러 메시지였다.

# k8s api 로 node 메트릭을 다음과 같이 실행하면 결과가 나온다.
NODE_NAME="ysoftman-cpu1"
kubectl get --raw /api/v1/nodes/$NODE_NAME/proxy/metrics/resource | grep -i -E "node_cpu|node_mem"

# metrics api 에서 pods 응답은 나온다.
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods | jq 

# 하지만 nodes 응답을 보면 items: [] 로 빈값으로 나온다.
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq 

# metrics-server pod log 는 다음과 같이 노드로부터 정보를 받아 저장했다고 나온다.
round_trippers.go:553] GET https://10.10.10.10:10250/metrics/resource 200 OK in 2 millisecond
server.go:139] "Storing metrics"
server.go:144] "Scraping cycle complete"

# metrics-server 를 삭제했는데, k top nodes/pods 에러가 발행하지 않는다.
kubectl delete -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/downl
oad/components.yaml

# top 명령을 받고 있는 별도의 pod 가 있는것으로 의심된다.
# v1beta1.metrics.k8s.io 를 사용하는 api 서비를 조회하면
kubectl get apiservices | grep -i v1beta1.metrics.k8s.io

# 다음과 같이 prometheus-adapter 서비스가 나온다.
v1beta1.metrics.k8s.io     prometheus-adapter/prometheus-adapter

# kubectl top nodes 동작하는 클러스터는 다음과 같다.
v1beta1.metrics.k8s.io     kube-system/metrics-server

# metrics-server (kind:APIService) 부분이 반영이 안되는게 문제였다.
# prometheus-adapter > v1beta1.metrics.k8s.io 를 사용하고 있고, 이를 argo-cd 에서 항상 sync 하고 있어 삭제해도 다시 생성된다.

helm dependencies prometheus alert 비활성화 하기

# Chart.yaml 에서 prometheus helm-charts 를 가져와 사용중이였는데,
# CPUThrottlingHigh 관련 알림이 너무 많아 알람을 비활성화 해보자
dependencies:
  - name: "kube-prometheus-stack"
    version: "45.9.1"
    repository: "https://prometheus-community.github.io/helm-charts"

# 우선 CPUThrottlingHigh 는 다음 템플릿 조건으로 추가할지 판단 한다.

# 그리고 prometheus values.yaml 에 default > disabled: {} 을 확인했다.

# 이제 내가 생성한 Chart values.yaml 에서
# dependencies(sub chart)의 values 를 다음과 형식으로 명시하면 된다.
kube-prometheus-stack:
  defaultRules:
    disabled: 
      CPUThrottlingHigh: true
  # 추가로 prometheus 설정은 다음과 같이 수정할 수 있다.
  prometheus:
    prometheusSpec:
      replicas: 2
      retention: 30d  # 저장기간(디폴트 10d)

Prometheus ServiceMonitor

# 사용자가 만든 api 가 prometheus 데이터 포맷(시계열 데이터...)으로 응답할때
# 이 응답을 주기적으로 prometheus 에서 수집하기 위해 monitoring.coreos.com 의 ServiceMonitor 리소스를 생성한다.

# 사용자 api 서버에 대한 Service 리소스
apiVersion: v1
kind: Service
metadata:
  labels:
    app: ysoftman-server
    release: prometheus-monitor
  name: ysoftman-server
  namespace: ysoftman-server
spec:
  ports:
    - name: metrics
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app: ysoftman-server

---
# ServiceMonitor 리소스 생성
# 위 Service 에 대해 주기적으로 요청해 prometheus 로 수집한다.
# ServiceMonitor 가 정상적으로 등록되면 prometheus에서 메트릭이 수집되고, tagets 에 추가한 api 를 확인할 수 있다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app: prometheus-monitor-ysoftman-exporter
    # prometheus 오브젝트의 다음 값이 'release: prometheus-monitor' 로 되어 있고
    # matchLabels 에 명시해야 이 ServiceMonitor 가 prometheus target 으로 추가된다.
    # kubectl get prometheus -n prometheus-monitor prometheus-monitor -o yaml | yq '.spec.serviceMonitorSelector'
    release: prometheus-monitor
  name: prometheus-monitor-ysoftman-exporter
  namespace: prometheus-monitor
spec:
  namespaceSelector:
    # 모든 namespace 에서 대상(수집,모니터링)할 service 찾는다.
    # any: true
    # namespace 가 ysoftman-server 인곳에서 대상(수집,모니터링)할 service 를 찾는다.
    matchNames:
      - ysoftman-server
  selector:
    matchLabels:
      # 다음 label(key,value)가 명시된 Service 를 선택한다.
      app: ysoftman-server
      release: prometheus-monitor
  endpoints:
      # Service 요청할 path
    - path: /metrics
      # Service port name 명시
      port: metrics

DCGM GPU utilization

# GKE(Goole Kubernetes Engin) k8s 에서 Nvidia GPU utilization 메트릭(prometheus용)을 수집하기 위해
# Data Center GPU Manager(DCGM) exporter(https://github.com/NVIDIA/gpu-monitoring-tools) 를 사용한다.
# prometheus 에서 DCGM_FI_DEV_GPU_UTIL 메트릭으로 조회가 가능한데
# 다음과 같이 pod 값에 실제 gpu 를 사용하는 pod 가 아닌 dcgm-exporter-xxx 로만 수집된다.
DCGM_FI_DEV_GPU_UTIL{Hostname="dcgm-exporter-xxx",UUID="GPU-xxx",device="nvidia1",endpoint="metrics",gpu="1",instance="my-app1",job="dcgm-exporter",modelName="Tesla P40",namespace="monitoring",pod="dcgm-exporter-xxx",service="dcgm-exporter"}

# 참고로 k8s v1.13 부터 /var/lib/kubelet/pod-resources 소켓파일로 pod 이름등의 정보를 제공한다.

# 관련한 이슈가 있었고 dcgm-exporter daemonset 에 아래와 같은 환경변수를 적용하면 된다고 한다.
env:
  - name: "DCGM_EXPORTER_KUBERNETES"
    value: "true"
  - name: "DCGM_EXPORTER_KUBERNETES_GPU_ID_TYPE"
    value: "device-name"

# daemonset 적용 후 dcgm-exporter container 에 하나에 접속해 환경변수를 확인해 보자
root@dcgm-exporter-xxxx:/# printenv | grep DCGM_EXPORTER
DCGM_EXPORTER_KUBERNETES=true
DCGM_EXPORTER_KUBERNETES_GPU_ID_TYPE=device-name

prometheus query

# prometheus query 사용 예시
# 버전 조회
prometheus_build_info

# my_requests 메트릭 모두 조회
my_requests

# my_requests 중 abc label 값이 lemon 인 경우 조회
my_requests{abc="lemon"}

# my_requests 중 abc label 값이 lemon 이 아닌 경우 조회
my_requests{abc!="lemon"}

# my_requests 중 abc label 값이 lemon로 시작하는 경우 조회
# =~ 로 regex match 한다.
my_requests{abc=~"^lemon.*"}

# [1m] : 최근 1분 동안 존재했던 값들 예를 들어 [1,2,5,10]을 취합
# 처음과 끝의 차이로 초당 평균 변화율(rate)을 계산한다.
# 처음과 시작값 외 중간의 값들은 사용되지 않기 때문에
# range vector 를 너무 크게하면 정확한 값이 도출되지 않는다.
# [1d:1h] : 최근 2일 동안 1시간 간격의 값들

# abc=lemon 요청이 1분동안 60번의 요청이 있었다면 rate 로 1tps가 된다.
rate(my_requests{abc="lemon"}[1m])

# tps 같은 변화율이 아닌 실제 카운트 값을 취할때는 increase 를 사용하면 된다.
# abc=lemon 요청이 1분동안 60번의 요청이 있었다면 increase 는 60(개)가 된다.
increase(my_requests{abc="lemon"}[1m])

# rate 로 나오는 n 개의 값을 더한다.
sum(rate(my_requests{abc="lemon"}[1m]))

# rate 로 나오는 n 개의 값 평균을 계산한다.
avg(rate(my_requests{abc="lemon"}[1m]))

# rate 로 나오는 n 개의 값중 최소값
min(rate(my_requests{abc="lemon"}[1m]))

# rate 로 나오는 n 개의 값중 최대값
max(rate(my_requests{abc="lemon"}[1m]))

# 하루 중 1분단위로 rate 합산 결과들 중 최대 값
max_over_time(sum(rate(my_requests{abc="lemon"}[1m]))[1d:1m])

# 하루 중 1분단위로 rate 합산 결과들 중 평균 값
avg_over_time(sum(rate(my_requests{abc="lemon"}[1m]))[1d:1m])

# 하루 중 1분단위로 rate 합산 결과들 중 중간 값
quantile_over_time(0.5, sum(rate(my_requests{abc="lemon"}[1m]))[1d:1m])

# pod,container 별 CPU 사용량 백분율
sum(rate(container_cpu_usage_seconds_total{name!~".*prometheus.*", image!="", container!="POD"}[5m])) by (pod, container) / 
sum(container_spec_cpu_quota{name!~".*prometheus.*", image!="", container!="POD"} / container_spec_cpu_period{name!~".*prometheus.*", image!="", container!="POD"}) by (pod, container) * 100

# worker 노드의 pod 최대 개수 파악
# on(양쪽 메트릭에 존재하는 레이블로 결과들을 구분할 수 있는 레이블)
# group_left (왼쪽 매트릭 레이블 기준으로 병합, 병합 결과에 포함할 레이블 명시할 수 있다.)
# sum (결과) by (node) 결과중 node 레이블 같은 것 까리 합치기
sum(kube_node_status_allocatable{resource="pods", unit="integer"} * on(node) group_left() kube_node_role{role="worker"}) by (node)

# worker 노드의 running pod 개수 파악
sum((kube_pod_info * on(pod, namespace) group_right(node) kube_pod_status_phase{phase="Running"}) * on (node) group_left() kube_node_role{role="worker"}) by (node)

#####

# promethus > alerts 메뉴에 등록된 rule 확인을 할 수 있다.
# 알람은 다음 3가지 상태가 있다.
- inactive: 알람 (rule)조건이 해당하지 않는 경우(정상)
- pending: 조건에 맞아서 발송 대기중, rule 명세의 for 필드에 설정된 기간동안 검사하며 이 기간 동안 조건이 해제되면 inactive, 계속 조건이 맞으면 firing 상태로 변경된다.
- firing: firing 상태가 되면 alert-manager 에게 알람 내용 전송한다.

# 자주 사용되는 prometheus alert 을 모아둔곳(왠만한건 다있음~ㅎ)