安装

架构

image.png

兼容性

kube-prometheus stackKubernetes 1.18Kubernetes 1.19Kubernetes 1.20Kubernetes 1.21
release-0.5
release-0.6
release-0.7
release-0.8
HEAD

配置存储

可修改的配置见

manifests/setup/prometheus-operator-0prometheusCustomResourceDefinition.yaml
或
https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#prometheusspec
或
https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/custom-configuration.md

vim prometheus-prometheus.yaml

cat prometheus-prometheus.yaml 
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
  labels:
    app.kubernetes.io/component: prometheus
    app.kubernetes.io/name: prometheus
    app.kubernetes.io/part-of: kube-prometheus
    app.kubernetes.io/version: 2.26.0
    prometheus: k8s
  name: k8s
  namespace: monitoring
spec:
  retention: 30d  # 配置日志存储时间
  retentionSize: 4GB # 配置日志存储大小
  alerting:
    alertmanagers:
    - apiVersion: v2
      name: alertmanager-main
      namespace: monitoring
      port: web
  externalLabels: {}
  image: quay.io/prometheus/prometheus:v2.26.0
  nodeSelector:
    kubernetes.io/os: linux
  podMetadata:
    labels:
      app.kubernetes.io/component: prometheus
      app.kubernetes.io/name: prometheus
      app.kubernetes.io/part-of: kube-prometheus
      app.kubernetes.io/version: 2.26.0
  podMonitorNamespaceSelector: {}
  podMonitorSelector: {}
  probeNamespaceSelector: {}
  probeSelector: {}
  replicas: 1 
  resources:
    requests:
      memory: 400Mi
  ruleSelector:
    matchLabels:
      prometheus: k8s
      role: alert-rules
  securityContext:
    fsGroup: 2000
    runAsNonRoot: true
    runAsUser: 1000
  serviceAccountName: prometheus-k8s
  serviceMonitorNamespaceSelector: {}
  serviceMonitorSelector: {}
  version: 2.26.0
  storage:
    volumeClaimTemplate:
      spec:
        storageClassName: csi-rbd-sc
        resources:
          requests:
            storage: 5Gi

安装

kubectl create -f manifests/setup
until kubectl get servicemonitors --all-namespaces ; do date; sleep 1; echo ""; done
kubectl create -f manifests/

删除

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

暴露 Prometheus 和 Grafana 端口

将下面 service 的 ClusterIP 改为 NodePort

kubectl edit svc prometheus-k8s -n monitoring
kubectl edit svc grafana -n monitoring

自定义 Kube-Prometheus 监控项

除了 Kubernetes 集群中的一些资源对象、节点以及组件需要监控,有的时候我们可能还需要根据实际的业务需求去添加自定义的监控项,添加一个自定义监控的步骤也是非常简单的。

  • 第一步:建立一个 ServiceMonitor 对象,用于 Prometheus 添加监控项;
  • 第二步:为 ServiceMonitor 对象关联 metrics 数据接口的一个 Service 对象;
  • 第三步:确保 Service 对象可以正确获取到 metrics 数据。

接下来我们就来看看如何添加 Etcd 集群的监控。无论是 Kubernetes 集群外的还是使用 Kubeadm 安装在集群内部的 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/kubernetes/ssl/ca.pem #证书路径 (Pod里的路径)
      certFile: /etc/kubernetes/ssl/etcd.pem
      keyFile: /etc/kubernetes/ssl/etcd-key.pem
      insecureSkipVerify: true
  selector:
    matchLabels:
      k8s-app: etcd
  namespaceSelector:
    matchNames:
    - kube-system

上面这个文件我们匹配 Kube-system 这个命名空间下面具有 k8s-app=etcd 这个label标签的Service,job label用于检索job任务名称的标签。由于证书 serverName 和 etcd 中签发的证书可能不匹配,所以添加了 insecureSkipVerify=true 将不再对服务端的证书进行校验。接下来我们直接创建这个ServiceMonitor:

# 创建资源文件
kubectl apply -f prometheus-serviceMonitorEtcd.yaml

# 查看servicemonitors资源
kubectl get servicemonitors -n monitoring |grep etcd

image.png

Service 和 Endpoints

我们需要定义一个 Service 对象和一个 Endpoints,对应资源文件如下。
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

prometheus-EtcdServiceEnpoints.yaml

apiVersion: v1
kind: Endpoints
metadata:
  name: etcd-k8s
  namespace: kube-system
  labels:
    k8s-app: etcd
subsets:
- addresses:
  - ip: 172.16.230.51     #etcd节点名称
    #nodeName: etcd1     #kubelet名称 (kubectl get node)显示的名称
  - ip: 172.16.230.52
    #nodeName: etcd2
  - ip: 172.16.230.53
    #nodeName: etcd3
  ports:
  - name: port
    port: 2379
    protocol: TCP

然后我们直接创建上面的 Service 对象和 Endpoints 对象:

kubectl apply -f  prometheus-EtcdService.yaml
kubectl apply -f  prometheus-EtcdServiceEnpoints.yaml

查看ETCD状态
kubectl describe svc -n kube-system etcd-k8s

创建完成后,稍等一会我们可以去Prometheus 里面查看targets,便会出现etcd监控信息:
image.png

如果提示ip:2379 connection refused,首先检查本地Telnet 是否正常,在检查etcd配置文件是否是监听0.0.0.0:2379。

数据采集完成后,接下来可以在grafana中导入dashboard。这里我们可以导入 :https://grafana.com/grafana/dashboards/3070;还可以导入中文版ETCD集群插件:https://grafana.com/grafana/dashboards/9733;

Grafana数据持久化

前面我们介绍了关于prometheus的数据持久化、但是没有介绍如何针对Grafana做数据持久化;如果Grafana不做数据持久化、那么服务重启以后,Grafana里面配置的Dashboard、账号密码等信息将会丢失;所以Grafana做数据持久化也是很有必要的。

原始的数据是以 emptyDir 形式存放在pod里面,生命周期与pod相同;出现问题时,容器重启,在Grafana里面设置的数据就全部消失了。

volumeMounts:
  - mountPath: /var/lib/grafana
    name: grafana-storage
    readOnly: false
...
volumes:
- emptyDir: {}
  name: grafana-storage

从上图我们可以看出Grafana将dashboard、插件这些数据保存在/var/lib/grafana这个目录下面。做持久化的话,就需要对这个目录进行volume挂载声明。

我们把emptyDir修改为pvc方式:

volumes:
- name: grafana-storage
  persistentVolumeClaim:
    claimName: grafana

如果要使用一个 pvc 对象来持久化数据,我们就需要添加一个可用的 pv 供 pvc 绑定使用,grafana-volume.yaml内容如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: grafana
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    server: 172.16.200.10
    path: /mnt/lv/k8s
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana
  namespace: monitoring
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

然后我们直接创建上面的PV和PVC、更新 grafana-deployment.yaml 文件即可:

kubectl apply -f grafana-volume.yaml 
kubectl apply -f grafana-deployment.yaml

创建完成以后我们查看Pod状态,我们发现Pod状态一直是 CrashLoopBackOff 没有正常启动,我们再看一下这个 Pod 的日志,错误信息如下:

mkdir: cannot create directory '/var/lib/grafana/plugins': Permission denied

这个错误是 Grafana 5.1版本以后才会出现的。错误的原因很明显,就是 /var/lib/grafana 目录的权限不够。在 `` 中有这样一个属性:

securityContext: 
  runAsNonRoot: true 
  runAsUser: 65534

我们查看一下65534是哪个用户:

cat /etc/passwd | grep 65534

所以,我们只需要把 /mnt/lv/k8s 目录的用户改为 nfsnobody 就可以了。当然把属性改为 777 也没问题:

chown nfsnobody /mnt/lv/k8s

把刚才出错的那个 Pod 删除,新的 Grafana Pod 就成功启动了。然后就可以添加 Dashboard 了,现在Pod 重建也不会丢失数据了。

参考

https://www.cnblogs.com/fengjian2016/p/13064193.html