K8s 集群监控之Kube Prometheus(Prometheus Operator)

Kube Prometheus项目地址

https://github.com/coreos/kube-prometheus

项目的Helm安装包地址

https://github.com/helm/charts/blob/master/stable/prometheus-operator

Prometheus官网地址

https://prometheus.io/

Prometheus Operator项目地址

https://github.com/coreos/prometheus-operator/

一个部署样例

https://github.com/coreos/kube-prometheus/blob/master/examples/example-app/

Prometheus Operator是什么

Prometheus Operator是运行在Kubernetes之上的监控和告警工具。部署时不用创建和修改prometheus的配置文件,所有的操作通过创建prometheus自己的资源对象来实现。对于监控配置的修改可以做到实时生效。

Prometheus Operator的自定义资源(CustomResourceDefinitions CRD)

  • Prometheus: 定义Prometheus监控系统的部署。
  • ServiceMonitor:监控一组service。该service需要暴露监控数据,供prometheus收集。
  • PodMonitor:监控一组pod。
  • PrometheusRule:Prometheus的规则文件。包含告警规则。
  • AlertManager:定义告警管理器的部署。

QuickStart

下载kube-prometheus项目。

git clone https://github.com/coreos/kube-prometheus.git

执行:

# Create the namespace and CRDs, and then wait for them to be availble before creating the remaining resources
kubectl create -f manifests/setup
# 下面命令为等待setup过程运行完毕
until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done
kubectl create -f manifests/

移除Kube Prometheus

执行:

kubectl delete --ignore-not-found=true -f manifests/ -f manifests/setup

访问仪表盘

可以使用port forward方式访问仪表盘。

访问Prometheus

$ kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090

访问Grafana

$ kubectl --namespace monitoring port-forward svc/grafana 3000

访问Alert Manager

$ kubectl --namespace monitoring port-forward svc/alertmanager-main 9093

这些服务的端口可以通过localhost访问到。

注意:如果需要通过其他地址访问,需要增加address参数。举例如下:

$ kubectl --namespace monitoring port-forward --address 0.0.0.0 svc/prometheus-k8s 9090

手动部署prometheus operator

上面步骤使用的是Kube Prometheus。该项目内置了一系列prometheus operator的资源对象配置,可以做到一键安装。

Prometheus operator也可以手工方式部署。

安装Prometheus Operator

  1. Git下载Prometheus Operator项目
git clone https://github.com/coreos/prometheus-operator.git
  1. 执行命令,创建prometheus-operator对象和相关CRD
kubectl apply -f bundle.yaml
  1. 启用prometheus资源对象的RBAC规则

创建ServiceAccount:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus

创建ClusterRole:

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - nodes
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources:
  - configmaps
  verbs: ["get"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]

创建ClusterRoleBinding

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: default
  1. 创建prometheus资源对象
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: prometheus
spec:
  serviceAccountName: prometheus
  serviceMonitorSelector:
    matchLabels:
      team: frontend
  podMonitorSelector:
    matchLabels:
      team: frontend
  resources:
    requests:
      memory: 400Mi
  enableAdminAPI: false

通过serviceMonitorSelectorpodMonitorSelector决定哪些ServiceMonitor和PodMonitor生效。如果选择器为空({})意味着会选择所有的对象。

  1. 部署自己的应用。
    下面举一个例子:

创建一个Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: example-app
  template:
    metadata:
      labels:
        app: example-app
    spec:
      containers:
      - name: example-app
        image: fabxc/instrumented_app
        ports:
        - name: web
          containerPort: 8080

这里假定我们的监控数据在8080端口暴露。

再创建一个service,即访问监控数据的service。

kind: Service
apiVersion: v1
metadata:
  name: example-app
  labels:
    app: example-app
spec:
  selector:
    app: example-app
  ports:
  - name: web
    port: 8080
  1. 创建ServiceMonitor

这一步我们需要Prometheus读取上一步创建的service暴露的监控数据。需要借助于ServiceMonitor完成。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: example-app
  labels:
    team: frontend
spec:
  selector:
    matchLabels:
      app: example-app
  endpoints:
  - port: web

注意:

  • 这里的selector需要匹配上一步创建出来的service。
  • endpoints的port只能配置为service中的命名端口,不能使用数字。
  • 需要确保prometheus对象的serviceMonitorSelectorserviceMonitorNamespaceSelector匹配这一步创建出的ServiceMonitor对象。
  1. 暴露prometheus端口

如果需要暴露prometheus端口可以在集群外访问,需要执行此步骤。

apiVersion: v1
kind: Service
metadata:
  name: prometheus
spec:
  type: NodePort
  ports:
  - name: web
    nodePort: 30900
    port: 9090
    protocol: TCP
    targetPort: web
  selector:
    prometheus: prometheus

这里使用创建了一个使用NodePort的Service。

Prometheus资源对象

Prometheus资源对象的作用相当于整个Prometheus的配置中心。

Prometheus资源对象描述文件如下:

apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  creationTimestamp: "2020-02-12T04:38:38Z"
  generation: 1
  labels:
    prometheus: k8s
  name: k8s
  namespace: monitoring
  resourceVersion: "3745"
  selfLink: /apis/monitoring.coreos.com/v1/namespaces/monitoring/prometheuses/k8s
  uid: 3d66375e-b8fb-453b-bcd2-a9ef1fd75387
spec:
  alerting:
    alertmanagers:
    - name: alertmanager-main
      namespace: monitoring
      port: web
  baseImage: quay.io/prometheus/prometheus
  nodeSelector:
    kubernetes.io/os: linux
  podMonitorNamespaceSelector: {}
  podMonitorSelector: {}
  replicas: 2
  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.15.2

其中,限制监控范围的配置有如下四个:

  • podMonitorNamespaceSelector:扫描哪个namespace下的PodMonitor,如果为空,则扫描所有的namespace。
  • serviceMonitorNamespaceSelector:扫描哪个namespace下的ServiceMonitor,如果为空,则扫描所有的namespace。
  • podMonitorSelector:通过selector配置扫描哪些PodMonitor。如果为空,则扫描所有PodMonitor。
  • serviceMonitorSelector:通过selector配置扫描哪些ServiceMonitor。如果为空,则扫描所有ServiceMonitor。

除此之外还有一个ruleSelector,只有匹配该selector的PrometheusRules才会被读取。因此我们如是用默认的prometheus配置,自己创建的PrometheusRules需要有如下两个标签:

prometheus: k8s
role: alert-rules

指定Prometheus的远程存储

生产环境Prometheus的监控数据需要落地到数据库中。

建议使用Influx数据库。它和Prometheus的兼容性最好。

安装InfluxDB

InfluxDB官网链接:https://www.influxdata.com/

下载安装并启动服务即可。

# 启动InfluxDB
systemctl start influxdb

# 进入InfluxDB
influx

创建一个名为prometheus的数据库:

curl -XPOST http://localhost:8086/query --data-urlencode "q=CREATE DATABASE prometheus"

编译并运行Remote storage adapter

Prometheus使用Influx作为远程存储需要一个remote_storage_adapterremote_storage_adapter可以支持Graphite, Influxdb和Opentsdb。其中Influxdb支持READ和WRITE模式。

源代码链接如下:https://github.com/prometheus/prometheus/tree/master/documentation/examples/remote_storage/remote_storage_adapter

使用Git clone源代码之后,执行go build命令编译。

接下来运行Remote storage adapter

./remote_storage_adapter --influxdb-url=http://localhost:8086/ --influxdb.database=prometheus --influxdb.retention-policy=autogen

注意:这里Influxdb默认端口是8086,使用的数据库名为prometheus。

配置prometheus资源对象

涉及的配置项解释如下:

  • remoteRead 获取数据的URL
  • remoteWrite 写入数据的URL

修改prometheus资源对象的配置文件,增加:

spec:
  remoteRead:
    - url: "http://localhost:9201/read"
  remoteWrite:
    - url: "http://localhost:9201/write"

注意:9201端口是remote_storage_adapter默认监听的端口。

PS:prometheus原生配置文件的配置方法如下:

# Remote write configuration (for Graphite, OpenTSDB, or InfluxDB).
remote_write:
  - url: "http://localhost:9201/write"

# Remote read configuration (for InfluxDB only at the moment).
remote_read:
  - url: "http://localhost:9201/read"

ServiceMonitor资源资源对象

配置Prometheus从一个Service读取监控信息。

首先配置一个service,用来指定监控信息暴露端口。

kind: Service
apiVersion: v1
metadata:
  name: example-app
  labels:
    app: example-app
spec:
  selector:
    app: example-app
  ports:
  - name: web
    port: 8080

监控信息从这个pod的8080端口暴露。

再创建一个ServiceMonitor:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: example-app
  labels:
    team: frontend
spec:
  selector:
    matchLabels:
      app: example-app
  endpoints:
  - port: web

port这个地方必须使用命名端口。

PodMonitor

配置Prometheus从一个Pod读取监控信息。

注意:目前配置项作用尚未明确,这里给出部分配置项。

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: example-pod-monitor
  namespace: default
  labels:
    app: example
spec:
  podMetricsEndpoints:
  selector:
  podTargetLabels:
  sampleLimit:
  jobLabel:

PrometheusRule

用于配置告警规则。

示例如下:

kind: PrometheusRule
metadata:
labels: 
  prometheus: k8s
  role: alert-rules
name: prometheus-k8s-rules
spec:
  groups:
  - name: k8s.rules
  rules: 
  - alert: KubeletDown
    annotations:
      message: Kubelet has disappeared from Prometheus target discovery.
    expr: |
      absent(up{job="kubelet"} == 1)
    for: 15m
    labels:
      severity: critical

和Ingress配合使用

除了使用NodePort暴露prometheus服务到集群外,我们还可以使用Ingress的方式暴露服务。

Ingress的配置如下所示:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: monitoring
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: prometheus
          servicePort: 9090
        path: /prometheus/(.*)

该Ingress将/prometheus/映射为prometheus这个service。此时可以通过http://hostname/prometheus/访问到Prometheus server。但有个问题,页面的静态资源没法加载。

为了解决这个问题,接下来需要为Prometheus server添加一个context path的配置。

Prometheus对象有一个externalUrl的配置项,它包含了context path的功能,需要配置为完整的对外暴露的URL。如下所示:

apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  name: main
spec:
  replicas: 2
  version: v2.15.2
  externalUrl: http://hostname/prometheus/
  resources:
    requests:
      memory: 400Mi

更详细的使用方式可参考:
https://coreos.com/operators/prometheus/docs/latest/user-guides/exposing-prometheus-and-alertmanager.html

使用示例

https://github.com/coreos/kube-prometheus/blob/master/examples/example-app/

参考文档

https://github.com/coreos/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md

https://coreos.com/operators/prometheus/docs/latest/user-guides/exposing-prometheus-and-alertmanager.html

你可能感兴趣的:(K8s 集群监控之Kube Prometheus(Prometheus Operator))