使用Operator部署Prometheus監控k8s集群


一、什么是Operator

Operator是由CoreOS開發的,用來擴展Kubernetes API,特定的應用程序控制器,它用來創建、配置和管理復雜的有狀態應用,如數據庫、緩存和監控系統。Operator基於Kubernetes的資源和控制器概念之上構建,但同時又包含了應用程序特定的領域知識。創建Operator的關鍵是CRD(自定義資源)的設計。

Operator是將運維人員對軟件操作的知識給代碼化,同時利用 Kubernetes 強大的抽象來管理大規模的軟件應用。目前CoreOS官方提供了幾種Operator的實現,其中就包括我們今天的主角:Prometheus OperatorOperator的核心實現就是基於 Kubernetes 的以下兩個概念:

  • 資源:對象的狀態定義
  • 控制器:觀測、分析和行動,以調節資源的分布

當前CoreOS提供的以下四種Operator:

  • etcd:創建etcd集群
  • Rook:雲原生環境下的文件、塊、對象存儲服務
  • Prometheus:創建Prometheus監控實例
  • Tectonic:部署Kubernetes集群

接下來我們將使用Operator創建Prometheus。

二、安裝

我們這里直接通過 Prometheus-Operator 的源碼來進行安裝,當然也可以用 Helm 來進行一鍵安裝,我們采用源碼安裝可以去了解更多的實現細節。首頁將源碼 Clone 下來:

git clone https://github.com/coreos/prometheus-operator     ### 0.30.0版本之前
git clone https://github.com/coreos/kube-prometheus         ### 0.30.0版本之后

目前我使用的k8s版本為1.14.2,所以選擇0.30.0之前的版本,請根據自己k8s版本信息選擇github上的版本進行下載

進入到 manifests 目錄下面,這個目錄下面包含我們所有的資源清單文件,直接在該文件夾下面執行創建資源命令即可:

如果沒有網絡,需要提前下載鏡像,並推到私有倉庫,需要下載以下鏡像:

quay.io/coreos/prometheus-config-reloader:v0.34.0
quay.io/coreos/prometheus-operator:v0.34.0
quay.io/coreos/kube-state-metrics:v1.8.0
quay.io/prometheus/prometheus:v2.11.0
quay.io/prometheus/alertmanager:v0.18.0
quay.io/prometheus/node-exporter:v0.18.1
quay.io/coreos/k8s-prometheus-adapter-amd64:v0.5.0
quay.io/coreos/kube-rbac-proxy:v0.4.1
quay.io/coreos/configmap-reload:v0.0.1
grafana/grafana:6.4.3

PS:需要根據版本拉取鏡像

修改完鏡像后即可繼續執行:

cd prometheus-operator/contrib/kube-prometheus/manifests
kubectl apply -f setup/ kubectl apply
-f .

部署完成后,會創建一個名為monitoring的 namespace,所以資源對象對將部署在改命名空間下面,此外 Operator 會自動創建4個 CRD 資源對象:

 kubectl get crd |grep coreos
alertmanagers.monitoring.coreos.com           2019-03-18T02:43:57Z
prometheuses.monitoring.coreos.com            2019-03-18T02:43:58Z
prometheusrules.monitoring.coreos.com         2019-03-18T02:43:58Z
servicemonitors.monitoring.coreos.com         2019-03-18T02:43:58Z

可以在 monitoring 命名空間下面查看所有的 Pod,其中 alertmanager 和 prometheus 是用 StatefulSet 控制器管理的,其中還有一個比較核心的 prometheus-operator 的 Pod,用來控制其他資源對象和監聽對象變化的:

復制代碼
kubectl get pods -n monitoring
NAME                                   READY     STATUS    RESTARTS   AGE
alertmanager-main-0                    2/2       Running   0          37m
alertmanager-main-1                    2/2       Running   0          34m
alertmanager-main-2                    2/2       Running   0          33m
grafana-7489c49998-pkl8w               1/1       Running   0          40m
kube-state-metrics-d6cf6c7b5-7dwpg     4/4       Running   0          27m
node-exporter-dlp25                    2/2       Running   0          40m
node-exporter-fghlp                    2/2       Running   0          40m
node-exporter-mxwdm                    2/2       Running   0          40m
node-exporter-r9v92                    2/2       Running   0          40m
prometheus-adapter-84cd9c96c9-n92n4    1/1       Running   0          40m
prometheus-k8s-0                       3/3       Running   1          37m
prometheus-k8s-1                       3/3       Running   1          37m
prometheus-operator-7b74946bd6-vmbcj   1/1       Running   0          40m
復制代碼

查看創建的 Service:

復制代碼
kubectl get svc -n monitoring
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
alertmanager-main       ClusterIP   10.110.43.207   <none>        9093/TCP            40m
alertmanager-operated   ClusterIP   None            <none>        9093/TCP,6783/TCP   38m
grafana                 ClusterIP   10.109.160.0    <none>        3000/TCP            40m
kube-state-metrics      ClusterIP   None            <none>        8443/TCP,9443/TCP   40m
node-exporter           ClusterIP   None            <none>        9100/TCP            40m
prometheus-adapter      ClusterIP   10.105.174.21   <none>        443/TCP             40m
prometheus-k8s          ClusterIP   10.97.195.143   <none>        9090/TCP            40m
prometheus-operated     ClusterIP   None            <none>        9090/TCP            38m
prometheus-operator     ClusterIP   None            <none>        8080/TCP            40m
復制代碼

可以看到上面針對 grafana 和 prometheus 都創建了一個類型為 ClusterIP 的 Service,當然如果我們想要在外網訪問這兩個服務的話可以通過創建對應的 Ingress 對象或者使用 NodePort 類型的 Service,我們這里為了簡單,直接使用 NodePort 類型的服務即可,編輯 grafana 和 prometheus-k8s 這兩個 Service,將服務類型更改為 NodePort:

復制代碼
kubectl edit svc grafana -n monitoring
kubectl edit svc prometheus-k8s -n monitoring
kubectl get svc -n monitoring
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
.....
grafana                 NodePort    10.109.160.0    <none>        3000:31740/TCP      42m
prometheus-k8s          NodePort    10.97.195.143   <none>        9090:31310/TCP      42m
復制代碼

更改完成后,我們就可以通過去訪問上面的兩個服務了,比如查看 prometheus 的 targets 頁面:

我們可以看到大部分的配置都是正常的,只有兩三個沒有管理到對應的監控目標,比如 kube-controller-manager 和 kube-scheduler 這兩個系統組件,這就和 ServiceMonitor 的定義有關系了,我們先來查看下 kube-scheduler 組件對應的 ServiceMonitor 資源的定義:(prometheus-serviceMonitorKubeScheduler.yaml)

配置kube-scheduler

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: kube-scheduler
  name: kube-scheduler
  namespace: monitoring
spec:
  endpoints:
  - interval: 30s  #30s獲取一次信息
    port: http-metrics  # 對應service的端口名
  jobLabel: k8s-app  
  namespaceSelector:  # 表示去匹配某一命名空間中的service,如果想從所有的namespace中匹配用any: true
    matchNames:
    - kube-system
  selector:    # 匹配的 Service 的labels,如果使用mathLabels,則下面的所有標簽都匹配時才會匹配該service,如果使用matchExpressions,則至少匹配一個標簽的service都會被選擇
    matchLabels:
      k8s-app: kube-scheduler
復制代碼

上面是一個典型的 ServiceMonitor 資源文件的聲明方式,上面我們通過selector.matchLabels在 kube-system 這個命名空間下面匹配具有k8s-app=kube-scheduler這樣的 Service,但是我們系統中根本就沒有對應的 Service,所以我們需要手動創建一個 Service:(prometheus-kubeSchedulerService.yaml)

復制代碼
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-scheduler
  labels:
    k8s-app: kube-scheduler
spec:
  selector:
    component: kube-scheduler
  ports:
  - name: http-metrics
    port: 10251
    targetPort: 10251
    protocol: TCP
復制代碼

其中最重要的是上面 labels 和 selector 部分,labels 區域的配置必須和我們上面的 ServiceMonitor 對象中的 selector 保持一致,selector下面配置的是component=kube-scheduler,為什么會是這個 label 標簽呢,我們可以去 describe 下 kube-scheduelr 這個 Pod:

復制代碼
$ kubectl describe pod kube-scheduler-k8s-master -n kube-system
Name:               kube-scheduler-k8s-master
Namespace:          kube-system
Priority:           2000000000
PriorityClassName:  system-cluster-critical
Node:               k8s-master/172.16.138.40
Start Time:         Tue, 19 Feb 2019 21:15:05 -0500
Labels:             component=kube-scheduler
                    tier=control-plane
......
復制代碼

我們可以看到這個 Pod 具有component=kube-schedulertier=control-plane這兩個標簽,而前面這個標簽具有更唯一的特性,所以使用前面這個標簽較好,這樣上面創建的 Service 就可以和我們的 Pod 進行關聯了,直接創建即可:

$ kubectl create -f prometheus-kubeSchedulerService.yaml
$ kubectl get svc -n kube-system -l k8s-app=kube-scheduler
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
kube-scheduler   ClusterIP   10.103.165.58   <none>        10251/TCP   4m

創建完成后,隔一小會兒后去 prometheus 查看 targets 下面 kube-scheduler 的狀態:

我們可以看到現在已經發現了 target,但是抓取數據結果出錯了,這個錯誤是因為我們集群是使用 kubeadm 搭建的,其中 kube-scheduler 默認是綁定在127.0.0.1上面的,而上面我們這個地方是想通過節點的 IP 去訪問,所以訪問被拒絕了,我們只要把 kube-scheduler 綁定的地址更改成0.0.0.0即可滿足要求,由於 kube-scheduler 是以靜態 Pod 的形式運行在集群中的,所以我們只需要更改靜態 Pod 目錄下面對應的 YAML (kube-scheduler.yaml)文件即可:

復制代碼
$ cd /etc/kubernetes/manifests
將 kube-scheduler.yaml 文件中-command的--address地址更改成0.0.0.0
$ vim kube-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: kube-scheduler
    tier: control-plane
  name: kube-scheduler
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-scheduler
    - --address=0.0.0.0
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true
....
復制代碼

修改完成后我們將該文件從當前文件夾中移除,隔一會兒再移回該目錄,就可以自動更新了,然后再去看 prometheus 中 kube-scheduler 這個 target 是否已經正常了:

配置kube-controller-manager

我們來查看一下kube-controller-manager的ServiceMonitor資源的定義:

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: kube-controller-manager
  name: kube-controller-manager
  namespace: monitoring
spec:
  endpoints:
  - interval: 30s
    metricRelabelings:
    - action: drop
      regex: etcd_(debugging|disk|request|server).*
      sourceLabels:
      - __name__
    port: http-metrics
  jobLabel: k8s-app
  namespaceSelector:
    matchNames:
    - kube-system
  selector:
    matchLabels:
      k8s-app: kube-controller-manager
復制代碼

上面我們可以看到是通過k8s-app: kube-controller-manager這個標簽選擇的service,但系統中沒有這個service。這里我們手動創建一個:

創建前我們需要看確定pod的標簽:

復制代碼
$ kubectl describe pod kube-controller-manager-k8s-master -n kube-system
Name:               kube-controller-manager-k8s-master
Namespace:          kube-system
Priority:           2000000000
PriorityClassName:  system-cluster-critical
Node:               k8s-master/172.16.138.40
Start Time:         Tue, 19 Feb 2019 21:15:16 -0500
Labels:             component=kube-controller-manager
                    tier=control-plane
....
復制代碼

創建svc

復制代碼
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-controller-manager
  labels:
    k8s-app: kube-controller-manager
spec:
  selector:
    component: kube-controller-manager
  ports:
  - name: http-metrics
    port: 10252
    targetPort: 10252
    protocol: TCP
復制代碼

創建完后,我們查看targer

這里和上面是同一個問題。讓我們使用上面的方法修改。讓我們修改kube-controller-manager.yaml:

復制代碼
apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: kube-controller-manager
    tier: control-plane
  name: kube-controller-manager
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-controller-manager
    - --node-monitor-grace-period=10s
    - --pod-eviction-timeout=10s
    - --address=0.0.0.0   #修改
......
復制代碼

修改完成后我們將該文件從當前文件夾中移除,隔一會兒再移回該目錄,就可以自動更新了,然后再去看 prometheus 中 kube-controller-manager 這個 target 是否已經正常了:

 

 配置coredns

coredns啟動的metrics端口是9153,我們查看kube-system下的svc是否有這個端口:

 

復制代碼
kubectl get svc -n kube-system
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
heapster                             ClusterIP   10.96.28.220     <none>        80/TCP          19d
kube-controller-manager              ClusterIP   10.99.208.51     <none>        10252/TCP       1h
kube-dns                             ClusterIP   10.96.0.10       <none>        53/UDP,53/TCP   188d
kube-scheduler                       ClusterIP   10.103.165.58    <none>        10251/TCP       2h
kubelet                              ClusterIP   None             <none>        10250/TCP       5h
kubernetes-dashboard                 NodePort    10.103.15.27     <none>        443:30589/TCP   131d
monitoring-influxdb                  ClusterIP   10.103.155.57    <none>        8086/TCP        19d
tiller-deploy                        ClusterIP   10.104.114.83    <none>        44134/TCP       18d
復制代碼

 

這里我們看到kube-dns沒有metrics的端口,但是metrics后端是啟動,所以我們需要把這個端口通過svc暴露出來。創建svc:

復制代碼
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: kube-prometheus-prometheus-coredns
  labels:
    k8s-app: prometheus-operator-coredns
spec:
  selector:
    k8s-app: kube-dns
  ports:
  - name: metrics
    port: 9153
    targetPort: 9153
    protocol: TCP
復制代碼

這里我們啟動一個svc,labels是 k8s-app: prometheus-operator-coredns ,所有我們需要修改DNS的serviceMonitor下的labels值。

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    k8s-app: coredns
  name: coredns
  namespace: monitoring
spec:
  endpoints:
  - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
    interval: 15s
    port: metrics
  jobLabel: k8s-app
  namespaceSelector:
    matchNames:
    - kube-system
  selector:
    matchLabels:
      k8s-app: prometheus-operator-coredns
復制代碼

 

創建查看這兩個資源:

$ kubectl apply  -f prometheus-serviceMonitorCoreDNS.yaml
$ kubectl create -f prometheus-KubeDnsSvc.yaml
$ kubectl get svc -n kube-system
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
kube-prometheus-prometheus-coredns   ClusterIP   10.100.205.135   <none>        9153/TCP        1h

讓我們再去看 prometheus 中 coredns 這個 target 是否已經正常了:

 

 上面的監控數據配置完成后,現在我們可以去查看下 grafana 下面的 dashboard,同樣使用上面的 NodePort 訪問即可,第一次登錄使用 admin:admin 登錄即可,進入首頁后,可以發現已經和我們的 Prometheus 數據源關聯上了,正常來說可以看到一些監控圖表了:

 

 自定義監控項

除了 Kubernetes 集群中的一些資源對象、節點以及組件需要監控,有的時候我們可能還需要根據實際的業務需求去添加自定義的監控項,添加一個自定義監控的步驟也是非常簡單的。

  • 第一步建立一個 ServiceMonitor 對象,用於 Prometheus 添加監控項
  • 第二步為 ServiceMonitor 對象關聯 metrics 數據接口的一個 Service 對象
  • 第三步確保 Service 對象可以正確獲取到 metrics 數據

接下來演示如何添加 etcd 集群的監控。

無論是 Kubernetes 集群外的還是使用 Kubeadm 安裝在集群內部的 etcd 集群,我們這里都將其視作集群外的獨立集群,因為對於二者的使用方法沒什么特殊之處。

etcd 證書

對於 etcd 集群一般情況下,為了安全都會開啟 https 證書認證的方式,所以要想讓 Prometheus 訪問到 etcd 集群的監控數據,就需要提供相應的證書校驗。

由於我們這里演示環境使用的是 Kubeadm 搭建的集群,我們可以使用 kubectl 工具去獲取 etcd 啟動的時候使用的證書路徑:

復制代碼
$ kubectl get pods -n kube-system | grep etcd
etcd-k8s-master                         1/1       Running   2773       188d
etcd-k8s-node01                         1/1       Running   2          104d
$ kubectl get pod etcd-k8s-master -n kube-system -o yaml
.....
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://172.16.138.40:2379
    - --initial-advertise-peer-urls=https://172.16.138.40:2380
    - --initial-cluster=k8s-master=https://172.16.138.40:2380
    - --listen-client-urls=https://127.0.0.1:2379,https://172.16.138.40:2379
    - --listen-peer-urls=https://172.16.138.40:2380
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/etcd
    - --key-file=/etc/kubernetes/pki/etcd/server.key
    - --name=k8s-master
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/etcd-amd64:3.2.18
    imagePullPolicy: IfNotPresent
    livenessProbe:
      exec:
        command:
        - /bin/sh
        - -ec
        - ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt
          --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key
          get foo
      failureThreshold: 8
      initialDelaySeconds: 15
      periodSeconds: 10
      successThreshold: 1
      timeoutSeconds: 15
    name: etcd
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/lib/etcd
      name: etcd-data
    - mountPath: /etc/kubernetes/pki/etcd
      name: etcd-certs
......
  tolerations:
  - effect: NoExecute
    operator: Exists
  volumes:
  - hostPath:
      path: /var/lib/etcd
      type: DirectoryOrCreate
    name: etcd-data
  - hostPath:
      path: /etc/kubernetes/pki/etcd
      type: DirectoryOrCreate
    name: etcd-certs
.....
復制代碼

我們可以看到 etcd 使用的證書都對應在節點的 /etc/kubernetes/pki/etcd 這個路徑下面,所以首先我們將需要使用到的證書通過 secret 對象保存到集群中去:(在 etcd 運行的節點)

$ kubectl -n monitoring create secret generic etcd-certs --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.crt --from-file=/etc/kubernetes/pki/etcd/healthcheck-client.key --from-file=/etc/kubernetes/pki/etcd/ca.crt
secret/etcd-certs created

然后將上面創建的 etcd-certs 對象配置到 prometheus 資源對象中,直接更新 prometheus 資源對象即可:

nodeSelector:
  beta.kubernetes.io/os: linux
replicas: 2
secrets:
- etcd-certs

更新完成后,我們就可以在 Prometheus 的 Pod 中獲取到上面創建的 etcd 證書文件了,具體的路徑我們可以進入 Pod 中查看:

復制代碼
$ kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring
Defaulting container name to prometheus.
Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod.
/prometheus $ ls /etc/prometheus/
config_out/         console_libraries/  consoles/           prometheus.yml      rules/              secrets/
/prometheus $ ls /etc/prometheus/secrets/etcd-certs/
ca.crt                  healthcheck-client.crt  healthcheck-client.key
/prometheus $
復制代碼

創建 ServiceMonitor

現在 Prometheus 訪問 etcd 集群的證書已經准備好了,接下來創建 ServiceMonitor 對象即可(prometheus-serviceMonitorEtcd.yaml)

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: etcd-k8s
  namespace: monitoring
  labels:
    k8s-app: etcd-k8s
spec:
  jobLabel: k8s-app
  endpoints:
  - port: port
    interval: 30s
    scheme: https
    tlsConfig:
      caFile: /etc/prometheus/secrets/etcd-certs/ca.crt
      certFile: /etc/prometheus/secrets/etcd-certs/healthcheck-client.crt
      keyFile: /etc/prometheus/secrets/etcd-certs/healthcheck-client.key
      insecureSkipVerify: true
  selector:
    matchLabels:
      k8s-app: etcd
  namespaceSelector:
    matchNames:
    - kube-system
復制代碼

上面我們在 monitoring 命名空間下面創建了名為 etcd-k8s 的 ServiceMonitor 對象,基本屬性和前面章節中的一致,匹配 kube-system 這個命名空間下面的具有 k8s-app=etcd 這個 label 標簽的 Service,jobLabel 表示用於檢索 job 任務名稱的標簽,和前面不太一樣的地方是 endpoints 屬性的寫法,配置上訪問 etcd 的相關證書,endpoints 屬性下面可以配置很多抓取的參數,比如 relabel、proxyUrl,tlsConfig 表示用於配置抓取監控數據端點的 tls 認證,由於證書 serverName 和 etcd 中簽發的可能不匹配,所以加上了 insecureSkipVerify=true

直接創建這個 ServiceMonitor 對象:

$ kubectl create -f prometheus-serviceMonitorEtcd.yaml
servicemonitor.monitoring.coreos.com/etcd-k8s created

創建 Service

ServiceMonitor 創建完成了,但是現在還沒有關聯的對應的 Service 對象,所以需要我們去手動創建一個 Service 對象(prometheus-etcdService.yaml):

復制代碼
apiVersion: v1
kind: Service
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
spec:
  type: ClusterIP
  clusterIP: None
  ports:
  - name: port
    port: 2379
    protocol: TCP

---
apiVersion: v1
kind: Endpoints
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
subsets:
- addresses:
  - ip: 172.16.138.40
    nodeName: etcd-k8s-master
  - ip: 172.16.138.41
    nodeName: etcd-k8s-node01
  ports:
  - name: port
    port: 2379
    protocol: TCP
復制代碼

我們這里創建的 Service 沒有采用前面通過 label 標簽的形式去匹配 Pod 的做法,因為前面我們說過很多時候我們創建的 etcd 集群是獨立於集群之外的,這種情況下面我們就需要自定義一個 Endpoints,要注意 metadata 區域的內容要和 Service 保持一致,Service 的 clusterIP 設置為 None,對改知識點不太熟悉的,可以去查看我們前面關於 Service 部分的講解。

Endpoints 的 subsets 中填寫 etcd 集群的地址即可,我們這里是創建的是高可用測試集群,我們創建的時候指定了node的主機IP地址(2個etcd也是不符合規范的。因為etcd是選舉制,2個就等於一個是一樣的。),直接創建該 Service 資源:

$ kubectl create -f prometheus-etcdService.yaml
service/etcd-k8s created
endpoints/etcd-k8s created

創建完成后,隔一會兒去 Prometheus 的 Dashboard 中查看 targets,便會有 etcd 的監控項了:

數據采集到后,可以在 grafana 中導入編號為3070的 dashboard,獲取到 etcd 的監控圖表。

配置 PrometheusRule

現在我們知道怎么自定義一個 ServiceMonitor 對象了,但是如果需要自定義一個報警規則的話呢?比如現在我們去查看 Prometheus Dashboard 的 Alert 頁面下面就已經有一些報警規則了,還有一些是已經觸發規則的了:

但是這些報警信息是哪里來的呢?他們應該用怎樣的方式通知我們呢?我們知道之前我們使用自定義的方式可以在 Prometheus 的配置文件之中指定 AlertManager 實例和 報警的 rules 文件,現在我們通過 Operator 部署的呢?我們可以在 Prometheus Dashboard 的 Config 頁面下面查看關於 AlertManager 的配置:

復制代碼
alerting:
  alert_relabel_configs:
  - separator: ;
    regex: prometheus_replica
    replacement: $1
    action: labeldrop
  alertmanagers:
  - kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
        - monitoring
    scheme: http
    path_prefix: /
    timeout: 10s
    relabel_configs:
    - source_labels: [__meta_kubernetes_service_name]
      separator: ;
      regex: alertmanager-main
      replacement: $1
      action: keep
    - source_labels: [__meta_kubernetes_endpoint_port_name]
      separator: ;
      regex: web
      replacement: $1
      action: keep
rule_files:
- /etc/prometheus/rules/prometheus-k8s-rulefiles-0/*.yaml
復制代碼

上面 alertmanagers 實例的配置我們可以看到是通過角色為 endpoints 的 kubernetes 的服務發現機制獲取的,匹配的是服務名為 alertmanager-main,端口名未 web 的 Service 服務,我們查看下 alertmanager-main 這個 Service:

復制代碼
kubectl describe svc alertmanager-main -n monitoring
Name:              alertmanager-main
Namespace:         monitoring
Labels:            alertmanager=main
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"alertmanager":"main"},"name":"alertmanager-main","namespace":"monitoring"},...
Selector:          alertmanager=main,app=alertmanager
Type:              ClusterIP
IP:                10.110.43.207
Port:              web  9093/TCP
TargetPort:        web/TCP
Endpoints:         10.244.0.31:9093,10.244.2.42:9093,10.244.3.40:9093
Session Affinity:  None
Events:            <none>
復制代碼

可以看到服務名正是 alertmanager-main,Port 定義的名稱也是 web,符合上面的規則,所以 Prometheus 和 AlertManager 組件就正確關聯上了。而對應的報警規則文件位於:/etc/prometheus/rules/prometheus-k8s-rulefiles-0/目錄下面所有的 YAML 文件。我們可以進入 Prometheus 的 Pod 中驗證下該目錄下面是否有 YAML 文件:

復制代碼
$ kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring
Defaulting container name to prometheus.
Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod.
/prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/
monitoring-prometheus-k8s-rules.yaml
/prometheus $ cat /etc/prometheus/rules/prometheus-k8s-rulefiles-0/monitoring-prometheus-k8s-rules.yaml
groups:
- name: k8s.rules
  rules:
  - expr: |
      sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)
    record: namespace:container_cpu_usage_seconds_total:sum_rate
  - expr: |
      sum by (namespace, pod_name, container_name) (
        rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])
      )
    record: namespace_pod_name_container_name:container_cpu_usage_seconds_total:sum_rate
...........
復制代碼

這個 YAML 文件實際上就是我們之前創建的一個 PrometheusRule 文件包含的:

復制代碼
$ cat prometheus-rules.yaml 
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: k8s
    role: alert-rules
  name: prometheus-k8s-rules
  namespace: monitoring
spec:
  groups:
  - name: k8s.rules
    rules:
    - expr: |
        sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)
      record: namespace:container_cpu_usage_seconds_total:sum_rate
    - expr: |
        sum by (namespace, pod_name, container_name) (
          rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])
        )
      record: namespace_pod_name_container_name:container_cpu_usage_seconds_total:sum_rate
.....
復制代碼

我們這里的 PrometheusRule 的 name 為 prometheus-k8s-rules,namespace 為 monitoring,我們可以猜想到我們創建一個 PrometheusRule 資源對象后,會自動在上面的 prometheus-k8s-rulefiles-0 目錄下面生成一個對應的<namespace>-<name>.yaml文件,所以如果以后我們需要自定義一個報警選項的話,只需要定義一個 PrometheusRule 資源對象即可。至於為什么 Prometheus 能夠識別這個 PrometheusRule 資源對象呢?這就需要查看我們創建的 prometheus 這個資源對象了,里面有非常重要的一個屬性 ruleSelector,用來匹配 rule 規則的過濾器,要求匹配具有 prometheus=k8s 和 role=alert-rules 標簽的 PrometheusRule 資源對象,現在明白了吧?

ruleSelector:
  matchLabels:
    prometheus: k8s
    role: alert-rules

所以我們要想自定義一個報警規則,只需要創建一個具有 prometheus=k8s 和 role=alert-rules 標簽的 PrometheusRule 對象就行了,比如現在我們添加一個 etcd 是否可用的報警,我們知道 etcd 整個集群有一半以上的節點可用的話集群就是可用的,所以我們判斷如果不可用的 etcd 數量超過了一半那么就觸發報警,創建文件 prometheus-etcdRules.yaml:

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    prometheus: k8s
    role: alert-rules
  name: etcd-rules
  namespace: monitoring
spec:
  groups:
  - name: etcd
    rules:
    - alert: EtcdClusterUnavailable
      annotations:
        summary: etcd cluster small
        description: If one more etcd peer goes down the cluster will be unavailable
      expr: |
        count(up{job="etcd"} == 0) > (count(up{job="etcd"}) / 2 - 1)
      for: 3m
      labels:
        severity: critical
.....
$ kubectl create -f  prometheus-etcdRules.yam
復制代碼

注意 label 標簽一定至少要有 prometheus=k8s 和 role=alert-rules,創建完成后,隔一會兒再去容器中查看下 rules 文件夾:

$ kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoring
Defaulting container name to prometheus.
Use 'kubectl describe pod/prometheus-k8s-0 -n monitoring' to see all of the containers in this pod.
/prometheus $ ls /etc/prometheus/rules/prometheus-k8s-rulefiles-0/
monitoring-etcd-rules.yaml            monitoring-prometheus-k8s-rules.yaml

可以看到我們創建的 rule 文件已經被注入到了對應的 rulefiles 文件夾下面了,證明我們上面的設想是正確的。然后再去 Prometheus Dashboard 的 Alert 頁面下面就可以查看到上面我們新建的報警規則了:

 配置報警

我們知道了如何去添加一個報警規則配置項,但是這些報警信息用怎樣的方式去發送呢?前面的課程中我們知道我們可以通過 AlertManager 的配置文件去配置各種報警接收器,現在我們是通過 Operator 提供的 alertmanager 資源對象創建的組件,應該怎樣去修改配置呢?

首先我們將 alertmanager-main 這個 Service 改為 NodePort 類型的 Service,修改完成后我們可以在頁面上的 status 路徑下面查看 AlertManager 的配置信息:

復制代碼
$ kubectl edit svc alertmanager-main -n monitoring
......
  selector:
    alertmanager: main
    app: alertmanager
  sessionAffinity: None
  type: NodePort
.....
復制代碼

 這些配置信息實際上是來自於我們之前在prometheus-operator/contrib/kube-prometheus/manifests目錄下面創建的 alertmanager-secret.yaml 文件:

復制代碼
apiVersion: v1
data:
  alertmanager.yaml: Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg==
kind: Secret
metadata:
  name: alertmanager-main
  namespace: monitoring
type: Opaque
復制代碼

可以將 alertmanager.yaml 對應的 value 值做一個 base64 解碼:

echo Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg== | base64 -d
復制代碼
解碼出來的結果
"global":
  "resolve_timeout": "5m"
"receivers":
- "name": "null"
"route":
  "group_by":
  - "job"
  "group_interval": "5m"
  "group_wait": "30s"
  "receiver": "null"
  "repeat_interval": "12h"
  "routes":
  - "match":
      "alertname": "DeadMansSwitch"
    "receiver": "null"
復制代碼

我們可以看到內容和上面查看的配置信息是一致的,所以如果我們想要添加自己的接收器,或者模板消息,我們就可以更改這個文件:

復制代碼
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.qq.com:587'
  smtp_from: 'zhaikun1992@qq.com'
  smtp_auth_username: 'zhaikun1992@qq.com'
  smtp_auth_password: '***'
  smtp_hello: 'qq.com'
  smtp_require_tls: true
templates:
  - "/etc/alertmanager-tmpl/wechat.tmpl"
route:
  group_by: ['job', 'severity']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 5m
  receiver: default
  routes:
  - receiver: 'wechat'
    group_wait: 10s
    match:
      alertname: CoreDNSDown
receivers:
- name: 'default'
  email_configs:
  - to: 'zhai_kun@suixingpay.com'
    send_resolved: true
- name: 'wechat'
  wechat_configs:
  - corp_id: '***'
    to_party: '*'
    to_user: "**"
    agent_id: '***'
    api_secret: '***'
    send_resolved: true
復制代碼

將上面文件保存為 alertmanager.yaml,然后使用這個文件創建一個 Secret 對象:

#刪除原secret對象
kubectl delete secret alertmanager-main -n monitoring
secret "alertmanager-main" deleted
#將自己的配置文件導入到新的secret
kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoring

我們添加了兩個接收器,默認的通過郵箱進行發送,對於 CoreDNSDown 這個報警我們通過 wechat 來進行發送,上面的步驟創建完成后,很快我們就會收到一條釘釘消息:

同樣郵箱中也會收到報警信息:

我們再次查看 AlertManager 頁面的 status 頁面的配置信息可以看到已經變成上面我們的配置信息了:

AlertManager 配置也可以使用模板(.tmpl文件),這些模板可以與 alertmanager.yaml 配置文件一起添加到 Secret 對象中,比如:

復制代碼
apiVersion:v1
kind:secret
metadata:
   name:alertmanager-example
data:
  alertmanager.yaml:{BASE64_CONFIG}
  template_1.tmpl:{BASE64_TEMPLATE_1}
  template_2.tmpl:{BASE64_TEMPLATE_2}
  ...
復制代碼

模板會被放置到與配置文件相同的路徑,當然要使用這些模板文件,還需要在 alertmanager.yaml 配置文件中指定:

templates:
- '*.tmpl'

創建成功后,Secret 對象將會掛載到 AlertManager 對象創建的 AlertManager Pod 中去。

樣例:我們創建一個alertmanager-tmpl.yaml文件,添加如下內容:

復制代碼
{{ define "wechat.default.message" }}
{{ range .Alerts }}
========start==========
告警程序: prometheus_alert
告警級別: {{ .Labels.severity }}
告警類型: {{ .Labels.alertname }}
故障主機: {{ .Labels.instance }}
告警主題: {{ .Annotations.summary }}
告警詳情: {{ .Annotations.description }}
觸發時間: {{ .StartsAt.Format "2013-12-02 15:04:05" }}
========end==========
{{ end }}
{{ end }}
復制代碼

刪除原secret對象

$ kubectl delete secret alertmanager-main -n monitoring
secret "alertmanager-main" deleted

創建新的secret對象

$ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml --from-file=alertmanager-tmpl.yaml -n monitoring
secret/alertmanager-main created

 過一會我們的微信就會收到告警信息。當然這里標簽定義的問題,獲取的值不全,我們可以根據實際情況自定義。

自動發現配置

我們想一個問題,如果在我們的 Kubernetes 集群中有了很多的 Service/Pod,那么我們都需要一個一個的去建立一個對應的 ServiceMonitor 對象來進行監控嗎?這樣豈不是又變得麻煩起來了?

為解決這個問題,Prometheus Operator 為我們提供了一個額外的抓取配置的來解決這個問題,我們可以通過添加額外的配置來進行服務發現進行自動監控。和前面自定義的方式一樣,我們想要在 Prometheus Operator 當中去自動發現並監控具有prometheus.io/scrape=true這個 annotations 的 Service,之前我們定義的 Prometheus 的配置如下:

復制代碼
- job_name: 'kubernetes-service-endpoints'
  kubernetes_sd_configs:
  - role: endpoints
  relabel_configs:
  - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
    action: keep
    regex: true
  - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
    action: replace
    target_label: __scheme__
    regex: (https?)
  - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
    action: replace
    target_label: __metrics_path__
    regex: (.+)
  - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
    action: replace
    target_label: __address__
    regex: ([^:]+)(?::\d+)?;(\d+)
    replacement: $1:$2
  - action: labelmap
    regex: __meta_kubernetes_service_label_(.+)
  - source_labels: [__meta_kubernetes_namespace]
    action: replace
    target_label: kubernetes_namespace
  - source_labels: [__meta_kubernetes_service_name]
    action: replace
    target_label: kubernetes_name
復制代碼

要想自動發現集群中的 Service,就需要我們在 Service 的annotation區域添加prometheus.io/scrape=true的聲明,將上面文件直接保存為 prometheus-additional.yaml,然后通過這個文件創建一個對應的 Secret 對象:

$ kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml -n monitoring
secret/additional-configs created

創建完成后,會將上面配置信息進行 base64 編碼后作為 prometheus-additional.yaml 這個 key 對應的值存在:

復制代碼
$ kubectl get secret additional-configs -n monitoring -o yaml
apiVersion: v1
data:
  prometheus-additional.yaml: LSBqb2JfbmFtZTogJ2t1YmVybmV0ZXMtc2VydmljZS1lbmRwb2ludHMnCiAga3ViZXJuZXRlc19zZF9jb25maWdzOgogIC0gcm9sZTogZW5kcG9pbnRzCiAgcmVsYWJlbF9jb25maWdzOgogIC0gc291cmNlX2xhYmVsczogW19fbWV0YV9rdWJlcm5ldGVzX3NlcnZpY2VfYW5ub3RhdGlvbl9wcm9tZXRoZXVzX2lvX3NjcmFwZV0KICAgIGFjdGlvbjoga2VlcAogICAgcmVnZXg6IHRydWUKICAtIHNvdXJjZV9sYWJlbHM6IFtfX21ldGFfa3ViZXJuZXRlc19zZXJ2aWNlX2Fubm90YXRpb25fcHJvbWV0aGV1c19pb19zY2hlbWVdCiAgICBhY3Rpb246IHJlcGxhY2UKICAgIHRhcmdldF9sYWJlbDogX19zY2hlbWVfXwogICAgcmVnZXg6IChodHRwcz8pCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9hbm5vdGF0aW9uX3Byb21ldGhldXNfaW9fcGF0aF0KICAgIGFjdGlvbjogcmVwbGFjZQogICAgdGFyZ2V0X2xhYmVsOiBfX21ldHJpY3NfcGF0aF9fCiAgICByZWdleDogKC4rKQogIC0gc291cmNlX2xhYmVsczogW19fYWRkcmVzc19fLCBfX21ldGFfa3ViZXJuZXRlc19zZXJ2aWNlX2Fubm90YXRpb25fcHJvbWV0aGV1c19pb19wb3J0XQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IF9fYWRkcmVzc19fCiAgICByZWdleDogKFteOl0rKSg/OjpcZCspPzsoXGQrKQogICAgcmVwbGFjZW1lbnQ6ICQxOiQyCiAgLSBhY3Rpb246IGxhYmVsbWFwCiAgICByZWdleDogX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9sYWJlbF8oLispCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfbmFtZXNwYWNlXQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IGt1YmVybmV0ZXNfbmFtZXNwYWNlCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9uYW1lXQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IGt1YmVybmV0ZXNfbmFtZQo=
kind: Secret
metadata:
  creationTimestamp: 2019-03-20T03:38:37Z
  name: additional-configs
  namespace: monitoring
  resourceVersion: "29056864"
  selfLink: /api/v1/namespaces/monitoring/secrets/additional-configs
  uid: a579495b-4ac1-11e9-baf3-005056930126
type: Opaque
復制代碼

然后我們只需要在聲明 prometheus 的資源對象文件中添加上這個額外的配置:(prometheus-prometheus.yaml)

復制代碼
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  labels:
    prometheus: k8s
  name: k8s
  namespace: monitoring
spec:
  alerting:
    alertmanagers:
    - name: alertmanager-main
      namespace: monitoring
      port: web
  baseImage: quay.io/prometheus/prometheus
  nodeSelector:
    beta.kubernetes.io/os: linux
  replicas: 2
  secrets:
  - etcd-certs
  resources:
    requests:
      memory: 400Mi
  ruleSelector:
    matchLabels:
      prometheus: k8s
      role: alert-rules
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
    runAsUser: 1000
  additionalScrapeConfigs:
    name: additional-configs
    key: prometheus-additional.yaml
  serviceAccountName: prometheus-k8s
  serviceMonitorNamespaceSelector: {}
  serviceMonitorSelector: {}
  version: v2.5.0
復制代碼

添加完成后,直接更新 prometheus 這個 CRD 資源對象:

$ kubectl apply -f prometheus-prometheus.yaml
prometheus.monitoring.coreos.com/k8s configured

隔一小會兒,可以前往 Prometheus 的 Dashboard 中查看配置是否生效:

在 Prometheus Dashboard 的配置頁面下面我們可以看到已經有了對應的的配置信息了,但是我們切換到 targets 頁面下面卻並沒有發現對應的監控任務,查看 Prometheus 的 Pod 日志:

復制代碼
$ kubectl logs -f prometheus-k8s-0 prometheus -n monitoring
evel=error ts=2019-03-20T03:55:01.298281581Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:302: Failed to list *v1.Pod: pods is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list pods at the cluster scope"
level=error ts=2019-03-20T03:55:02.29813427Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:301: Failed to list *v1.Service: services is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list services at the cluster scope"
level=error ts=2019-03-20T03:55:02.298431046Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:300: Failed to list *v1.Endpoints: endpoints is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list endpoints at the cluster scope"
level=error ts=2019-03-20T03:55:02.299312874Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:302: Failed to list *v1.Pod: pods is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list pods at the cluster scope"
level=error ts=2019-03-20T03:55:03.299674406Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:301: Failed to list *v1.Service: services is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list services at the cluster scope"
level=error ts=2019-03-20T03:55:03.299757543Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:300: Failed to list *v1.Endpoints: endpoints is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list endpoints at the cluster scope"
level=error ts=2019-03-20T03:55:03.299907982Z caller=main.go:240 component=k8s_client_runtime err="github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:302: Failed to list *v1.Pod: pods is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list pods at the cluster scope"
復制代碼

可以看到有很多錯誤日志出現,都是xxx is forbidden,這說明是 RBAC 權限的問題,通過 prometheus 資源對象的配置可以知道 Prometheus 綁定了一個名為 prometheus-k8s 的 ServiceAccount 對象,而這個對象綁定的是一個名為 prometheus-k8s 的 ClusterRole:(prometheus-clusterRole.yaml)

復制代碼
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-k8s
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get
- nonResourceURLs:
  - /metrics
  verbs:
  - get
復制代碼

上面的權限規則中我們可以看到明顯沒有對 Service 或者 Pod 的 list 權限,所以報錯了,要解決這個問題,我們只需要添加上需要的權限即可:

復制代碼
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-k8s
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  - services
  - endpoints
  - pods
  - nodes/proxy
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - configmaps
  - nodes/metrics
  verbs:
  - get
- nonResourceURLs:
  - /metrics
  verbs:
  - get
復制代碼

更新上面的 ClusterRole 這個資源對象,然后重建下 Prometheus 的所有 Pod,正常就可以看到 targets 頁面下面有 kubernetes-service-endpoints 這個監控任務了:

$ kubectl apply -f prometheus-clusterRole.yaml
clusterrole.rbac.authorization.k8s.io/prometheus-k8s configured

我們這里自動監控了兩個 Service,這兩個都是coredns的,我們在 Service 中有兩個特殊的 annotations:

復制代碼
$ kubectl describe svc kube-dns -n kube-system
Name:              kube-dns
Namespace:         kube-system
....
Annotations:       prometheus.io/port=9153
                   prometheus.io/scrape=true
...
復制代碼

所以被自動發現了,當然我們也可以用同樣的方式去配置 Pod、Ingress 這些資源對象的自動發現。

數據持久化

上面我們在修改完權限的時候,重啟了 Prometheus 的 Pod,如果我們仔細觀察的話會發現我們之前采集的數據已經沒有了,這是因為我們通過 prometheus 這個 CRD 創建的 Prometheus 並沒有做數據的持久化,我們可以直接查看生成的 Prometheus Pod 的掛載情況就清楚了:

復制代碼
............
    volumeMounts:
    - mountPath: /etc/prometheus/config_out
      name: config-out
      readOnly: true
    - mountPath: /prometheus
      name: prometheus-k8s-db
    - mountPath: /etc/prometheus/rules/prometheus-k8s-rulefiles-0 
.........
 volumes:
  - name: config
    secret:
      defaultMode: 420
      secretName: prometheus-k8s
  - emptyDir: {}
復制代碼

我們可以看到 Prometheus 的數據目錄 /prometheus 實際上是通過 emptyDir 進行掛載的,我們知道 emptyDir 掛載的數據的生命周期和 Pod 生命周期一致的,所以如果 Pod 掛掉了,數據也就丟失了,這也就是為什么我們重建 Pod 后之前的數據就沒有了的原因,對應線上的監控數據肯定需要做數據的持久化的,同樣的 prometheus 這個 CRD 資源也為我們提供了數據持久化的配置方法,由於我們的 Prometheus 最終是通過 Statefulset 控制器進行部署的,所以我們這里需要通過 storageclass 來做數據持久化, 我們之前用rook已經搭建過storageclass。所以我們就可以直接用了。我們讓prometheus 的 CRD 資源對象(prometheus-prometheus.yaml)中添加如下配置:

復制代碼
  storage:
    volumeClaimTemplate:
      spec:
        storageClassName: rook-ceph-block
        resources:
          requests:
            storage: 10Gi
復制代碼

注意這里的 storageClassName 名字為上面我們創建的 StorageClass 對象名稱,然后更新 prometheus 這個 CRD 資源。更新完成后會自動生成兩個 PVC 和 PV 資源對象:

復制代碼
$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                           STORAGECLASS      REASON    AGE
pvc-dba11961-4ad6-11e9-baf3-005056930126   10Gi       RWO            Delete           Bound     monitoring/prometheus-k8s-db-prometheus-k8s-0   rook-ceph-block             1m
pvc-dbc6bac5-4ad6-11e9-baf3-005056930126   10Gi       RWO            Delete           Bound     monitoring/prometheus-k8s-db-prometheus-k8s-1   rook-ceph-block             1m
$ kubectl get pvc -n monitoring
NAME                                 STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
prometheus-k8s-db-prometheus-k8s-0   Bound     pvc-dba11961-4ad6-11e9-baf3-005056930126   10Gi       RWO            rook-ceph-block   2m
prometheus-k8s-db-prometheus-k8s-1   Bound     pvc-dbc6bac5-4ad6-11e9-baf3-005056930126   10Gi       RWO            rook-ceph-block   2m
復制代碼

現在我們再去看 Prometheus Pod 的數據目錄就可以看到是關聯到一個 PVC 對象上了。

復制代碼
.......
volumeMounts:
    - mountPath: /etc/prometheus/config_out
      name: config-out
      readOnly: true
    - mountPath: /prometheus
      name: prometheus-k8s-db
      subPath: prometheus-db
    - mountPath: /etc/prometheus/rules/prometheus-k8s-rulefiles-0
      name: prometheus-k8s-rulefiles-0
.........
  volumes:
  - name: prometheus-k8s-db
    persistentVolumeClaim:
      claimName: prometheus-k8s-db-prometheus-k8s-0
.........
復制代碼

現在即使我們的 Pod 掛掉了,數據也不會丟失了。讓我們測試一下。

我們先隨便查一下數據

刪除pod

kubectl delete pod prometheus-k8s-1 -n monitorin
kubectl delete pod prometheus-k8s-0 -n monitorin

查看pod狀態

復制代碼
kubectl get pod -n monitoring
NAME                                   READY     STATUS              RESTARTS   AGE
alertmanager-main-0                    2/2       Running             0          2d
alertmanager-main-1                    2/2       Running             0          2d
alertmanager-main-2                    2/2       Running             0          2d
grafana-7489c49998-pkl8w               1/1       Running             0          2d
kube-state-metrics-d6cf6c7b5-7dwpg     4/4       Running             0          2d
node-exporter-dlp25                    2/2       Running             0          2d
node-exporter-fghlp                    2/2       Running             0          2d
node-exporter-mxwdm                    2/2       Running             0          2d
node-exporter-r9v92                    2/2       Running             0          2d
prometheus-adapter-84cd9c96c9-n92n4    1/1       Running             0          2d
prometheus-k8s-0                       0/3       ContainerCreating   0          3s
prometheus-k8s-1                       3/3       Running             0          9s
prometheus-operator-7b74946bd6-vmbcj   1/1       Running             0          2d
復制代碼

pod正在重新創建。等創建完成,我們再查看一下數據

我們的數據是正常的,沒有丟失。

碎片化時間學習和你一起終身學習

原文請查看:https://www.cnblogs.com/xzkzzz/p/10532002.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM