一、什么是Operator
Operator是由CoreOS開發的,用來擴展Kubernetes API,特定的應用程序控制器,它用來創建、配置和管理復雜的有狀態應用,如數據庫、緩存和監控系統。Operator基於Kubernetes的資源和控制器概念之上構建,但同時又包含了應用程序特定的領域知識。創建Operator的關鍵是CRD(自定義資源)的設計。
Operator
是將運維人員對軟件操作的知識給代碼化,同時利用 Kubernetes 強大的抽象來管理大規模的軟件應用。目前CoreOS
官方提供了幾種Operator
的實現,其中就包括我們今天的主角:Prometheus Operator
,Operator
的核心實現就是基於 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-scheduler
和tier=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正在重新創建。等創建完成,我們再查看一下數據
我們的數據是正常的,沒有丟失。