prometheus operator

网友投稿 638 2022-10-04

prometheus operator

prometheus operator

  导航:这里主要是列出一个prometheus一些系统的学习过程,最后按照章节顺序查看,由于写作该文档经历了不同时期,所以在文中有时出现

的云环境不统一,但是学习具体使用方法即可,在最后的篇章,有一个完整的腾讯云的实战案例。

  1.​​什么是prometheus?​

  2.​​Prometheus安装​

  3.​​Prometheus的Exporter详解​

  4.​​Prometheus的PromQL​

  5.​​Prometheus告警处理​

  6.​​Prometheus的集群与高可用​

  7.​​Prometheus服务发现​

  8.​​kube-state-metrics 和 metrics-server​

  9.​​监控kubernetes集群的方式​

  10.​​prometheus operator​

  11.​​Prometheus实战之联邦+高可用+持久​

  12.​​Prometheus实战之配置汇总​

  13.​​Grafana简单用法​

  14.​​Grafana SQL汇总​

  15.​​prometheus SQL汇总​

  参考:

  ​​data-id="p838747a-Esxt90ag">  ​​data-id="p838747a-iRypRvoW">  ​​data-id="p838747a-LWlTnW3t">  ​​data-id="p838747a-ILPneNNN">  ​​Operator 介绍

在各种方式部署要注意各方式不同的地方,比如二进制部署,那么metrics-server等服务一定要正常,以及二进制集群开启比如聚合层这样的配置,所以这一章在metrics-server章节的后面,这2章阅读的时候是相辅相成的,不然实验很容易失败.

之前为了在Kubernetes能够方便的管理和部署Prometheus,可使用ConfigMap了管理Prometheus配置文件。每次对Prometheus配置文件进行升级时,我们需要手动移除已经运行的Pod实例,从而让Kubernetes可以使用最新的配置文件创建Prometheus。 而如果当应用实例的数量更多时,通过手动的方式部署和升级Prometheus过程繁琐并且效率低下。

从本质上来讲Prometheus属于是典型的有状态应用,而其有包含了一些自身特有的运维管理和配置管理方式。而这些都无法通过Kubernetes原生提供的应用管理概念实现自动化。为了简化这类应用程序的管理复杂度,CoreOS率先引入了Operator的概念,并且首先推出了针对在Kubernetes下运行和管理Etcd的Etcd Operator。并随后推出了Prometheus Operator。

1.1 Prometheus Operator的工作原理

从概念上来讲Operator就是针对管理特定应用程序的,在Kubernetes基本的Resource和Controller的概念上,以扩展Kubernetes api的形式。帮助用户创建,配置和管理复杂的有状态应用程序。从而实现特定应用程序的常见操作以及运维自动化。

而除了这些原生的Resource资源以外,Kubernetes还允许用户添加自己的自定义资源(Custom Resource)。并且通过实现自定义Controller来实现对Kubernetes的扩展。

如下所示,是Prometheus Operator的架构示意图:

Prometheus Operator架构

Prometheus的本职就是一组用户自定义的CRD资源以及Controller的实现,Prometheus Operator负责监听这些自定义资源的变化,并且根据这些资源的定义自动化的完成如Prometheus Server自身以及配置的自动化管理工作。

1.2 Prometheus Operator能做什么

要了解Prometheus Operator能做什么,其实就是要了解Prometheus Operator为我们提供了哪些自定义的Kubernetes资源,列出了Prometheus Operator目前提供的4类资源:

简言之,Prometheus Operator能够帮助用户自动化的创建以及管理Prometheus Server以及其相应的配置。

2.安装

最新的版本官方将资源:​​opetator的yml,其余的crd都需要自己去自定义,非常不方便;kube-prometheus里面有全套的模版给我们使用.

我们这里直接通过 Prometheus-Operator 的源码来进行安装,当然也可以用 Helm 来进行一键安装,我们采用源码安装可以去了解更多的实现细节。

git clone [root@ip-10-1-50-250 kube-prometheus]# cd manifests/ [root@ip-10-1-50-250 manifests]# pwd /k8s/kube-prometheus/manifests [root@ip-10-1-50-250 manifests]# ls 00namespace-namespace.yaml grafana-service.yaml prometheus-adapter-configMap.yaml 0prometheus-operator-0alertmanagerCustomResourceDefinition.yaml kube-controller-manager-service.yaml prometheus-adapter-deployment.yaml 0prometheus-operator-0podmonitorCustomResourceDefinition.yaml kube-scheduler-service.yaml prometheus-adapter-roleBindingAuthReader.yaml 0prometheus-operator-0prometheusCustomResourceDefinition.yaml kube-state-metrics-clusterRoleBinding.yaml prometheus-adapter-serviceAccount.yaml 0prometheus-operator-0prometheusruleCustomResourceDefinition.yaml kube-state-metrics-clusterRole.yaml prometheus-adapter-service.yaml 0prometheus-operator-0servicemonitorCustomResourceDefinition.yaml kube-state-metrics-deployment.yaml prometheus-additional.yaml 0prometheus-operator-clusterRoleBinding.yaml kube-state-metrics-roleBinding.yaml prometheus-clusterRoleBinding.yaml

如果这里kubelet的端口不是manifests 目录下面,这个目录下面包含我们所有的资源清单文件,我们需要对其中的文件 prometheus-serviceMonitorKubelet.yaml 进行简单的修改,因为默认情况下,这个 ServiceMonitor 是关联的 kubelet 的10250端口去采集的节点数据,而我们前面说过为了安全,这个 metrics 数据已经迁移到10255这个只读端口上面去了,我们只需要将文件中的eks环境,这一步不需要操作.

[root@ip-10-1-50-250 manifests]# pwd/k8s/kube-prometheus/manifests[root@ip-10-1-50-250 manifests]# kubectl apply -f .

部署完成后,会创建一个名为monitoring的 namespace,所以资源对象对将部署在改命名空间下面,此外 Operator 会自动创建4个 CRD 资源对象:

$ kubectl get crd |grep coreosalertmanagers.monitoring.coreos.com 5dprometheuses.monitoring.coreos.com 5dprometheusrules.monitoring.coreos.com 5dservicemonitors.monitoring.coreos.com 5d

可以在 monitoring 命名空间下面查看所有的 Pod,其中 alertmanager 和 prometheus 是用 StatefulSet 控制器管理的,其中还有一个比较核心的 prometheus-operator 的 Pod,用来控制其他资源对象和监听对象变化的:

$ kubectl get pods -n monitoringNAME READY STATUS RESTARTS AGEalertmanager-main-0 2/2 Running 0 21halertmanager-main-1 2/2 Running 0 21halertmanager-main-2 2/2 Running 0 21hgrafana-df9bfd765-f4dvw 1/1 Running 0 22hkube-state-metrics-77c9658489-ntj66 4/4 Running 0 20hnode-exporter-4sr7f 2/2 Running 0 21hnode-exporter-9mh2r 2/2 Running 0 21hnode-exporter-m2gkp 2/2 Running 0 21hprometheus-adapter-dc548cc6-r6lhb 1/1 Running 0 22hprometheus-k8s-0 3/3 Running 1 21hprometheus-k8s-1 3/3 Running 1 21hprometheus-operator-bdf79ff67-9dc48 1/1 Running 0 21h

查看创建的 Service:

$ kubectl get svc -n monitoringNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEalertmanager-main ClusterIP 172.20.71.161 9093/TCP 79malertmanager-operated ClusterIP None 9093/TCP,9094/TCP,9094/UDP 79mgrafana ClusterIP 172.20.200.116 3000/TCP 79mkube-state-metrics ClusterIP None 8443/TCP,9443/TCP 79mnode-exporter ClusterIP None 9100/TCP 79mprometheus-adapter ClusterIP 172.20.122.213 443/TCP 79mprometheus-k8s ClusterIP 172.20.32.47 9090/TCP 79mprometheus-operated ClusterIP None 9090/TCP 79m

可以看到上面针对 grafana 和 prometheus 都创建了一个类型为 ClusterIP 的 Service,当然如果我们想要在外网访问这两个服务的话可以通过创建对应的 Ingress 对象或者使用 NodePort 类型的 Service,这里使用什么样的方式都可以,按照自己定义的环境,接下来看看2个服务.(这里使用的是nginx)

比如Prometheus targets界面

3.简单配置

像在EKS上,全部托管了,而且不是以pod的方式部署的,那么我们就无法监控(具体看后面章节)

我们可以看到大部分的配置都是正常的,只有两三个没有管理到对应的监控目标,比如 kube-controller-manager 和 kube-scheduler 这两个系统组件,这就和 ServiceMonitor 的定义有关系了,我们先来查看下 kube-scheduler 组件对应的 ServiceMonitor 资源的定义:(prometheus-serviceMonitorKubeScheduler.yaml)

apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: labels: k8s-app: kube-scheduler name: kube-scheduler namespace: monitoringspec: endpoints: - interval: 30s # 每30s获取一次信息 port: # 对应service的端口名 jobLabel: k8s-app namespaceSelector: # 表示去匹配某一命名空间中的service,如果想从所有的namespace中匹配用any: true matchNames: - kube-system selector: # 匹配的 Service 的labels,如果使用mathLabels,则下面的所有标签都匹配时才会匹配该service,如果使用matchExpressions,则至少匹配一个标签的service都会被选择 matchLabels: k8s-app: kube-scheduler

apiVersion: v1kind: Servicemetadata: namespace: kube-system name: kube-scheduler labels: k8s-app: kube-schedulerspec: selector: component: kube-scheduler ports: - name: port: 10251 targetPort: 10251 protocol: TCP

10251是kube-scheduler组件 metrics 数据所在的端口,10252是kube-controller-manager组件的监控数据所在端口。

这里有2个分支,2种部署方式了。

3.1 Kube-scheduler以pod方式部署

其中最重要的是上面 labels 和 selector 部分,labels 区域的配置必须和我们上面的 ServiceMonitor 对象中的 selector 保持一致,selector下面配置的是component=kube-scheduler,为什么会是这个 label 标签呢,我们可以去 describe 下 kube-scheduelr 这个 Pod:(二进制部署没有这个步骤)

$ kubectl describe pod kube-scheduler-master -n kube-systemName: kube-scheduler-masterNamespace: kube-systemNode: master/10.151.30.57Start Time: Sun, 05 Aug 2018 18:13:32 +0800Labels: 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-schedulerNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkube-scheduler ClusterIP 10.102.119.231 10251/TCP 18m

创建完成后,隔一小会儿后去 prometheus 查看 targets 下面 kube-scheduler 的状态

我们可以看到现在已经发现了 target,但是抓取数据结果出错了,这个错误是因为我们集群是使用 kubeadm 搭建的,其中 kube-scheduler 默认是绑定在127.0.0.1上面的,而上面我们这个地方是想通过节点的 IP 去访问,所以访问被拒绝了,我们只要把 kube-scheduler 绑定的地址更改成0.0.0.0即可满足要求,由于 kube-scheduler 是以静态 Pod 的形式运行在集群中的,所以我们只需要更改静态 Pod 目录下面对应的 YAML 文件即可:

$ ls /etc/kubernetes/manifests/etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml

将 kube-scheduler.yaml 文件中-command的--address地址更改成0.0.0.0:

containers:- command:- kube-scheduler- --leader-elect=true- --kubeconfig=/etc/kubernetes/scheduler.conf- --address=0.0.0.0

修改完成后我们将该文件从当前文件夹中移除,隔一会儿再移回该目录,就可以自动更新了,然后再去看 prometheus 中 kube-scheduler 这个 target 是否已经正常了

以上是kube-scheduler以pod模式部署配置正常监控的流程, kube-controller-manager和kube-scheudler方式相同

3.2 Kube-scheduler以二进制方式部署

首先二进制的方式不仅没有匹配到svc,甚至即使匹配到了svc,默认是没有endpoints的,所以在pod部署的方式里面创建svc就可以了;但是二进制,不仅要创建svc,还要创建关联的endpoints.这样监控才知道要监控的目标是什么。

下面还是列出完整的步骤;

[root@master01 manifests]# cat kube-controller-manager-service.yaml kube-scheduler-service.yaml ---apiVersion: v1kind: Servicemetadata: labels: k8s-app: kube-controller-manager name: kube-controller-manager namespace: kube-systemspec: type: ClusterIP clusterIP: None ports: - name: port: 10252 protocol: TCP targetPort: 10252---apiVersion: v1kind: Servicemetadata: namespace: kube-system name: kube-scheduler labels: k8s-app: kube-schedulerspec: type: ClusterIP clusterIP: None ports: - name: port: 10251 targetPort: 10251 protocol: TCP

现在查看这这2个svc是没有endpoints,所以,这里我们还要创建关联的endpoints

[root@master01 manifests]# cat kube-scheduler-endpoint.yml kube-controller-manager-endpoint.yaml ---apiVersion: v1kind: Endpointsmetadata: labels: k8s-app: kube-scheduler name: kube-scheduler namespace: kube-systemsubsets:- addresses: - ip: 172.21.161.145 #这里是具体二进制部署组件的ip,我这里有2台 - ip: 172.21.161.146 ports: - name: port: 10251 protocol: TCPapiVersion: v1kind: Endpointsmetadata: labels: k8s-app: kube-controller-manager name: kube-controller-manager namespace: kube-systemsubsets:- addresses: - ip: 172.21.161.145 - ip: 172.21.161.146 ports: - name: port: 10252protocol: TCP

创建完成之后可以看到一下endpoints,那么prometheus根据标签就可以得到要监控访问的地址了

到这里差不多就结束了,但是在prometheus 的targets界面的时候,还是显示连接超时,这是因为controller-manager的监听地址是127.0.0.1,那么就需要把127.0.0.1改为0.0.0.0,目前二进制只需要更改controller-manager即可,改完之后重启服务,然后登录网页查看.

4.高级配置

4.1 新增自动发现配置

以下是添加自定义刮擦的官方链接: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: ( - 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

$ kubectl create secret generic additional-configs --from-file=prometheus-additional.yaml -n monitoringsecret "additional-configs"

创建完成后,会将上面配置信息进行 base64 编码后作为 prometheus-additional.yaml 这个 key 对应的值存在:

$ kubectl get secret additional-configs -n monitoring -o yamlapiVersion: v1data: prometheus-additional.yaml: LSBqb2JfbmFtZTogJ2t1YmVybmV0ZXMtc2VydmljZS1lbmRwb2ludHMnCiAga3ViZXJuZXRlc19zZF9jb25maWdzOgogIC0gcm9sZTogZW5kcG9pbnRzCiAgcmVsYWJlbF9jb25maWdzOgogIC0gc291cmNlX2xhYmVsczogW19fbWV0YV9rdWJlcm5ldGVzX3NlcnZpY2VfYW5ub3RhdGlvbl9wcm9tZXRoZXVzX2lvX3NjcmFwZV0KICAgIGFjdGlvbjoga2VlcAogICAgcmVnZXg6IHRydWUKICAtIHNvdXJjZV9sYWJlbHM6IFtfX21ldGFfa3ViZXJuZXRlc19zZXJ2aWNlX2Fubm90YXRpb25fcHJvbWV0aGV1c19pb19zY2hlbWVdCiAgICBhY3Rpb246IHJlcGxhY2UKICAgIHRhcmdldF9sYWJlbDogX19zY2hlbWVfXwogICAgcmVnZXg6IChodHRwcz8pCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9hbm5vdGF0aW9uX3Byb21ldGhldXNfaW9fcGF0aF0KICAgIGFjdGlvbjogcmVwbGFjZQogICAgdGFyZ2V0X2xhYmVsOiBfX21ldHJpY3NfcGF0aF9fCiAgICByZWdleDogKC4rKQogIC0gc291cmNlX2xhYmVsczogW19fYWRkcmVzc19fLCBfX21ldGFfa3ViZXJuZXRlc19zZXJ2aWNlX2Fubm90YXRpb25fcHJvbWV0aGV1c19pb19wb3J0XQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IF9fYWRkcmVzc19fCiAgICByZWdleDogKFteOl0rKSg/OjpcZCspPzsoXGQrKQogICAgcmVwbGFjZW1lbnQ6ICQxOiQyCiAgLSBhY3Rpb246IGxhYmVsbWFwCiAgICByZWdleDogX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9sYWJlbF8oLispCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfbmFtZXNwYWNlXQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IGt1YmVybmV0ZXNfbmFtZXNwYWNlCiAgLSBzb3VyY2VfbGFiZWxzOiBbX19tZXRhX2t1YmVybmV0ZXNfc2VydmljZV9uYW1lXQogICAgYWN0aW9uOiByZXBsYWNlCiAgICB0YXJnZXRfbGFiZWw6IGt1YmVybmV0ZXNfbmFtZQo=kind: Secretmetadata: creationTimestamp: 2018-12-20T14:50:35Z name: additional-configs namespace: monitoring resourceVersion: "41814998" selfLink: /api/v1/namespaces/monitoring/secrets/additional-configs uid: 9bbe22c5-0466-11e9-a777-525400db4df7type: Opaque

apiVersion: monitoring.coreos.com/v1kind: Prometheusmetadata: labels: prometheus: k8s name: k8s namespace: monitoringspec: 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-k8s serviceMonitorNamespaceSelector: {} serviceMonitorSelector: {} version: v2.5.0

在Prometheus Dashboard 的配置页面下面我们可以看到已经有了对应的的配置信息了,但是我们切换到 targets 页面下面却并没有发现对应的监控任务,查看 Prometheus 的 Pod 日志:

$ kubectl logs -f prometheus-k8s-0 prometheus -n monitoringlevel=error ts=2018-12-20T15:14:06.772903214Z 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=2018-12-20T15:14:06.773096875Z 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=2018-12-20T15:14:06.773212629Z 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"......

可以看到有很多错误日志出现,都是xxx is forbidden,这说明是 RBAC 权限的问题,通过 prometheus 资源对象的配置可以知道 Prometheus 绑定了一个名为 prometheus-k8s 的 ServiceAccount 对象,而这个对象绑定的是一个名为 prometheus-k8s 的 ClusterRole:(prometheus-clusterRole.yaml)

apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: prometheus-k8srules:- apiGroups: - "" resources: - nodes/metrics verbs: - get- nonResourceURLs: - /metrics verbs: - get

上面的权限规则中我们可以看到明显没有对 Service 或者 Pod 的 list 权限,所以报错了,要解决这个问题,我们只需要添加上需要的权限即可:

apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: prometheus-k8srules:- 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 这个监控任务了:

我们这里自动监控了两个 Service,这是默认的core dns ,Service 中有两个特殊的 annotations:

annotations: prometheus.io/scrape: "true" prometheus.io/port: "9121"

所以被自动发现了,当然我们也可以用同样的方式去配置 Pod、Ingress 这些资源对象的自动发现。

4.2 新增prometheus 配置

在上节中,配置了自定义的发现配置,但是如果想配置其它的一些配置,比如remote_write,remote_read就不是这种方法了,那么这里有官方文档的对应.

​​ name: additional-configs key: prometheus-additional.yaml remoteWrite: - url: ' remoteRead: - url: 'prometheus-prometheus.yaml

验证,查看influxdb是否有数据写入。

由于写入可以很明显的看出是否配置正确,但读取因为prometheus的特性,即使错误了在短期也无法判断,所以这里看prometheus没有报错,可以不准确的判断;

4.3 新增prometheus 持久化

由于这里是功能实体的类型,所以很难手动给pod加入pvc,所以本章主要是使用pv动态供给来完成的,如果对动态供给不太熟悉的,可以翻阅书籍然后在看这一章.

如果在没有remote_write和remote_read的情况下, 上面我们在修改完权限的时候,重启了 Prometheus 的 Pod,如果我们仔细观察的话会发现我们之前采集的数据已经没有了,这是因为我们通过 prometheus 这个 CRD 创建的 Prometheus 并没有做数据的持久化,我们可以直接查看生成的 Prometheus Pod 的挂载情况就清楚了:

我们可以看到 Prometheus 的数据目录 /prometheus 实际上是通过 emptyDir 进行挂载的,我们知道 emptyDir 挂载的数据的生命周期和 Pod 生命周期一致的,所以如果 Pod 挂掉了,数据也就丢失了,这也就是为什么我们重建 Pod 后之前的数据就没有了的原因,对应线上的监控数据肯定需要做数据的持久化的,同样的 prometheus 这个 CRD 资源也为我们提供了数据持久化的配置方法,由于我们的 Prometheus 最终是通过 Statefulset 控制器进行部署的,所以我们这里需要通过 storageclass 来做数据持久化,首先创建一个 StorageClass 对象:

(aws是gp2,默认不需要不需要创建,这一步根据不同的环境来确认是否需要创建)

apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: prometheus-data-dbprovisioner: fuseim.pri/ifs

$ kubectl create -f prometheus-storageclass.yamlstorageclass.storage.k8s.io "prometheus-data-db"

然后在 prometheus 的 CRD 资源对象中添加如下配置:

storage: volumeClaimTemplate: spec: storageClassName: prometheus-data-db resources: requests: storage: 10Gi

注意这里的 storageClassName 名字为上面我们创建的 StorageClass 对象名称,然后更新 prometheus 这个 CRD 资源。更新完成后会自动生成两个 PVC 和 PV 资源对象:

$ kubectl get pvc -n monitoringNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEprometheus-k8s-db-prometheus-k8s-0 Bound pvc-0cc03d41-047a-11e9-a777-525400db4df7 10Gi RWO prometheus-data-db 8mprometheus-k8s-db-prometheus-k8s-1 Bound pvc-1938de6b-047b-11e9-a777-525400db4df7 10Gi RWO prometheus-data-db 1m$ kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpvc-0cc03d41-047a-11e9-a777-525400db4df7 10Gi RWO Delete Bound monitoring/prometheus-k8s-db-prometheus-k8s-0 prometheus-data-db 2mpvc-1938de6b-047b-11e9-a777-525400db4df7 10Gi RWO Delete Bound monitoring/prometheus-k8s-db-prometheus-k8s-1 prometheus-data-db 1m

现在我们再去看 Prometheus Pod 的数据目录就可以看到是关联到一个 PVC 对象上了。

$ kubectl get pod prometheus-k8s-0 -n monitoring -o yaml...... volumeMounts: - mountPath: /etc/prometheus/config_out name: config-out readOnly: true - mountPath: /prometheus name: prometheus-k8s-db...... volumes:...... - name: prometheus-k8s-db persistentVolumeClaim: claimName: prometheus-k8s-db-prometheus-k8s-0......

现在即使我们的 Pod 挂掉了,数据也不会丢失了,最后,下面是我们 Prometheus Operator 系列课程中最终的创建资源清单文件,更多的信息可以在​​monitoring.coreos.com/v1kind: Prometheusmetadata: labels: prometheus: k8s name: k8s namespace: monitoringspec: alerting: alertmanagers: - name: alertmanager-main namespace: monitoring port: web storage: volumeClaimTemplate: spec: storageClassName: prometheus-data-db resources: requests: storage: 10Gi baseImage: quay.io/prometheus/prometheus nodeSelector: beta.kubernetes.io/os: linux replicas: 2 secrets: - etcd-certs additionalScrapeConfigs: name: additional-configs key: prometheus-additional.yaml resources: requests: memory: 400Mi ruleSelector: matchLabels: prometheus: k8s role: alert-rules securityContext: fsGroup: 2000 runAsNonRoot: true runAsUser: 1000 serviceAccountName: prometheus-k8s serviceMonitorNamespaceSelector: {} serviceMonitorSelector: {} version: v2.5.0

示例代码

5.Prometheus operator 自定义报警

5.1 配置 PrometheusRule

如果需要自定义一个报警规则的话呢?比如现在我们去查看 Prometheus Dashboard 的 Alert 页面下面就已经有一些报警规则了,还有一些是已经触发规则的了:

但是这些报警信息是哪里来的呢?他们应该用怎样的方式通知我们呢?我们知道之前我们使用自定义的方式可以在 Prometheus 的配置文件之中指定 AlertManager 实例和报警的 rules 文件,现在我们通过 Operator 部署的呢?我们可以在 Prometheus Dashboard 的 Config 页面下面查看关于 AlertManager 的配置:

上面 alertmanagers 实例的配置我们可以看到是通过角色为 endpoints 的 kubernetes 的服务发现机制获取的,匹配的是服务名为 alertmanager-main,端口名未 web 的 Service 服务,我们查看下 alertmanager-main 这个 Service:

kubectl describe svc alertmanager-main -n monitoringName: alertmanager-mainNamespace: monitoringLabels: alertmanager=mainAnnotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"alertmanager":"main"},"name":"alertmanager-main","namespace":"...Selector: alertmanager=main,app=alertmanagerType: ClusterIPIP: 172.20.71.161Port: web 9093/TCPTargetPort: web/TCPEndpoints: 10.1.53.79:9093,10.1.54.229:9093,10.1.55.141:9093Session Affinity: ClientIPEvents:

可以看到服务名正是 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 monitoringDefaulting 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.yamlgroups:- 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......

这个 YAML 文件实际上就是我们之前创建的一个 PrometheusRule 文件包含的:

$ cat prometheus-rules.yamlapiVersion: monitoring.coreos.com/v1kind: PrometheusRulemetadata: labels: prometheus: k8s role: alert-rules name: prometheus-k8s-rules namespace: monitoringspec: 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

我们这里的 PrometheusRule 的 name 为 prometheus-k8s-rules,namespace 为 monitoring,我们可以猜想到我们创建一个 PrometheusRule 资源对象后,会自动在上面的 prometheus-k8s-rulefiles-0 目录下面生成一个对应的-.yaml文件,所以如果以后我们需要自定义一个报警选项的话,只需要定义一个 PrometheusRule 资源对象即可。至于为什么 Prometheus 能够识别这个 PrometheusRule 资源对象呢?这就需要查看我们创建的 prometheus 这个资源对象了,里面有非常重要的一个属性 ruleSelector,用来匹配 rule 规则的过滤器,要求匹配具有 prometheus=k8s 和 role=alert-rules 标签的 PrometheusRule 资源对象,现在明白了吧?

prometheus-prometheus.yamlruleSelector: matchLabels: prometheus: k8s role: alert-rules

所以我们要想自定义一个报警规则,只需要创建一个具有 prometheus=k8s 和 role=alert-rules 标签的 PrometheusRule 对象就行了,比如现在我们添加一个 etcd 是否可用的报警,我们知道 etcd 整个集群有一半以上的节点可用的话集群就是可用的,所以我们判断如果不可用的 etcd 数量超过了一半那么就触发报警,创建文件 prometheus-etcdRules.yaml:

apiVersion: monitoring.coreos.com/v1kind: PrometheusRulemetadata: labels: prometheus: k8s role: alert-rules name: etcd-rules namespace: monitoringspec: 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

注意 label 标签一定至少要有 prometheus=k8s 和 role=alert-rules,创建完成后,隔一会儿再去容器中查看下 rules 文件夹:

kubectl exec -it prometheus-k8s-0 /bin/sh -n monitoringDefaulting 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 页面下面就可以查看到上面我们新建的报警规则了:

5.2 配置报警

我们知道了如何去添加一个报警规则配置项,但是这些报警信息用怎样的方式去发送呢?前面的课程中我们知道我们可以通过 AlertManager 的配置文件去配置各种报警接收器,现在我们是通过 Operator 提供的 alertmanager 资源对象创建的组件,应该怎样去修改配置呢?

首先我们将 alertmanager-main 这个 Service 改为 NodePort 类型的 Service,修改完成后我们可以在页面上的 status 路径下面查看 AlertManager 的配置信息:

这些配置信息实际上是来自于我们之前在prometheus-operator/contrib/kube-prometheus/manifests目录下面创建的 alertmanager-secret.yaml 文件:

apiVersion: v1data: alertmanager.yaml: Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg==kind: Secretmetadata: name: alertmanager-main namespace: monitoringtype: 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.163.com:25' #smtp_from: 'lizexiongtest@163.com' #smtp_auth_username: 'lizexiongtest@163.com' #smtp_auth_password: 'lzx1231' smtp_smarthost: 'postfix.public:25' smtp_from: 'alert@dena.com' smtp_auth_username: 'alert' smtp_auth_password: 'renyi' smtp_require_tls: falsereceivers:- name: 'email' email_configs: - to: "zexiong.li@dena.com" send_resolved: true text: '.GroupLabels.app }}/{{ .GroupLabels.alertname }}'route: group_by: ['alertname'] group_interval: 20s group_wait: 20s receiver: 'email' repeat_interval: 20s

将上面文件保存为 alertmanager.yaml,然后使用这个文件创建一个 Secret 对象:(注意,这个文件名一定要和alertmanager-alertmanager.yaml里面的对应上,包括yaml的后缀)

# 先将之前的 secret 对象删除$ kubectl delete secret alertmanager-main -n monitoringsecret "alertmanager-main" deleted$ kubectl create secret generic alertmanager-main --from-file=alertmanager.yaml -n monitoringsecret "alertmanager-main"

可以查看收到告警

我们再次查看 AlertManager 页面的 status 页面的配置信息可以看到已经变成上面我们的配置信息了:

5.3 告警模版

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

apiVersion:v1kind:secretmetadata: name:alertmanager-exampledata: alertmanager.yaml:{BASE64_CONFIG} #这里的模版只是一个变量,这里要替换成实际的 template_1.tmpl:{BASE64_TEMPLATE_1} template_2.tmpl:{BASE64_TEMPLATE_2} ...

模板会被放置到与配置文件相同的路径,当然要使用这些模板文件,还需要在 alertmanager.yaml 配置文件中指定:

templates:- '*.tmpl'

创建成功后,Secret 对象将会挂载到 AlertManager 对象创建的 AlertManager Pod 中去。

作者:​​小家电维修​​

转世燕还故榻,为你衔来二月的花。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小程序加载器的实现:按需预加载远程图片资源(小程序图片预加载)
下一篇:Prometheus实战之联邦+高可用+持久
相关文章

 发表评论

暂时没有评论,来抢沙发吧~