目录
引言
在云原生时代,Kubernetes(简称K8s)已经成为了容器编排的事实标准。然而,如何监控这个庞大的集群,确保其稳定运行,是每个运维人员都需要面对的问题。Prometheus和Grafana作为开源的监控和可视化工具,被广泛应用于Kubernetes集群的监控中。本文将详细介绍如何在Kubernetes集群中部署Prometheus和Grafana,以实现对集群的全面监控。
一、环境准备
主机名 | IP地址 | 主机类型 | 资源配置 |
master01 | 192.168.83.30 | 控制节点 | 4C4G |
node01 | 192.168.83.40 | 工作节点1 | 4C4G |
node02 | 192.168.83.50 | 工作节点2 | 4C4G |
二、部署node-exporter
(一)创建命名空间
创建监控namespace
[root@master01 ~]#kubectl create ns monitor-sa
namespace/monitor-sa created
[root@master01 ~]#kubectl get ns monitor-sa
NAME STATUS AGE
monitor-sa Active 9s
(二)部署node-exporter
1.获取镜像
docker pull的方式下载镜像,可以从hub.docker.com下载,或者使用国内的镜像替代
[root@master01 images]#ls node-exporter.tar
node-exporter.tar
[root@master01 images]#docker load -i node-exporter.tar
ad68498f8d86: Loading layer [==============================>] 4.628MB/4.628MB
ad8512dce2a7: Loading layer [==============================>] 2.781MB/2.781MB
cc1adb06ef21: Loading layer [==============================>] 16.9MB/16.9MB
Loaded image: prom/node-exporter:v0.16.0
'----------------------------------------------------------------------------'
[root@node01 images]#ls node-exporter.tar
node-exporter.tar
[root@node01 images]#docker load -i node-exporter.tar
ad68498f8d86: Loading layer [==============================>] 4.628MB/4.628MB
ad8512dce2a7: Loading layer [==============================>] 2.781MB/2.781MB
cc1adb06ef21: Loading layer [==============================>] 16.9MB/16.9MB
Loaded image: prom/node-exporter:v0.16.0
'----------------------------------------------------------------------------'
[root@node02 images]#ls node-exporter.tar
node-exporter.tar
[root@node02 images]#docker load -i node-exporter.tar
ad68498f8d86: Loading layer [==============================>] 4.628MB/4.628MB
ad8512dce2a7: Loading layer [==============================>] 2.781MB/2.781MB
cc1adb06ef21: Loading layer [==============================>] 16.9MB/16.9MB
Loaded image: prom/node-exporter:v0.16.0
[root@node02 images]#docker images|grep prom/node-exporter
prom/node-exporter v0.16.0 188af75e2de0 6 years ago 22.9MB
2.定义yaml文件
使用yaml文件,以DaemonSet副本控制器,在每个节点上部署node-exporter
[root@master01 prometheus]#vim node-export.yaml
---
apiVersion: apps/v1
kind: DaemonSet #可以保证 k8s 集群的每个节点都运行完全一样的 pod
metadata:
name: node-exporter
namespace: monitor-sa
labels:
name: node-exporter
spec:
selector:
matchLabels:
name: node-exporter
template:
metadata:
labels:
name: node-exporter
spec:
hostPID: true #允许Pod使用宿主机的 PID
hostIPC: true #允许Pod使用宿主机的IPC
hostNetwork: true #允许Pod使用宿主机的网络命名空间
containers:
- name: node-exporter
image: prom/node-exporter:v0.16.0 #指定镜像
ports:
- containerPort: 9100 #指定容器暴露端口
resources:
requests:
cpu: 0.15 #这个容器运行至少需要0.15核cpu
securityContext:
privileged: true #开启特权模式
args: #传递给容器的命令行参数
- --path.procfs
- /host/proc
#通知node-exporter在哪里找到宿主机的/proc文件系统。
#由于node-exporter运行在容器中,不能直接访问宿主机的/proc文件系统,需要通过挂载来访问它
- --path.sysfs
- /host/sys
#类似地,这个参数告诉node-exporter在哪里找到宿主机的/sys文件系统
- --collector.filesystem.ignored-mount-points
- '"^/(sys|proc|dev|host|etc)($|/)"'
#这个参数指定以sys等开头文件系统挂载点,被node-exporter的文件系统收集器忽略,
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"
#定义了DaemonSet容忍了标记为node-role.kubernetes.io/master的节点上的污点
volumes: #定义了 Pod 中要使用的卷
- name: proc
hostPath:
path: /proc
- name: dev
hostPath:
path: /dev
- name: sys
hostPath:
path: /sys
- name: rootfs
hostPath:
path: /
3.创建服务
[root@master01 prometheus]#kubectl apply -f node-export.yaml
daemonset.apps/node-exporter created
[root@master01 prometheus]#kubectl get pod -n monitor-sa -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-exporter-dvl2v 1/1 Running 0 24s 192.168.83.30 master01 <none> <none>
node-exporter-nhk4t 1/1 Running 0 24s 192.168.83.40 node01 <none> <none>
node-exporter-rs8pd 1/1 Running 0 24s 192.168.83.50 node02 <none> <none>
4.查看监控数据
node-exporter 默认的监听端口是 9100,可以执行 curl http://主机ip:9100/metrics 获取到主机的所有监控数据
比如查看cpu的数据
curl -Ls http://192.168.83.30:9100/metrics | grep node_cpu_seconds
[root@master01 prometheus]#curl -Ls http://192.168.83.30:9100/metrics | grep node_cpu_seconds
# HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 6110.13
node_cpu_seconds_total{cpu="0",mode="iowait"} 5.72
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 0.05
node_cpu_seconds_total{cpu="0",mode="softirq"} 33.77
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 175.56
node_cpu_seconds_total{cpu="0",mode="user"} 164.87
node_cpu_seconds_total{cpu="1",mode="idle"} 6129.08
node_cpu_seconds_total{cpu="1",mode="iowait"} 4.52
node_cpu_seconds_total{cpu="1",mode="irq"} 0
node_cpu_seconds_total{cpu="1",mode="nice"} 0.05
node_cpu_seconds_total{cpu="1",mode="softirq"} 28.48
node_cpu_seconds_total{cpu="1",mode="steal"} 0
node_cpu_seconds_total{cpu="1",mode="system"} 181.28
node_cpu_seconds_total{cpu="1",mode="user"} 163.54
node_cpu_seconds_total{cpu="2",mode="idle"} 6126.05
node_cpu_seconds_total{cpu="2",mode="iowait"} 4.47
node_cpu_seconds_total{cpu="2",mode="irq"} 0
node_cpu_seconds_total{cpu="2",mode="nice"} 0
node_cpu_seconds_total{cpu="2",mode="softirq"} 38.63
node_cpu_seconds_total{cpu="2",mode="steal"} 0
node_cpu_seconds_total{cpu="2",mode="system"} 175.99
node_cpu_seconds_total{cpu="2",mode="user"} 166.63
node_cpu_seconds_total{cpu="3",mode="idle"} 6132.87
node_cpu_seconds_total{cpu="3",mode="iowait"} 2.5
node_cpu_seconds_total{cpu="3",mode="irq"} 0
node_cpu_seconds_total{cpu="3",mode="nice"} 0
node_cpu_seconds_total{cpu="3",mode="softirq"} 29.81
node_cpu_seconds_total{cpu="3",mode="steal"} 0
node_cpu_seconds_total{cpu="3",mode="system"} 183.06
node_cpu_seconds_total{cpu="3",mode="user"} 167.03
三、部署Prometheus
(一)创建账号并授权
创建一个管理账号,并绑定admin用户,admin用户拥有所有资源的所有权限
[root@master01 prometheus]#kubectl create serviceaccount monitor -n monitor-sa
serviceaccount/monitor created
[root@master01 prometheus]#kubectl create clusterrolebinding monitor-clusterrolebinding -n monitor-sa --clusterrole=cluster-admin --serviceaccount=monitor-sa:monitor
clusterrolebinding.rbac.authorization.k8s.io/monitor-clusterrolebinding created
#指定管理的命名空间
(二)创建configmap存储卷
在ConfigMap中,需要定义Prometheus的全局配置以及数据采集规则。数据采集规则包括从Kubernetes API Server、node-exporter等组件中收集指标数据的规则
[root@master01 prometheus]#cat prometheus-cfg.yaml
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: prometheus
name: prometheus-config
namespace: monitor-sa
data:
prometheus.yml: | #Prometheus 配置文件的内容
#-----------------------------全局设置-------------------------------------------
global: #指定prometheus的全局配置,比如采集间隔,抓取超时时间等
scrape_interval: 15s #采集目标主机监控数据的时间间隔,默认为1m
scrape_timeout: 10s #数据采集超时时间,默认10s
evaluation_interval: 1m #触发告警生成alert的时间间隔,默认是1m
scrape_configs: #配置数据源,称为target,每个target用job_name命名。
#-------------------第一个服务发现:监控 Kubernetes 集群中的节点------------------------
- job_name: 'kubernetes-node'
kubernetes_sd_configs: #指定的是k8s的服务发现
- role: node #使用node角色,它使用默认的kubelet提供的http端口来发现集群中每个node节点
relabel_configs: #重新标记,修改目标地址
- source_labels: [__address__] #配置的原始标签,匹配地址
regex: '(.*):10250' #匹配带有10250端口的url
replacement: '${1}:9100' #把匹配到的ip:10250的ip保留,类似与sed的后向引用
target_label: __address__ #新生成的url是${1}获取到的ip:9100
action: replace
#动作替换,从默认的kubelet端口(10250)更改为Prometheus Node Exporter 的端口(9100)
- action: labelmap
regex: __meta_kubernetes_node_label_(.+) #匹配到下面正则表达式的标签会被保留,如果不做regex正则的话,默认只是会显示instance标签
#--------------第二个服务发现:监控 Kubernetes 集群中每个节点的 cAdvisor-----------------
#抓取cAdvisor数据,是获取kubelet上/metrics/cadvisor接口数据来获取容器的资源使用情况
- job_name: 'kubernetes-node-cadvisor'
kubernetes_sd_configs:
- role: node
scheme: https #定义了与cAdvisor服务通信时使用HTTPS协议
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt #CA证书文件的路径
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token #指定了包含用于与Kubernetes API服务器进行身份验证的Bearer令牌的文件路径
relabel_configs:
- action: labelmap #把匹配到的标签保留
regex: __meta_kubernetes_node_label_(.+) #保留匹配到的具有__meta_kubernetes_node_label的标签
- target_label: __address__ #获取到的地址:__address__="192.168.80.20:10250"
replacement: kubernetes.default.svc:443 #把获取到的地址替换成新的地址kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+) #把原始标签中__meta_kubernetes_node_name值匹配到
target_label: __metrics_path__ #获取__metrics_path__对应的值
replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
#把metrics替换成新的值api/v1/nodes/k8s-master1/proxy/metrics/cadvisor
#${1}是__meta_kubernetes_node_name获取到的值
#新的url就是https://kubernetes.default.svc:443/api/v1/nodes/k8s-master1/proxy/metrics/cadvisor
#------------------第三个服务发现:监控Kubernetes API服务器---------------------------
- job_name: 'kubernetes-apiserver'
kubernetes_sd_configs:
- role: endpoints #使用k8s中的endpoint服务发现,采集apiserver6443端口获取到的数据
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
#[endpoint这个对象的名称空间,endpoint对象的服务名,exnpoint的端口名称]
action: keep #采集满足条件的实例,其他实例不采集
regex: default;kubernetes;https #正则匹配到的默认空间下的service名字是kubernetes,协议是https的endpoint类型保留下来
#-----------------------------第四个服务发现--------------------------------------
- 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
#重新打标仅抓取到的具有"prometheus.io/scrape: true"的annotation的端点
#意思是说如果某个service具有prometheus.io/scrape = true的annotation声明则抓取
#annotation本身也是键值结构, 所以这里的源标签设置为键
#而regex设置值true,当值匹配到regex设定的内容时则执行keep动作也就是保留,其余则丢弃。
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
#重新设置scheme,匹配源标签__meta_kubernetes_service_annotation_prometheus_io_scheme
#也就是prometheus.io/scheme annotation
#如果源标签的值匹配到regex,则把值替换为__scheme__对应的值。
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
#应用中自定义暴露的指标,也许你暴露的API接口不是/metrics这个路径,
#那么你可以在这个POD对应的service中做一个 "prometheus.io/path = /mymetrics" 声明,
#上面的意思就是把你声明的这个路径赋值给__metrics_path__,
#其实就是让prometheus来获取自定义应用暴露的metrices的具体路径,
#不过这里写的要和service中做好约定,
#如果service中这样写 prometheus.io/app-metrics-path: '/metrics'
#那么这里写__meta_kubernetes_service_annotation_prometheus_io_app_metrics_path
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
#暴露自定义的应用的端口,就是把地址和你在service中定义的 "prometheus.io/port = <port>"
#声明做一个拼接, 然后赋值给__address__,这样prometheus就能获取自定义应用的端口,
#然后通过这个端口再结合__metrics_path__来获取指标,
#如果__metrics_path__值不是默认的/metrics那么就要使用上面的标签替换来获取真正暴露的具体路径
- action: labelmap #保留下面匹配到的标签
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace #替换__meta_kubernetes_namespace变成kubernetes_namespace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
创建服务
[root@master01 prometheus]#kubectl apply -f prometheus-cfg.yaml
configmap/prometheus-config created
[root@master01 prometheus]#kubectl get configmaps -n monitor-sa
NAME DATA AGE
kube-root-ca.crt 1 26h
prometheus-config 1 77s
(三)部署prometheus
通过 deployment 部署prometheus
将 prometheus 调度到node1节点,在 node1 节点创建 prometheus 数据存储目录
首先在节点上预加载镜像,防止因为网络问题,导致镜像加载失败
或者可以使用国内的镜像代替
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/prometheus:v2.30.3
[root@node01 images]#ls prometheus.tar
prometheus.tar
[root@node01 images]#docker load -i prometheus.tar
6a749002dd6a: Loading layer [==================================================>] 1.338MB/1.338MB
5f70bf18a086: Loading layer [==================================================>] 1.024kB/1.024kB
1692ded805c8: Loading layer [==================================================>] 2.629MB/2.629MB
035489d93827: Loading layer [==================================================>] 66.18MB/66.18MB
8b6ef3a2ab2c: Loading layer [==================================================>] 44.5MB/44.5MB
ff98586f6325: Loading layer [==================================================>] 3.584kB/3.584kB
017a13aba9f4: Loading layer [==================================================>] 12.8kB/12.8kB
4d04d79bb1a5: Loading layer [==================================================>] 27.65kB/27.65kB
75f6c078fa6b: Loading layer [==================================================&g