该存储库收集 Kubernetes 清单、Grafana仪表板和Prometheus 规则以及文档和脚本,以使用 Prometheus Operator 通过Prometheus提供易于操作的端到端 Kubernetes 集群监控。
该项目的内容是用jsonnet编写的。该项目既可以被描述为一个包,也可以被描述为一个库。
该软件包中包含的组件:
该堆栈用于集群监控,因此它被预先配置为从所有 Kubernetes 组件收集指标。除此之外,它还提供一组默认的仪表板和警报规则。许多有用的仪表板和警报都来自kubernetes-mixin 项目,与该项目类似,它提供可组合的 jsonnet 作为库,供用户根据自己的需求进行自定义。
Prometheus Operator 的版本>=0.39.0需要 版本 的 Kubernetes 集群>=1.16.0。如果您刚刚开始使用 Prometheus Operator,强烈建议使用最新版本。
如果您运行的是旧版本的 Kubernetes 和 Prometheus Operator,我们建议先升级 Kubernetes,然后再升级 Prometheus Operator。
以下 Kubernetes 版本受支持,并且在我们在各自分支中针对这些版本进行测试时可以正常工作。但请注意,其他版本也可能有效!
kube-prometheus stack | Kubernetes 1.22 | Kubernetes 1.23 | Kubernetes 1.24 | Kubernetes 1.25 | Kubernetes 1.26 | Kubernetes 1.27 | Kubernetes 1.28 |
---|---|---|---|---|---|---|---|
release-0.10 | ✔ | ✔ | ✗ | ✗ | x | x | x |
release-0.11 | ✗ | ✔ | ✔ | ✗ | x | x | x |
release-0.12 | ✗ | ✗ | ✔ | ✔ | x | x | x |
release-0.13 | ✗ | ✗ | ✗ | x | ✔ | ✔ | ✔ |
main | ✗ | ✗ | ✗ | x | x | ✔ | ✔ |
注意:对于 Kubernetes v1.21.z 之前的版本,请参考Kubernetes 兼容性矩阵以选择兼容的分支。
首先 clone 项目代码,我们这里直接使用默认的 main 分支即可:
git clone https://github.com/prometheus-operator/kube-prometheus.git
cd kube-prometheus
使用manifests目录中的配置创建监控堆栈:
# Create the namespace and CRDs, and then wait for them to be available before creating the remaining resources
# Note that due to some CRD size we are using kubectl server-side apply feature which is generally available since kubernetes 1.22.
# If you are using previous kubernetes versions this feature may not be available and you would need to use kubectl create instead.
kubectl apply --server-side -f manifests/setup
当我们声明完 CRD 过后,就可以来自定义资源清单了,但是要让我们声明的自定义资源对象生效就需要安装对应的 Operator 控制器,在 manifests 目录下面就包含了 Operator 的资源清单以及各种监控对象声明,比如 Prometheus、Alertmanager 等,直接应用即可:
# 进入Operator 资源清单目录
cd kube-prometheus/manifests
# 新建对应的服务目录
mkdir -p operator node-exporter alertmanager grafana kube-state-metrics blackbox_exporter prometheus prometheusRules serviceMonitor adapter service
# 把对应的服务配置文件移动到相应的服务目录
mv prometheus-* prometheus/
mv prometheusOperator* operator/
mv grafana-* grafana/
mv prometheusAdapter-* adapter/
mv *-serviceMonitor* serviceMonitor/
mv kubeStateMetrics-* kube-state-metrics/
mv alertmanager-* alertmanager/
mv nodeExporter-* node-exporter/
mv blackboxExporter-* blackbox_exporter/
find . -name "*Rule.yaml" -exec mv {
} ./prometheusRules/ \;
# 新创建了两个目录,存放钉钉配置和其它配置
mkdir other dingtalk-hook
kubectl wait \
--for condition=Established \
--all CustomResourceDefinition \
--namespace=monitoring
kubectl apply -f operator/
这会创建一个名为 monitoring 的命名空间,以及相关的 CRD 资源对象声明,以避免部署监控组件时的竞争条件。
$ kubectl -n monitoring get pod
NAME READY STATUS RESTARTS AGE
prometheus-operator-586f75fb74-hzj24 2/2 Running 0 82s
$ kubectl get crd -n monitoring
NAME CREATED AT
alertmanagers.monitoring.coreos.com 2019-04-16T06:22:20Z
prometheuses.monitoring.coreos.com 2019-04-16T06:22:20Z
prometheusrules.monitoring.coreos.com 2019-04-16T06:22:20Z
servicemonitors.monitoring.coreos.com 2019-04-16T06:22:21Z
需要注意有一些资源的镜像来自于 k8s.gcr.io,如果不能正常拉取,则可以将镜像替换成可拉取的。
sed -i 's/registry.k8s.io/k8s.m.daocloud.io/g' adapter/prometheusAdapter-deployment.yaml
sed -i 's/registry.k8s.io/k8s.m.daocloud.io/g' kube-state-metrics/kubeStateMetrics-deployment.yaml
sed -i 's/quay.io/quay.m.daocloud.io/g' kube-state-metrics/kubeStateMetrics-deployment.yaml
kubectl apply -f prometheus/
kubectl apply -f grafana/
kubectl apply -f adapter/
kubectl apply -f alertmanager/
kubectl apply -f node-exporter/
kubectl apply -f kube-state-metrics/
kubectl apply -f serviceMonitor/
kubectl apply -f blackbox_exporter/
kubectl apply -f prometheusRules/
这会自动安装 prometheus-operator、node-exporter、kube-state-metrics、grafana、prometheus-adapter 以及 prometheus 和 alertmanager 等大量组件,如果没成功可以多次执行上面的安装命令。
$ kubectl get pods -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-main-0 2/2 Running 0 73m
alertmanager-main-1 2/2 Running 0 73m
alertmanager-main-2 2/2 Running 0 73m
blackbox-exporter-d46f55658-jjrjf 3/3 Running 0 72m
grafana-55dfb44658-gjhvw 1/1 Running 0 73m
kube-state-metrics-54b8f57bc9-wkcr2 3/3 Running 0 36m
node-exporter-267nz 2/2 Running 0 73m
node-exporter-6bfhs 2/2 Running 0 73m
node-exporter-9t4lj 2/2 Running 0 73m
node-exporter-nd5gh 2/2 Running 0 73m
prometheus-adapter-6f5fc7b689-24dph 1/1 Running 0 36m
prometheus-adapter-6f5fc7b689-ngcgn 1/1 Running 0 36m
prometheus-k8s-0 2/2 Running 0 73m
prometheus-k8s-1 2/2 Running 0 73m
prometheus-operator-586f75fb74-hzj24 2/2 Running 0 85m
$ kubectl get svc -o wide -n monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
alertmanager-main ClusterIP 10.247.60.19 9093/TCP,8080/TCP 3m56s app.kubernetes.io/component=alert-router,app.kubernetes.io/instance=main,app.kubernetes.io/name=alertmanager,app.kubernetes.io/part-of=kube-prometheus
alertmanager-operated ClusterIP None 9093/TCP,9094/TCP,9094/UDP 3m56s app.kubernetes.io/name=alertmanager
blackbox-exporter ClusterIP 10.247.22.106 9115/TCP,19115/TCP 3m54s app.kubernetes.io/component=exporter,app.kubernetes.io/name=blackbox-exporter,app.kubernetes.io/part-of=kube-prometheus
grafana ClusterIP 10.247.27.27 3000/TCP 3m57s app.kubernetes.io/component=grafana,app.kubernetes.io/name=grafana,app.kubernetes.io/part-of=kube-prometheus
kube-state-metrics ClusterIP None 8443/TCP,9443/TCP 3m55s app.kubernetes.io/component=exporter,app.kubernetes.io/name=kube-state-metrics,app.kubernetes.io/part-of=kube-prometheus
node-exporter ClusterIP None 9100/TCP 3m56s app.kubernetes.io/component=exporter,app.kubernetes.io/name=node-exporter,app.kubernetes.io/part-of=kube-prometheus
prometheus-adapter ClusterIP 10.247.207.100 443/TCP 3m57s app.kubernetes.io/component=metrics-adapter,app.kubernetes.io/name=prometheus-adapter,app.kubernetes.io/part-of=kube-prometheus
prometheus-k8s ClusterIP 10.247.87.202 9090/TCP,8080/TCP 4m1s app.kubernetes.io/component=prometheus,app.kubernetes.io/instance=k8s,app.kubernetes.io/name=prometheus,app.kubernetes.io/part-of=kube-prometheus
prometheus-operated ClusterIP None 9090/TCP 4m1s app.kubernetes.io/name=prometheus
prometheus-operator ClusterIP None 8443/TCP 15m app.kubernetes.io/component=controller,app.kubernetes.io/name=prometheus-operator,app.kubernetes.io/part-of=kube-prometheus
如果我们想要在外网访问这两个服务的话,可以通过创建对应的 Ingress 对象或者使用 NodePort 类型的 Service,我们这里为了简单,直接使用 NodePort 类型的服务即可,编辑 grafana、alertmanager-main 和 prometheus-k8s 这 3 个 Service,将服务类型更改为 NodePort:
# 将 type: ClusterIP 更改为 type: NodePort
$ kubectl edit svc grafana -n monitoring
$ kubectl edit svc alertmanager-main -n monitoring
$ kubectl edit svc prometheus-k8s -n monitoring
$ kubectl get svc -n monitoring
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
alertmanager-main NodePort 10.102.174.254 9093:32660/TCP,8080:31615/TCP 49m
grafana NodePort 10.105.33.193 3000:31837/TCP 49m
prometheus-k8s NodePort 10.109.250.233 9090:31664/TCP,8080:31756/TCP 49m
......
更改完成后,我们就可以通过上面的 NodePort 去访问对应的服务了,比如查看 prometheus 的服务发现页面:
可以看到已经监控上了很多指标数据了,上面我们可以看到 Prometheus 是两个副本,我们这里通过 Service 去访问,按正常来说请求是会去轮询访问后端的两个 Prometheus 实例的,但实际上我们这里访问的时候始终是路由到后端的一个实例上去,因为这里的 Service 在创建的时候添加了 sessionAffinity: ClientIP 这样的属性,会根据 ClientIP 来做 session 亲和性,所以我们不用担心请求会到不同的副本上去:
https://kubernetes.renkeju.com/chapter_6/6.2.3.Service_session_stickiness.html
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: prometheus
app.kubernetes.io/instance: k8s
app.kubernetes.io/name: prometheus
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 2.52.0
name: prometheus-k8s
namespace: monitoring
spec:
ports:
- name: web
port: 9090
targetPort: web
- name: reloader-web
port: 8080
targetPort: reloader-web
type: NodePort
selector:
app.kubernetes.io/component: prometheus
app.kubernetes.io/instance: k8s
app.kubernetes.io/name: prometheus
app.kubernetes.io/part-of: kube-prometheus
sessionAffinity: ClientIP
为什么会担心请求会到不同的副本上去呢?正常多副本应该是看成高可用的常用方案,理论上来说不同副本本地的数据是一致的,但是需要注意的是 Prometheus 的主动 Pull 拉取监控指标的方式,由于抓取时间不能完全一致,即使一致也不一定就能保证网络没什么问题,所以最终不同副本下存储的数据很大可能是不一样的,所以这里我们配置了 session 亲和性,可以保证我们在访问数据的时候始终是一致的。
如果要清理 Prometheus-Operator,可以直接删除对应的资源清单即可:
kubectl delete --ignore-not-found=true -f manifests/ -f manifests/setup
上面我们在修改完权限的时候,重启了 Prometheus 的 Pod,如果我们仔细观察的话会发现我们之前采集的数据已经没有了,这是因为我们通过 prometheus 这个 CRD 创建的 Prometheus 并没有做数据的持久化。
我们可以直接查看生成的 Prometheus Pod 的挂载情况就清楚了:
$ kubectl get pod prometheus-k8s-0 -n monitoring -o yaml
......
volumeMounts:
- mountPath: /etc/prometheus/config_out
name: config-out
readOnly: true
- mountPath: /etc/prometheus/certs
name: tls-assets
readOnly: true
- mountPath: /prometheus
name: prometheus-k8s-db
......
volumes:
......
- emptyDir: {
}
name: prometheus-k8s-db
......
emptyDir 挂载的数据的生命周期和 Pod 生命周期一致的,如果 Pod 挂掉了,数据也就丢失了,对应线上的监控数据肯定需要做数据的持久化的,由于我们的 Prometheus 最终是通过 Statefulset 控制器进行部署的,所以我们这里需要通过 storageclass 来做数据持久化。
$ cat prometheus-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: prometheus-data-db
provisioner: fuseim.pri/ifs
$ kubectl create -f prometheus-storageclass.yaml
storageclass.storage.k8s.io "prometheus-data-db" created
然后在 prometheus 的 CRD 资源对象中通过 storage 属性配置 volumeClaimTemplate 对象即可,更多配置项见API reference。
# vim prometheus/prometheus-prometheus.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
......
replicas: 2
storage:
volumeClaimTemplate:
metadata:
name: prometheus-data-db
spec:
storageClassName: prometheus-data-db
resources:
requests:
storage: 50Gi
然后更新 prometheus 这个 CRD 资源,更新完成后会自动生成两个 PVC 和 PV 资源对象:
$ kubectl apply -f prometheus-prometheus.yaml
prometheus.monitoring.coreos.com/k8s configured
$ kubectl get pvc -n monitoring
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
prometheus-k8s-db-prometheus-k8s-0 Bound pvc-4c67d0a9-e97c-4820-9c66-340a7da3c53f 20Gi RWO local-path 4s
prometheus-k8s-db-prometheus-k8s-1 Bound pvc-6f26e85c-01c6-483c-9d42-55166f77e5d0 20Gi RWO local-path 4s
$ kubectl get pv |grep monitoring
pvc-4c67d0a9-e97c-4820-9c66-340a7da3c53f 20Gi RWO Delete Bound monitoring/prometheus-k8s-db-prometheus-k8s-0 local-path 17s
pvc-6f26e85c-01c6-483c-9d42-55166f77e5d0 20Gi RWO Delete Bound monitoring/prometheus-k8s-db-prometheus-k8s-1 local-path
17s
现在即使我们的 Pod 挂掉了,数据也不会丢失了。
如果在我们的 Kubernetes 集群中有了很多的 Service/Pod,那么我们都需要一个一个的去建立一个对应的 ServiceMonitor 或 PodMonitor 对象来进行监控吗?这样岂不是又变得麻烦起来了?
为解决上面的问题,Prometheus Operator 为我们提供了一个额外的抓取配置来解决这个问题,我们可以通过添加额外的配置来进行服务发现进行自动监控。
我们可以在 Prometheus Operator 当中去自动发现并监控具有 prometheus.io/scrape=true 这个 annotations 的 Service加入到endpoints这个target中,否则就会被删除。之前我们定义的 Prometheus 的配置如下:
$ vim ./prometheus/prometheus-additional.yaml
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__address__]
target_label: __address__
regex: "(.*):10250"