k8s-Prometheus监控
对于Kubernetes而言,我们可以把当中所有的资源分为几类:
- 基础设施层(Node):集群节点,为整个集群和应用提供运行时资源
- 容器基础设施(Container):为应用提供运行时环境
- 用户应用(Pod):Pod中会包含一组容器,它们一起工作,并且对外提供一个(或者一组)功能
- 内部服务负载均衡(Service):在集群内,通过Service在集群暴露应用功能,集群内应用和应用之间访问时提供内部的负载均衡
- 外部访问入口(Ingress):通过Ingress提供集群外的访问入口,从而可以使外部客户端能够访问到部署在Kubernetes集群内的服务
因此,如果要构建一个完整的监控体系,我们应该考虑,以下5个方面:
- 集群节点状态监控:从集群中各节点的kubelet服务获取节点的基本运行状态;
- 集群节点资源用量监控:通过Daemonset的形式在集群中各个节点部署Node Exporter采集节点的资源使用情况;
- 节点中运行的容器监控:通过各个节点中kubelet内置的cAdvisor中获取个节点中所有容器的运行状态和资源使用情况;
- 如果在集群中部署的应用程序本身内置了对Prometheus的监控支持,那么我们还应该找到相应的Pod实例,并从该Pod实例中获取其内部运行状态的监控指标。
- 对k8s本身的组件做监控:apiserver、scheduler、controller-manager、kubelet、kube-proxy
node-exporter组件安装和配置
机器规划:
我的实验环境使用的k8s集群是2个master节点和1个node节点
master节点的机器ip是192.168.1.180/181,主机名是master01/02
node节点的机器ip是192.168.1.182,主机名是onode01
node-exporter介绍?
node-exporter可以采集机器(物理机、虚拟机、云主机等)的监控指标数据,能够采集到的指标包括CPU, 内存,磁盘,网络,文件数等信息。
安装node-exporter
#node/master节点都安装
[root@node01 ~]# docker pull prom/node-exporter
[root@master01 Prometheus]# kubectl create ns monitor-sa namespace/monitor-sa created
[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-c9hgh 1/1 Running 0 7m48s 192.168.1.180 master01 <none> <none> node-exporter-kbwjj 1/1 Running 0 7m48s 192.168.1.182 node01 <none> <none> node-exporter-vtnc6 1/1 Running 0 7m48s 192.168.1.181 master02 <none> <none>
node-exporter的文件
[root@master01 Prometheus]# cat 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 #容器使用宿主机的资源 hostIPC: true #容器使用宿主机的资源 hostNetwork: true #容器使用宿主机的资源 # hostNetwork、hostIPC、hostPID都为True时,表示这个Pod里的所有容器,会直接使用宿主机的网络,直接与宿主机进行IPC(进程间通信)通信,可以看到宿主机里正在运行的所有进程。加入了hostNetwork:true会直接将我们的宿主机的9100端口映射出来,从而不需要创建service 在我们的宿主机上就会有一个9100的端口 containers: - name: node-exporter image: prom/node-exporter:v1.2.2 imagePullPolicy: IfNotPresent ports: - containerPort: 9100 resources: requests: cpu: 0.15 #这个容器运行至少需要0.15核cpu securityContext: privileged: true #开启特权模式 args: - --path.procfs #配置挂载宿主机(node节点)的路径 - /host/proc - --path.sysfs #配置挂载宿主机(node节点)的路径 - /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 #将主机/dev、/proc、/sys这些目录挂在到容器中,这是因为我们采集的很多节点数据都是通过这些文件来获取系统信息的。 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采集数据
[root@master01 Prometheus]# curl 192.168.1.180:9100/metrics
#node-export默认的监听端口是9100,可以看到当前主机获取到的所有监控数据
[root@master01 Prometheus]# curl 192.168.1.180:9100/metrics | | grep node_cpu_seconds
#HELP:解释当前指标的含义,上面表示在每种模式下node节点的cpu花费的时间,以s为单位 #TYPE:说明当前指标的数据类型,上面是counter类型 node_cpu_seconds_total{cpu="0",mode="idle"} 453223.39 node_cpu_seconds_total{cpu="0",mode="iowait"} 58.95 node_cpu_seconds_total{cpu="0",mode="irq"} 0 node_cpu_seconds_total{cpu="0",mode="nice"} 14.97 node_cpu_seconds_total{cpu="0",mode="softirq"} 771.84 node_cpu_seconds_total{cpu="0",mode="steal"} 0 node_cpu_seconds_total{cpu="0",mode="system"} 9545.91 node_cpu_seconds_total{cpu="0",mode="user"} 3167.3
node_cpu_seconds_total{cpu="0",mode="idle"} :
cpu0上idle进程占用CPU的总时间,CPU占用时间是一个只增不减的度量指标,从类型中也可以看出node_cpu的数据类型是counter(计数器)
counter计数器:只是采集递增的指标
Prometheus server安装和配置
1.创建sa账号,对sa做rbac授权
#创建一个sa账号monitor
[root@master01 Prometheus]# kubectl create serviceaccount monitor -n monitor-sa
#把sa账号monitor通过clusterrolebing绑定到clusterrole上
[root@master01 Prometheus]# kubectl create clusterrolebinding monitor-clusterrolebinding -n monitor-sa --clusterrole=cluster-admin --serviceaccount=monitor-sa:monitor
2.创建prometheus数据存储目录
#在k8s集群的xianchaonode1节点上创建数据存储目录
[root@node01 ~]# mkdir /data/prometheus
安装Prometheus server服务
3.#创建一个configmap存储卷,用来存放prometheus配置信息
prometheus-cfg.yaml文件内容如下:
prometheus-cfg.yaml文件内容如下: --- kind: ConfigMap apiVersion: v1 metadata: labels: app: prometheus name: prometheus-config namespace: monitor-sa data: prometheus.yml: | global: scrape_interval: 15s #采集目标主机监控据的时间间隔 scrape_timeout: 10s # 数据采集超时时间,默认10s evaluation_interval: 1m #触发告警检测的时间,默认是1m scrape_configs: #scrape_configs:配置数据源,称为target,每个target用job_name命名。又分为静态配置和服务发现 - job_name: 'kubernetes-node' kubernetes_sd_configs: #使用的是k8s的服务发现 - role: node # 使用node角色,它使用默认的kubelet提供的http端口来发现集群中每个node节点。 relabel_configs: #重新标记 - source_labels: [__address__] #配置的原始标签,匹配地址 regex: '(.*):10250' #匹配带有10250端口的url
replacement: ':9100' #把匹配到的ip:10250的ip保留 target_label: __address__ #新生成的url是获取到的ip:9100 action: replace - action: labelmap #匹配到下面正则表达式的标签会被保留,如果不做regex正则的话,默认只是会显示instance标签 regex: __meta_kubernetes_node_label_(.+)
注意:Before relabeling表示匹配到的所有标签 instance="xianchaomaster1" Before relabeling: __address__="192.168.40.180:10250" __meta_kubernetes_node_address_Hostname="xianchaomaster1" __meta_kubernetes_node_address_InternalIP="192.168.40.180" __meta_kubernetes_node_annotation_kubeadm_alpha_kubernetes_io_cri_socket="/var/run/dockershim.sock" __meta_kubernetes_node_annotation_node_alpha_kubernetes_io_ttl="0" __meta_kubernetes_node_annotation_projectcalico_org_IPv4Address="192.168.40.180/24" __meta_kubernetes_node_annotation_projectcalico_org_IPv4IPIPTunnelAddr="10.244.123.64" __meta_kubernetes_node_annotation_volumes_kubernetes_io_controller_managed_attach_detach="true" __meta_kubernetes_node_label_beta_kubernetes_io_arch="amd64" __meta_kubernetes_node_label_beta_kubernetes_io_os="linux" __meta_kubernetes_node_label_kubernetes_io_arch="amd64" __meta_kubernetes_node_label_kubernetes_io_hostname="xianchaomaster1" __meta_kubernetes_node_label_kubernetes_io_os="linux" __meta_kubernetes_node_label_node_role_kubernetes_io_control_plane="" __meta_kubernetes_node_label_node_role_kubernetes_io_master="" __meta_kubernetes_node_name="xianchaomaster1" __metrics_path__="/metrics" __scheme__="http" instance="xianchaomaster1" job="kubernetes-node" - job_name: 'kubernetes-node-cadvisor' # 抓取cAdvisor数据,是获取kubelet上/metrics/cadvisor接口数据来获取容器的资源使用情况 kubernetes_sd_configs: - role: node 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: - action: labelmap #把匹配到的标签保留 regex: __meta_kubernetes_node_label_(.+) #保留匹配到的具有__meta_kubernetes_node_label的标签 - target_label: __address__ #获取到的地址:__address__="192.168.40.180: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//proxy/metrics/cadvisor #把metrics替换成新的值api/v1/nodes/xianchaomaster1/proxy/metrics/cadvisor 是__meta_kubernetes_node_name获取到的值 新的url就是https://kubernetes.default.svc:443/api/v1/nodes/xianchaomaster1/proxy/metrics/cadvisor - job_name: 'kubernetes-apiserver' kubernetes_sd_configs: - role: endpoints #使用k8s中的endpoint服务发现,采集apiserver 6443端口获取到的数据 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 #endpoint这个对象的名称空间 ,__meta_kubernetes_service_name #endpoint对象的服务名 , __meta_kubernetes_endpoint_port_name #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
#更新configmap资源
[root@master01 ~]# kubectl apply -f prometheus-cfg.yaml configmap/prometheus-config created
4.通过deployment部署prometheus
node01工作节点上传镜像
[root@node01 ~]# docker pull prom/prometheus:v2.29.1
#通过kubectl apply更新prometheus
[root@master01 ~]# kubectl apply -f prometheus-deploy.yaml
#显示如下,可看到pod状态是running,说明prometheus部署成功
[root@master01 ~]# kubectl get pod -n monitor-sa NAME READY STATUS RESTARTS AGE node-exporter-cmnfv 1/1 Running 0 3h6m node-exporter-fsrk6 1/1 Running 0 3h6m node-exporter-ksgsr 1/1 Running 0 3h6m prometheus-server-78b7bc76b4-zbd62 1/1 Running 0 9s
prometheus-deploy.yaml文件内容如下:
[root@master01 ~]# cat prometheus-deploy.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: prometheus-server namespace: monitor-sa labels: app: prometheus spec: replicas: 1 selector: matchLabels: app: prometheus component: server #matchExpressions: #- {key: app, operator: In, values: [prometheus]} #- {key: component, operator: In, values: [server]} template: metadata: labels: app: prometheus component: server annotations: prometheus.io/scrape: 'false' spec: nodeName: node01 serviceAccountName: monitor initContainers: - name: fix-permissions image: busybox:1.28 imagePullPolicy: IfNotPresent command: ["/bin/chown","-R","65534:65534","/prometheus"] volumeMounts: - mountPath: /prometheus/ name: prometheus-storage-volume containers: - name: prometheus image: prom/prometheus:v2.29.1 imagePullPolicy: IfNotPresent command: - prometheus - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus #旧数据存储目录 - --storage.tsdb.retention=720h #何时删除旧数据,默认为15天 - --web.enable-lifecycle #开启热加载 ports: - containerPort: 9090 protocol: TCP volumeMounts: - mountPath: /etc/prometheus/prometheus.yml name: prometheus-config subPath: prometheus.yml - mountPath: /prometheus/ name: prometheus-storage-volume volumes: - name: prometheus-config configMap: name: prometheus-config items: - key: prometheus.yml path: prometheus.yml mode: 0644 - name: prometheus-storage-volume hostPath: path: /data/prometheus type: Directory
5.给prometheus pod创建一个SVC
prometheus-svc.yaml文件内容如下:
[root@master01 ~]# cat prometheus-svc.yaml apiVersion: v1 kind: Service metadata: name: prometheus namespace: monitor-sa labels: app: prometheus spec: type: NodePort ports: - port: 9090 targetPort: 9090 protocol: TCP nodePort: 30002 selector: app: prometheus component: server
#查看service在物理机映射的端口
[root@master01 ~]# kubectl get svc -n monitor-sa NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE prometheus NodePort 10.1.239.41 <none> 9090:30002/TCP 9s
通过上面可以看到service在宿主机上映射的端口是30002,这样我们访问k8s集群的master1节点的ip:30002,就可以访问到prometheus的web ui界面了
#访问prometheus web ui界面
浏览器输入如下地址:
http://192.168.40.180:32732/graph
#点击页面的Status->Targets,可看到如下,说明我们配置的服务发现可以正常采集数据
Prometheus热加载
#为了每次修改配置文件可以热加载prometheus,也就是不停止prometheus,就可以使配置生效,想要使配置生效可用如下热加载命令:
[root@master01 ~]# kubectl get pods -n monitor-sa -o wide -l app=prometheus NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES prometheus-server-78b7bc76b4-j67wj 1/1 Running 0 31m 172.16.196.133 node01 <none> <none>
172.16.196.133是prometheus的pod的ip地址
想要使配置生效可用如下命令热加载:
[root@master01 ~]# curl -X POST http://172.16.196.133:9090/-/reload
#日志里能看到更新信息
[root@master01 ~]# kubectl logs -f prometheus-server-78b7bc76b4-j67wj -n monitor-sa level=info ts=2021-08-23T09:51:42.207Z caller=main.go:969 msg="Loading configuration file" filename=/etc/prometheus/prometheus.yml level=info ts=2021-08-23T09:51:42.209Z caller=kubernetes.go:282 component="discovery manager scrape" discovery=kubernetes msg="Using pod service account via in-cluster config"
#热加载速度比较慢,可以暴力重启prometheus,如修改上面的prometheus-cfg.yaml文件之后,可执行如下强制删除:
kubectl delete -f prometheus-cfg.yaml kubectl delete -f prometheus-deploy.yaml
然后再通过apply更新:
kubectl apply -f prometheus-cfg.yaml kubectl apply -f prometheus-deploy.yaml
注意:
线上最好热加载,暴力删除可能造成监控数据的丢失

评论