Prometheus是一个最初在SoundCloud上构建的开源监控系统 。它如今是一个独立的开源项目,为了强调这一点,并说明项目的治理结构,Prometheus 于2016年加入CNCF,做为继Kubernetes以后的第二个托管项目。node
Prometheus系统由多个组件组成,其中许多组件是可选的:git
大多数 Prometheus 组件都是用 Go 编写的,所以很容易构建和部署为静态的二进制文件。github
此图说明prometheus的体系结构及其一些系统组件web
总体流程比较简单,Prometheus 直接接收或者经过中间的 Pushgateway 网关被动获取指标数据,在本地存储全部的获取的指标数据,并对这些数据进行一些规则整理,用来生成一些聚合数据或者报警信息,Grafana 或者其余工具用来可视化这些数据。正则表达式
因为 Prometheus 是 Golang 编写的程序,因此要安装的话也很是简单,只须要将二进制文件下载下来直接执行便可,前往地址:https://prometheus.io/download 下载咱们对应的版本便可。redis
Prometheus 是经过一个 YAML 配置文件来进行启动的,若是咱们使用二进制的方式来启动的话,可使用下面的命令:docker
./prometheus --config.file=prometheus.yml
prometheus.yml配置文件后端
global: scrape_interval: 15s evaluation_interval: 15s rule_files: # - "first.rules" # - "second.rules" scrape_configs: - job_name: prometheus static_configs: - targets: ['localhost:9090']
配置文件中配置的三个模块:global
,rule_files
,和scrape_configs
api
global 模块是prometheus的全局配置
:跨域
rule_files 模块制定了规则所在的位置,prometheus 能够根据这个配置加载规则,用于生成新的时间序列数据或者报警信息,当前咱们没有配置任何规则。
scrape_configs 用于控制 prometheus 监控哪些资源。因为 prometheus 经过 HTTP 的方式来暴露的它自己的监控数据,prometheus 也可以监控自己的健康状况。在默认的配置里有一个单独的 job,叫作prometheus,它采集 prometheus 服务自己的时间序列数据。这个 job 包含了一个单独的、静态配置的目标:监听 localhost 上的9090端口。prometheus 默认会经过目标的/metrics
路径采集 metrics。因此,默认的 job 经过 URL:http://localhost:9090/metrics
采集 metrics。收集到的时间序列包含 prometheus 服务自己的状态和性能。若是咱们还有其余的资源须要监控的话,直接配置在该模块下面就能够了。
这里咱们把prometheus相关的服务都部署在kube-ops这个namespace下
一、咱们把prometheus.yml中部署成ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: prometheus-config namespace: kube-ops data: prometheus.yml: | global: scrape_interval: 15s scrape_timeout: 15s scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090']
二、建立prometheus相关pod资源
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: prometheus namespace: kube-ops labels: app: prometheus spec: template: metadata: labels: app: prometheus spec: containers: - image: prom/prometheus:v2.6.0 name: prometheus imagePullPolicy: IfNotPresent args: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention=7d" - "--web.enable-admin-api" - "--web.enable-lifecycle" ports: - containerPort: 9090 name: http volumeMounts: - mountPath: "/prometheus" subPath: prometheus name: data - mountPath: "/etc/prometheus" name: config resources: requests: cpu: 1000m memory: 2Gi limits: cpu: 1000m memory: 2Gi securityContext: runAsUser: 0 volumes: - name: config configMap: name: prometheus-config - name: data persistentVolumeClaim: claimName: prometheus
storage.tsdb.path
指定了 TSDB 数据的存储路径storage.tsdb.retention
设置了保留多长时间的数据经过web.enable-admin-api
参数能够用来开启对 admin api 的访问权限web.enable-lifecycle
很是重要,用来开启支持热更新的,有了这个参数以后,prometheus.yml 配置文件只要更新了,经过执行http://localhost:9090/-/reload
就会当即生效,因此必定要加上这个参数咱们这里将 prometheus.yml 文件对应的 ConfigMap 对象经过 volume 的形式挂载进了 Pod,这样 ConfigMap 更新后,对应的 Pod 里面的文件也会热更新的,而后咱们再执行上面的 reload 请求,Prometheus 配置就生效了
为了将时间序列数据进行持久化,咱们将数据目录和一个 pvc 对象进行了绑定,因此咱们须要提早建立好这个 pvc 对象(这里咱们使用的storageclass)
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: prometheus namespace: kube-ops spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: "rook-ceph-block"
除了上面的注意事项外,咱们这里还须要配置 rbac 认证,由于咱们须要在 prometheus 中去访问 Kubernetes 的相关信息,因此咱们这里管理了一个名为 prometheus 的 serviceAccount 对象:
apiVersion: v1 kind: ServiceAccount metadata: name: prometheus namespace: kube-ops --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus rules: - apiGroups: - "" resources: - nodes - services - endpoints - pods - nodes/proxy verbs: - get - list - watch - apiGroups: - "" resources: - configmaps - nodes/metrics verbs: - get - nonResourceURLs: - /metrics verbs: - get --- 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: kube-ops
因为咱们要获取的资源信息,在每个 namespace 下面都有可能存在,因此咱们这里使用的是 ClusterRole 的资源对象,值得一提的是咱们这里的权限规则声明中有一个nonResourceURLs
的属性,是用来对非资源型 metrics 进行操做的权限声明。
还有一个要注意的地方是咱们这里必需要添加一个securityContext
的属性,将其中的runAsUser
设置为0,这是由于如今的 prometheus 运行过程当中使用的用户是 nobody,不然会出现下面的permission denied
之类的权限错误:
level=error ts=2018-10-22T14:34:58.632016274Z caller=main.go:617 err="opening storage failed: lock DB directory: open /data/lock: permission denied"
这里咱们还须要一个svc服务,做为外部访问。
apiVersion: v1 kind: Service metadata: name: prometheus namespace: kube-ops labels: app: prometheus spec: selector: app: prometheus type: NodePort ports: - name: web port: 9090 targetPort: http
文件准备完成后咱们可使用如下命令构建
kubectl apply -f .
访问
kubectl get svc -n kube-ops NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE prometheus NodePort 10.111.210.47 <none> 9090:31990/TCP 7d
咱们能够经过任意节点访问31990端口便可访问
目前主要有如下集中方案
Google
开源的容器资源监控和性能分析工具,它是专门为容器而生,自己也支持 Docker 容器,在 Kubernetes 中,咱们不须要单独去安装,cAdvisor 做为 kubelet 内置的一部分程序能够直接使用。不过 kube-state-metrics 和 metrics-server 之间仍是有很大不一样的,两者的主要区别以下:
对于集群的监控通常咱们须要考虑如下几个方面:
这里经过 Prometheus 来采集节点的监控指标数据,能够经过node_exporter来获取,顾名思义,node_exporter 抓哟就是用于采集服务器节点的各类运行指标的,目前 node_exporter 支持几乎全部常见的监控点,好比 conntrack,cpu,diskstats,filesystem,loadavg,meminfo,netstat等,详细的监控点列表能够参考其Github repo。
咱们能够经过 DaemonSet 控制器来部署该服务,这样每个节点都会自动运行一个这样的 Pod,若是咱们从集群中删除或者添加节点后,也会进行自动扩展。
apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: node-exporter namespace: kube-ops labels: name: node-exporter spec: template: metadata: labels: name: node-exporter spec: hostPID: true hostIPC: true hostNetwork: true containers: - name: node-exporter image: prom/node-exporter:v0.17.0 ports: - containerPort: 9100 resources: requests: cpu: 0.15 securityContext: privileged: true args: - --path.procfs - /host/proc - --path.sysfs - /host/sys - --collector.filesystem.ignored-mount-points - '"^/(sys|proc|dev|host|etc)($|/)"' volumeMounts: - name: dev mountPath: /host/dev - name: proc mountPath: /host/proc - name: sys mountPath: /host/sys - name: rootfs mountPath: /rootfs tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule" volumes: - name: proc hostPath: path: /proc - name: dev hostPath: path: /dev - name: sys hostPath: path: /sys - name: rootfs hostPath: path: /
因为咱们要获取到的数据是主机的监控指标数据,而咱们的 node-exporter 是运行在容器中的,因此咱们在 Pod 中须要配置一些 Pod 的安全策略,这里咱们就添加了hostPID: true
、hostIPC: true
、hostNetwork: true
3个策略,用来使用主机的 PID namespace、IPC namespace 以及主机网络,这些 namespace 就是用于容器隔离的关键技术,要注意这里的 namespace 和集群中的 namespace 是两个彻底不相同的概念。
另外咱们还将主机的/dev
、/proc
、/sys
这些目录挂载到容器中,这些由于咱们采集的不少节点数据都是经过这些文件夹下面的文件来获取到的,好比咱们在使用top
命令能够查看当前cpu
使用状况,数据就来源于文件/proc/stat
,使用free
命令能够查看当前内存使用状况,其数据来源是来自/proc/meminfo
文件。
另外因为咱们集群使用的是 kubeadm 搭建的,因此若是但愿 master 节点也一块儿被监控,则须要添加响应的容忍。
建立上面的资源对象便可:
$ kubectl apply -f node-exporter.yaml $ kubectl get pods -n kube-ops -o wide | grep node-exporter node-exporter-48b6g 1/1 Running 0 7d 172.16.138.42 k8s-node02 node-exporter-4swrs 1/1 Running 0 7d 172.16.138.43 k8s-node03 node-exporter-4w2dd 1/1 Running 0 7d 172.16.138.40 k8s-master node-exporter-fcp9x 1/1 Running 0 7d 172.16.138.41 k8s-node01
部署完成后,咱们能够看到在3个节点上都运行了一个 Pod,有的同窗可能会说咱们这里不须要建立一个 Service 吗?咱们应该怎样去获取/metrics
数据呢?咱们上面是否是指定了hostNetwork=true
,因此在每一个节点上就会绑定一个端口 9100,咱们能够经过这个端口去获取到监控指标数据:
因为咱们这里3个节点上面都运行了 node-exporter 程序,若是咱们经过一个 Service 来将数据收集到一块儿用静态配置的方式配置到 Prometheus 去中,就只会显示一条数据,咱们得本身在指标数据中去过滤每一个节点的数据,那么有没有一种方式可让 Prometheus 去自动发现咱们节点的 node-exporter 程序,而且按节点进行分组呢?是有的,就是咱们前面和你们提到过的服务发现。
在 Kubernetes 下,Promethues 经过与 Kubernetes API 集成,目前主要支持5中服务发现模式,分别是:Node、Service、Pod、Endpoints、Ingress。
可是要让 Prometheus 也可以获取到当前集群中的全部节点信息的话,咱们就须要利用 Node 的服务发现模式,一样的,在 prometheus.yml 文件中配置以下的 job 任务便可:
- job_name: "kubernetes-nodes" kubernetes_sd_configs: - role: node relabel_configs: - source_labels: [__address__] regex: '(.*):10250' replacement: '${1}:9100' target_label: __address__ action: replace
- action: labelmap regex: __meta_kubernetes_node_label_(.+)
经过指定kubernetes_sd_configs
的模式为node
,Prometheus 就会自动从 Kubernetes 中发现全部的 node 节点并做为当前 job 监控的目标实例,发现的节点/metrics
接口是默认的 kubelet 的 HTTP 接口。
配置文件说明:
这里就是一个正则表达式,去匹配__address__
,而后将 host 部分保留下来,port 替换成了9100。
由于咱们是经过prometheus 去发现 Node 模式的服务的时候,访问的端口默认是10250,而如今该端口下面已经没有了/metrics
指标数据了,由于咱们是要去配置上面经过node-exporter
抓取到的节点指标数据,而咱们上面是否是指定了hostNetwork=true
,因此在每一个节点上就会绑定一个端口9100,因此咱们应该将这里的10250替换成9100。
这里咱们就须要使用到 Prometheus 提供的relabel_configs
中的replace
能力了,relabel 能够在 Prometheus 采集数据以前,经过Target 实例的 Metadata 信息,动态从新写入 Label 的值。除此以外,咱们还能根据 Target 实例的 Metadata 信息选择是否采集或者忽略该 Target 实例。好比咱们这里就能够去匹配__address__
这个 Label 标签,而后替换掉其中的端口。
经过labelmap
这个属性来将 Kubernetes 的 Label 标签添加为 Prometheus 的指标标签,添加了一个 action 为labelmap
,正则表达式是__meta_kubernetes_node_label_(.+)
的配置,这里的意思就是表达式中匹配都的数据也添加到指标数据的 Label 标签中去。
对于 kubernetes_sd_configs 下面可用的标签以下:
prometheus 的 ConfigMap 更新完成后,一样的咱们执行 reload 操做,让配置生效:
$ kubectl delete -f prome-cm.yaml $ kubectl create -f prome-cm.yaml $ kubectl get svc -n kube-ops $ curl -X POST "http://10.111.210.47:9090/-/reload"
配置生效后,咱们再去 prometheus 的 dashboard 中查看 Targets 是否可以正常抓取数据,访问任意节点IP:30358:
另外因为 kubelet 也自带了一些监控指标数据,因此咱们这里也把 kubelet 的监控任务也一并配置上:
- job_name: 'kubernetes-kubelet' kubernetes_sd_configs: - role: node scheme: https tls_config: ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt insecure_skip_verify: true bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token relabel_configs: - action: labelmap regex: __meta_kubernetes_node_label_(.+)
上面的配置和咱们以前配置 node-exporter 的时候几乎是同样的,区别是咱们这里使用了 https 的协议,另外须要注意的是配置了 ca.cart 和 token 这两个文件,这两个文件是 Pod 启动后自动注入进来的,经过这两个文件咱们能够在 Pod 中访问 apiserver。
如今咱们再去更新下配置文件,执行 reload 操做,让配置生效,而后访问 Prometheus 的 Dashboard 查看 Targets 路径:
咱们这里经过一个redis-exporter的服务来监控 redis 服务,对于这类应用,咱们通常会以 sidecar 的形式和主应用部署在同一个 Pod 中,好比咱们这里来部署一个 redis 应用,并用 redis-exporter 的方式来采集监控数据供 Prometheus 使用。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: redis namespace: kube-ops spec: template: metadata: annotations: prometheus.io/scrape: "true" prometheus.io/port: "9121" labels: app: redis spec: containers: - name: redis image: redis:4 resources: requests: cpu: 100m memory: 100Mi ports: - containerPort: 6379 - name: redis-exporter image: oliver006/redis_exporter:latest resources: requests: cpu: 100m memory: 100Mi ports: - containerPort: 9121 --- kind: Service apiVersion: v1 metadata: name: redis namespace: kube-ops spec: selector: app: redis ports: - name: redis port: 6379 targetPort: 6379 - name: prom port: 9121 targetPort: 9121
能够看到上面咱们在 redis 这个 Pod 中包含了两个容器,一个就是 redis 自己的主应用,另一个容器就是 redis_exporter。如今直接建立上面的应用:
$ kubectl create -f prome-redis.yaml deployment.extensions "redis" created service "redis" created
咱们能够经过 9121 端口来校验是否可以采集到数据:
$ curl 10.104.131.44:9121/metrics # HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 0 go_gc_duration_seconds{quantile="0.25"} 0 go_gc_duration_seconds{quantile="0.5"} 0 go_gc_duration_seconds{quantile="0.75"} 0 go_gc_duration_seconds{quantile="1"} 0 go_gc_duration_seconds_sum 0 go_gc_duration_seconds_count 0 ...... # HELP redis_used_cpu_user_children used_cpu_user_childrenmetric # TYPE redis_used_cpu_user_children gauge redis_used_cpu_user_children{addr="redis://localhost:6379",alias=""} 0
一样的,如今咱们只须要更新 Prometheus 的配置文件:
- job_name: 'redis' static_configs: - targets: ['redis:9121']
配置文件更新后,从新加载:
$ kubectl delete -f prome-cm.yaml $ kubectl create -f prome-cm.yaml $ curl -X POST "http://10.111.210.47:9090/-/reload"
前面咱们使用 Prometheus 采集了 Kubernetes 集群中的一些监控数据指标,咱们也尝试使用promQL
语句查询出了一些数据,而且在 Prometheus 的 Dashboard 中进行了展现,可是明显能够感受到 Prometheus 的图表功能相对较弱,因此通常状况下咱们会一个第三方的工具来展现这些数据,今天咱们要和你们使用到的就是grafana
。
grafana 是一个可视化面板,有着很是漂亮的图表和布局展现,功能齐全的度量仪表盘和图形编辑器,支持 Graphite、zabbix、InfluxDB、Prometheus、OpenTSDB、Elasticsearch 等做为数据源,比 Prometheus 自带的图表展现功能强大太多,更加灵活,有丰富的插件,功能更增强大。
接下来咱们就来直接安装,一样的,咱们将 grafana 安装到 Kubernetes 集群中,第一步一样是去查看 grafana 的 docker 镜像的介绍,咱们能够在 dockerhub 上去搜索,也能够在官网去查看相关资料,镜像地址以下:https://hub.docker.com/r/grafana/grafana/,咱们能够看到介绍中运行 grafana 容器的命令很是简单:
$ docker run -d --name=grafana -p 3000:3000 grafana/grafana
咱们将部署grafana的pod资源
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: grafana namespace: kube-ops labels: app: grafana spec: revisionHistoryLimit: 10 template: metadata: labels: app: grafana spec: containers: - name: grafana image: grafana/grafana:5.4.2 imagePullPolicy: IfNotPresent ports: - containerPort: 3000 name: grafana env: - name: GF_SECURITY_ADMIN_USER value: admin - name: GF_SECURITY_ADMIN_PASSWORD value: admin321 readinessProbe: failureThreshold: 10 httpGet: path: /api/health port: 3000 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 30 livenessProbe: failureThreshold: 3 httpGet: path: /api/health port: 3000 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: limits: cpu: 100m memory: 256Mi requests: cpu: 100m memory: 256Mi volumeMounts: - mountPath: /var/lib/grafana subPath: grafana name: storage securityContext: fsGroup: 472 runAsUser: 472 volumes: - name: storage persistentVolumeClaim: claimName: grafana
咱们使用了最新的镜像grafana/grafana:5.4.2
,而后添加了监控检查、资源声明,另外两个比较重要的环境变量GF_SECURITY_ADMIN_USER
和GF_SECURITY_ADMIN_PASSWORD
,用来配置 grafana 的管理员用户和密码的,因为 grafana 将 dashboard、插件这些数据保存在/var/lib/grafana
这个目录下面的,因此咱们这里若是须要作数据持久化的话,就须要针对这个目录进行 volume 挂载声明,其余的和咱们以前的 Deployment 没什么区别,因为上面咱们刚刚提到的 Changelog 中 grafana 的 userid 和 groupid 有所变化,因此咱们这里须要增长一个securityContext
的声明来进行声明。
固然若是要使用一个 pvc 对象来持久化数据,咱们就须要添加一个可用的 pv 供 pvc 绑定使用:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: grafana namespace: kube-ops annotations: volume.beta.kubernetes.io/storage-class: "rook-ceph-block" spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: "rook-ceph-block"
最后,咱们须要对外暴露 grafana 这个服务,因此咱们须要一个对应的 Service 对象,固然用 NodePort 或者再创建一个 ingress 对象都是可行的:
apiVersion: v1 kind: Service metadata: name: grafana namespace: kube-ops labels: app: grafana spec: type: NodePort ports: - port: 3000 selector: app: grafana
如今咱们直接建立上面的这些资源对象:
$ kubectl create -f .
这个时候咱们能够查看 Service 对象启动的端口:
kubectl get svc -n kube-ops NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE grafana NodePort 10.97.81.127 <none> 3000:30489/TCP 5d prometheus NodePort 10.111.210.47 <none> 9090:31990/TCP 7d
这里咱们看到grafana启动端口是30489。咱们能够经过任意节点+30489访问
因为上面咱们配置了管理员的,因此第一次打开的时候会跳转到登陆界面,而后就能够用上面咱们配置的两个环境变量的值来进行登陆了。
接下来点击Add data source
进入添加数据源界面。
咱们这个地方配置的数据源是 Prometheus,因此选择这个 Type 便可,给改数据源添加一个 name:prometheus,最主要的是下面HTTP
区域是配置数据源的访问模式。
访问模式是用来控制如何处理对数据源的请求的:
因为咱们这个地方 Prometheus 经过 NodePort 的方式的对外暴露的服务,因此咱们这个地方是否是可使用浏览器访问模式直接访问 Prometheus 的外网地址,可是这种方式显然不是最好的,至关于走的是外网,而咱们这里 Prometheus 和 Grafana 都处于 kube-ops 这同一个 namespace 下面,是否是在集群内部直接经过 DNS 的形式就能够访问了,并且还都是走的内网流量,因此咱们这里用服务器访问模式显然更好,数据源地址:http://prometheus:9090
(由于在同一个 namespace 下面因此直接用 Service 名也能够),而后其余的配置信息就根据实际状况了,好比 Auth 认证,咱们这里没有,因此跳过便可,点击最下方的Save & Test
提示成功证实咱们的数据源配置正确:
数据源添加完成后,就能够来添加 Dashboard 了。
配置Dashboard
一样,切换到主页,咱们能够根据本身的需求手动新建一个 Dashboard,除此以外,grafana 的官方网站上还有不少公共的 Dashboard 能够供咱们使用,咱们这里可使用Kubernetes cluster monitoring (via Prometheus)(dashboard id 为162)这个 Dashboard 来展现 Kubernetes 集群的监控信息,在左侧侧边栏 Create 中点击import
导入:
接下来输入162号导入(我如今已经导入,因此报一存在)
须要注意的是在执行上面的 import 以前要记得选择咱们的prometheus
这个名字的数据源,执行import
操做,就能够进入到 dashboard 页面:
若是这里数据没出现有两个缘由:
一、时间选择UTC时间
查询语句不正确
例如点击Edit的,咱们能够看到查询语句
(sum(node_memory_MemTotal) - sum(node_memory_MemFree_bytes+node_memory_Buffers_bytes+node_memory_Cached) ) / sum(node_memory_MemTotal) * 100
这就是咱们以前在 Prometheus 里面查询的promQL
语句,咱们能够将上面的查询语句复制到 Prometheus 的 Graph 页面进行查询,其实能够预想到是没有对应的数据的,由于咱们用node_exporter
采集到的数据指标不是node_memory_MemTotal
关键字,而是node_memory_MemTotal_bytes
,将上面的promQL
语句作相应的更改:
接下来按照此方法,依次修改Dashboard中的其余图标。
除此以外,咱们也能够前往 grafana dashboard 的页面去搜索其余的关于 Kubernetes 的监控页面,地址:https://grafana.com/dashboards,好比id 为747和741的这两个 dashboard。