要实现kubernetes集群的监控必须要有一些生成、收集、存储资源指标的工具和手段;
Heapster是早期实现资源指标的方法,弊端在于仅仅支持CPU一项指标;
kubernetes在kubelet程序中集成了cAdvisor,可以收集监控CPU、内存、网络吞吐量及文件系统使用情况指标,通过http://Node_IP:4194提供Web UI,cAdvisor的问题在于仅能收集单个节点及其Pod的资源指标,且kubeadm部署的集群默认未开启此功能;
Heapster使用InfluxDB作为后端存储、Grafana为可视化接口,Heapster从各节点的cAdvisor采集数据并存储于InfluxDB中,用Grafana进行展示;
鉴于Heapster的各类限制,从1.7版本以后kubernetes聚合扩展了资源指标API和自定义指标API;
是以扩展方式提供的API;
提供用户自行按需扩展指标的接口;
是以扩展方式提供的API;
主要提供核心系统组件使用,如调度程序、HPA、kubectl top命令等等,只提供核心系统指标;
不适用第三方监控系统使用,例如promethues;
同时使用自定义指标和资源指标的组件是HPAv2;
Heapster提供核心指标API的功能被聚合方式的指标API服务器metrics-server所取代;
[root@k8s-master-01 ~]# kubectl top nodeerror: Metrics API not available
[root@k8s-master-01 HPA]# yum install -y git[root@k8s-master-01 HPA]# git clone https://github.com/kubernetes-incubator/metrics-server.gitCloning into 'metrics-server'...remote: Enumerating objects: 58, done.remote: Counting objects: 100% (58/58), done.remote: Compressing objects: 100% (55/55), done.remote: Total 12635 (delta 20), reused 17 (delta 2), pack-reused 12577Receiving objects: 100% (12635/12635), 12.56 MiB | 8.00 KiB/s, done.Resolving deltas: 100% (6601/6601), done.[root@k8s-master-01 HPA]# lsmetrics-server[root@k8s-master-01 base]# kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yam#由于镜像下载失败,改用0.3.6版本部署
#https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/metrics-server[root@k8s-master-01 ~]# wget https://github.com/kubernetes-sigs/metrics-server/archive/v0.3.6.tar.gz[root@k8s-master-01 ~]# tar xf v0.3.6.tar.gz[root@k8s-master-01 ~]# cd metrics-server-0.3.6/deploy/1.8+/[root@k8s-master-01 1.8+]# pwd/root/metrics-server-0.3.6/deploy/1.8+[root@k8s-master-01 1.8+]# lltotal 28-rw-rw-r-- 1 root root 393 Oct 14 2019 aggregated-metrics-reader.yaml-rw-rw-r-- 1 root root 308 Oct 14 2019 auth-delegator.yaml-rw-rw-r-- 1 root root 329 Oct 14 2019 auth-reader.yaml-rw-rw-r-- 1 root root 298 Oct 14 2019 metrics-apiservice.yaml-rw-rw-r-- 1 root root 1085 Nov 22 15:33 metrics-server-deployment.yaml-rw-rw-r-- 1 root root 291 Oct 14 2019 metrics-server-service.yaml-rw-rw-r-- 1 root root 517 Oct 14 2019 resource-reader.yaml[root@k8s-master-01 1.8+]# kubectl apply -f root/metrics-server-0.3.6/deploy/1.8+/clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader createdWarning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBindingclusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator createdWarning: rbac.authorization.k8s.io/v1beta1 RoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 RoleBindingrolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader createdWarning: apiregistration.k8s.io/v1beta1 APIService is deprecated in v1.19+, unavailable in v1.22+; use apiregistration.k8s.io/v1 APIServiceapiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io createdserviceaccount/metrics-server createddeployment.apps/metrics-server createdservice/metrics-server createdclusterrole.rbac.authorization.k8s.io/system:metrics-server createdclusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
注意:下载后的metrics-service-deployment.yaml文件需要修改;
[root@k8s-master-01 1.8+]# cat metrics-server-deployment.yaml---apiVersion: v1kind: ServiceAccountmetadata:name: metrics-servernamespace: kube-system---apiVersion: apps/v1kind: Deploymentmetadata:name: metrics-servernamespace: kube-systemlabels:k8s-app: metrics-serverspec:selector:matchLabels:k8s-app: metrics-servertemplate:metadata:name: metrics-serverlabels:k8s-app: metrics-serverspec:serviceAccountName: metrics-servervolumes:# mount in tmp so we can safely use from-scratch images and/or read-only containers- name: tmp-diremptyDir: {}containers:- name: metrics-server#修改为本地的可用镜像image: mirrorgooglecontainers/metrics-server-amd64:v0.3.6#或者iamge: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64imagePullPolicy: IfNotPresent#添加command内容command:- metrics-server- --kubelet-insecure-tls- --kubelet-preferred-address-types=InternalDNS,InternalIP,ExternalDNS,ExternalIP,Hostname#将原内容注释掉#image: k8s.gcr.io/metrics-server-amd64:v0.3.6#imagePullPolicy: AlwaysvolumeMounts:- name: tmp-dirmountPath: tmp
[root@k8s-master-01 1.8+]# cat metrics-apiservice.yaml---apiVersion: apiregistration.k8s.io/v1beta1kind: APIServicemetadata:name: v1beta1.metrics.k8s.iospec:service:name: metrics-servernamespace: kube-systemgroup: metrics.k8s.ioversion: v1beta1insecureSkipTLSVerify: truegroupPriorityMinimum: 100versionPriority: 100
[root@k8s-master-01 1.8+]# cat metrics-server-service.yaml---apiVersion: v1kind: Servicemetadata:name: metrics-servernamespace: kube-systemlabels:kubernetes.io/name: "Metrics-server"kubernetes.io/cluster-service: "true"spec:selector:k8s-app: metrics-serverports:- port: 443protocol: TCPtargetPort: 443
[root@k8s-master-01 1.8+]# cat aggregated-metrics-reader.yamlkind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: system:aggregated-metrics-readerlabels:rbac.authorization.k8s.io/aggregate-to-view: "true"rbac.authorization.k8s.io/aggregate-to-edit: "true"rbac.authorization.k8s.io/aggregate-to-admin: "true"rules:- apiGroups: ["metrics.k8s.io"]resources: ["pods", "nodes"]verbs: ["get", "list", "watch"]
[root@k8s-master-01 1.8+]# cat auth-delegator.yaml---apiVersion: rbac.authorization.k8s.io/v1beta1kind: ClusterRoleBindingmetadata:name: metrics-server:system:auth-delegatorroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: system:auth-delegatorsubjects:- kind: ServiceAccountname: metrics-servernamespace: kube-system
[root@k8s-master-01 1.8+]# cat auth-reader.yaml---apiVersion: rbac.authorization.k8s.io/v1beta1kind: RoleBindingmetadata:name: metrics-server-auth-readernamespace: kube-systemroleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: extension-apiserver-authentication-readersubjects:- kind: ServiceAccountname: metrics-servernamespace: kube-system
[root@k8s-master-01 1.8+]# cat resource-reader.yaml---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: system:metrics-serverrules:- apiGroups:- ""resources:- pods- nodes- nodes/stats- namespacesverbs:- get- list- watch---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: system:metrics-serverroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: system:metrics-serversubjects:- kind: ServiceAccountname: metrics-servernamespace: kube-system
[root@k8s-master-01 1.8+]# kubectl get apiservice | grep metricsv1beta1.metrics.k8s.io kube-system/metrics-server True 4m37s[root@k8s-master-01 1.8+]# kubectl api-versions | grep metrics.k8smetrics.k8s.io/v1beta1#APIService成功创建了对应的群组[root@k8s-master-01 1.8+]# kubectl get pods -n kube-system -l k8s-app=metrics-server -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESmetrics-server-8665c8fbd9-txlnr 1/1 Running 0 2m41s 10.244.3.12 k8s-worker-02 <none> <none>[root@k8s-master-01 1.8+]# kubectl logs metrics-server-8665c8fbd9-txlnr -n kube-systemI1122 07:35:06.404183 1 serving.go:312] Generated self-signed cert (apiserver.local.config/certificates/apiserver.crt, apiserver.local.config/certificates/apiserver.key)I1122 07:35:07.332599 1 secure_serving.go:116] Serving securely on [::]:443
[root@k8s-master-01 1.8+]# kubectl top nodeNAME CPU(cores) CPU% MEMORY(bytes) MEMORY%k8s-master-01 223m 5% 1562Mi 42%k8s-master-02 171m 4% 1528Mi 41%k8s-worker-01 90m 2% 533Mi 14%k8s-worker-02 66m 1% 821Mi 22%
[root@k8s-master-01 1.8+]# yum install -y jq[root@k8s-master-01 1.8+]# kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq{"kind": "NodeMetricsList","apiVersion": "metrics.k8s.io/v1beta1","metadata": {"selfLink": "/apis/metrics.k8s.io/v1beta1/nodes"},"items": [{"metadata": {"name": "k8s-worker-01","selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/k8s-worker-01","creationTimestamp": "2020-11-22T07:45:18Z"},"timestamp": "2020-11-22T07:45:05Z","window": "30s","usage": {"cpu": "91433503n","memory": "548340Ki"}},{"metadata": {"name": "k8s-worker-02","selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/k8s-worker-02","creationTimestamp": "2020-11-22T07:45:18Z"},"timestamp": "2020-11-22T07:45:02Z","window": "30s","usage": {"cpu": "88106006n","memory": "841060Ki"}},{"metadata": {"name": "k8s-master-01","selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/k8s-master-01","creationTimestamp": "2020-11-22T07:45:18Z"},"timestamp": "2020-11-22T07:45:02Z","window": "30s","usage": {"cpu": "233161058n","memory": "1568216Ki"}},{"metadata": {"name": "k8s-master-02","selfLink": "/apis/metrics.k8s.io/v1beta1/nodes/k8s-master-02","creationTimestamp": "2020-11-22T07:45:18Z"},"timestamp": "2020-11-22T07:45:01Z","window": "30s","usage": {"cpu": "185202863n","memory": "1542340Ki"}}]}#使用URL路径也可查看每个Pod的指标状态;[root@k8s-master-01 1.8+]# kubectl get --raw "/apis/metrics.k8s.io/v1beta1/pods" | jq
除了资源指标之外,我们还需要获取很多指标,自定义指标允许API请求任意指标,其指标API要特定于相应的后端监视系统,prometheus是一个相应的监控系统.
[root@k8s-master-01 HPA]# git clone https://github.com/kubernetesCloning into 'kubernetes'...remote: Enumerating objects: 218, done.remote: Counting objects: 100% (218/218), done.remote: Compressing objects: 100% (127/127), done.remote: Total 1169214 (delta 112), reused 91 (delta 91), pack-reused 1168996Receiving objects: 100% (1169214/1169214), 710.78 MiB | 2.74 MiB/s, done.Resolving deltas: 100% (839462/839462), done.Checking out files: 100% (22748/22748), done.
[root@k8s-master-01 HPA]# git clone https://github.com/iKubernetes/k8s-prom.gitCloning into 'k8s-prom'...remote: Enumerating objects: 49, done.remote: Total 49 (delta 0), reused 0 (delta 0), pack-reused 49Unpacking objects: 100% (49/49), done.[root@k8s-master-01 HPA]# tree k8s-promk8s-prom├── k8s-prometheus-adapter│ ├── custom-metrics-apiserver-auth-delegator-cluster-role-binding.yaml│ ├── custom-metrics-apiserver-auth-reader-role-binding.yaml│ ├── custom-metrics-apiserver-deployment.yaml│ ├── custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml│ ├── custom-metrics-apiserver-service-account.yaml│ ├── custom-metrics-apiserver-service.yaml│ ├── custom-metrics-apiservice.yaml│ ├── custom-metrics-cluster-role.yaml│ ├── custom-metrics-resource-reader-cluster-role.yaml│ └── hpa-custom-metrics-cluster-role-binding.yaml├── kube-state-metrics│ ├── kube-state-metrics-deploy.yaml│ ├── kube-state-metrics-rbac.yaml│ └── kube-state-metrics-svc.yaml├── namespace.yaml├── node_exporter│ ├── node-exporter-ds.yaml│ └── node-exporter-svc.yaml├── podinfo│ ├── podinfo-deploy.yaml│ └── podinfo-svc.yaml├── prometheus│ ├── prometheus-cfg.yaml│ ├── prometheus-deploy.yaml│ ├── prometheus-rbac.yaml│ └── prometheus-svc.yaml└── README.md5 directories, 23 files
kube-state-metrics能够从kubernetes API Server上收集大多数资源对象的状态信息并转化为指标数据。
kube-state-metrics主要负责为CronJob、Deployment、PersistentVolumeClaim等各类资源的对象生成指标数据;
[1] 创建专用的名称空间
[root@k8s-master-01 k8s-prom]# kubectl apply -f namespace.yamlnamespace/prom created[root@k8s-master-01 k8s-prom]# kubectl get namespacesNAME STATUS AGEprom Active 7s
[root@k8s-worker-02 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/kubernets-imags/kube-state-metrics:v1.3.0[root@k8s-worker-02 ~]# docker tag registry.cn-hangzhou.aliyuncs.com/kubernets-imags/kube-state-metrics:v1.3.0 gcr.io/google_containers/kube-state-metrics-amd64:v1.3.1[root@k8s-master-01 kube-state-metrics]# kubectl apply -f kube-state-metrics/[root@k8s-master-01 k8s-prom]# cat kube-state-metrics/kube-state-metrics-deploy.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: kube-state-metricsnamespace: promspec:replicas: 1selector:matchLabels:app: kube-state-metricstemplate:metadata:labels:app: kube-state-metricsspec:serviceAccountName: kube-state-metricscontainers:- name: kube-state-metricsimage: gcr.io/google_containers/kube-state-metrics-amd64:v1.3.1ports:- containerPort: 8080
[root@k8s-master-01 k8s-prom]# cat kube-state-metrics/kube-state-metrics-svc.yamlapiVersion: v1kind: Servicemetadata:annotations:prometheus.io/scrape: 'true'name: kube-state-metricsnamespace: promlabels:app: kube-state-metricsspec:ports:- name: kube-state-metricsport: 8080protocol: TCPselector:app: kube-state-metrics
[root@k8s-master-01 k8s-prom]# cat kube-state-metrics/kube-state-metrics-rbac.yaml---apiVersion: v1kind: ServiceAccountmetadata:name: kube-state-metricsnamespace: prom---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: kube-state-metricsrules:- apiGroups: [""]resources: ["nodes", "pods", "services", "resourcequotas", "replicationcontrollers", "limitranges", "persistentvolumeclaims", "persistentvolumes", "namespaces", "endpoints"]verbs: ["list", "watch"]- apiGroups: ["extensions"]resources: ["daemonsets", "deployments", "replicasets"]verbs: ["list", "watch"]- apiGroups: ["apps"]resources: ["statefulsets"]verbs: ["list", "watch"]- apiGroups: ["batch"]resources: ["cronjobs", "jobs"]verbs: ["list", "watch"]- apiGroups: ["autoscaling"]resources: ["horizontalpodautoscalers"]verbs: ["list", "watch"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: kube-state-metricsroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: kube-state-metricssubjects:- kind: ServiceAccountname: kube-state-metricsnamespace: prom
[root@k8s-master-01 kube-state-metrics]# kubectl get pods -n prom -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESkube-state-metrics-7b99db8cdb-22vdz 1/1 Running 0 6m28s 10.244.3.13 k8s-worker-02 <none> <none>[root@k8s-master-01 kube-state-metrics]# kubectl get svc -n prom -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORkube-state-metrics ClusterIP 10.100.241.139 <none> 8080/TCP 33m app=kube-state-metrics
[root@k8s-worker-01 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2[root@k8s-worker-01 ~]# docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2[root@k8s-master-01 kube-state-metrics]# kubectl run client-$RANDOM --image=cirros -n prom -it -- sh/ # curl kube-state-metrics:8080/metrics | tail% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed100 5333 100 5333 0 0 1302k 0 --:--:-- --:--:-- --:--:-- 1736kkube_namespace_status_phase{namespace="default",phase="Active"} 1kube_namespace_status_phase{namespace="default",phase="Terminating"} 0kube_namespace_status_phase{namespace="kube-node-lease",phase="Active"} 1kube_namespace_status_phase{namespace="kube-node-lease",phase="Terminating"} 0kube_namespace_status_phase{namespace="kube-public",phase="Active"} 1kube_namespace_status_phase{namespace="kube-public",phase="Terminating"} 0kube_namespace_status_phase{namespace="kube-system",phase="Active"} 1kube_namespace_status_phase{namespace="kube-system",phase="Terminating"} 0kube_namespace_status_phase{namespace="prom",phase="Active"} 1kube_namespace_status_phase{namespace="prom",phase="Terminating"} 0
prometheus通过HTTP周期性的抓取指标数据,监控目标上用于接收并相应数据抓取请求的组件统称为exporter;
node_exporter是prometheus提供的专用的监控类程序;
node_exporter不是必须组件,也可通过kubelet或者cAdvsior提供监控指标;
[root@k8s-master-01 k8s-prom]# kubectl apply -f node_exporter/node-exporter-ds.yaml[root@k8s-master-01 k8s-prom]# cat node_exporter/node-exporter-ds.yamlapiVersion: apps/v1kind: DaemonSetmetadata:name: prometheus-node-exporternamespace: promlabels:app: prometheuscomponent: node-exporterspec:selector:matchLabels:app: prometheuscomponent: node-exportertemplate:metadata:name: prometheus-node-exporterlabels:app: prometheuscomponent: node-exporterspec:tolerations:- effect: NoSchedulekey: node-role.kubernetes.io/mastercontainers:- image: prom/node-exporter:v0.15.2name: prometheus-node-exporterports:- name: prom-node-expcontainerPort: 9100hostPort: 9100hostNetwork: truehostPID: true
[root@k8s-master-01 k8s-prom]# kubectl apply -f node_exporter/node-exporter-svc.yaml[root@k8s-master-01 k8s-prom]# cat node_exporter/node-exporter-svc.yamlapiVersion: v1kind: Servicemetadata:annotations:prometheus.io/scrape: 'true'name: prometheus-node-exporternamespace: promlabels:app: prometheuscomponent: node-exporterspec:clusterIP: Noneports:- name: prometheus-node-exporterport: 9100protocol: TCPselector:app: prometheuscomponent: node-exportertype: ClusterIP
[root@k8s-master-01 k8s-prom]# kubectl get svc -n prom -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORprometheus-node-exporter ClusterIP None <none> 9100/TCP 3m57s app=prometheus,component=node-exporter[root@k8s-master-01 k8s-prom]# kubectl get svc -n prom -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORprometheus-node-exporter ClusterIP None <none> 9100/TCP 4m16s app=prometheus,component=node-exporter
[root@k8s-master-01 k8s-prom]# curl http://172.17.61.220:9100/metrics | tail% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed100 110k 100 110k 0 0 6765k 0 --:--:-- --:--:-- --:--:-- 7369kprocess_open_fds 8# HELP process_resident_memory_bytes Resident memory size in bytes.# TYPE process_resident_memory_bytes gaugeprocess_resident_memory_bytes 1.0027008e+07# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.# TYPE process_start_time_seconds gaugeprocess_start_time_seconds 1.60604524865e+09# HELP process_virtual_memory_bytes Virtual memory size in bytes.# TYPE process_virtual_memory_bytes gaugeprocess_virtual_memory_bytes 2.05336576e+08

为prometheus根据高进规则将告警信息发送给alertmanager插件,alertmanager插件再做去重、分组处理,而后发送给告警接收端,包括email、slack
[root@k8s-master-01 alertmanager]# ls root/kubernetes-config/prometheus/k8s-prom/alertmanageralertmanager-configmap.yaml alertmanager-rule.yaml alertmanager-deployment.yaml[root@k8s-master-01 alertmanager]# kubectl apply -f root/kubernetes-config/prometheus/k8s-prom/alertmanagerconfigmap/alertmanager-config unchangeddeployment.apps/alertmanager unchangedservice/alertmanager unchangedconfigmap/prometheus-rules unchanged
[root@k8s-master-01 alertmanager]# cat alertmanager-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: alertmanagernamespace: promspec:replicas: 1selector:matchLabels:app: alertmanagertemplate:metadata:labels:app: alertmanagerspec:containers:- name: alertmanagerimage: prom/alertmanager:v0.14.0args:- "--config.file=/etc/alertmanager/config.yml"- "--storage.path=/alertmanager"ports:- name: alertmanagercontainerPort: 9093volumeMounts:- name: alertmanager-cmmountPath: etc/alertmanagervolumes:- name: alertmanager-cmconfigMap:name: alertmanager-config
apiVersion: v1kind: Servicemetadata:name: alertmanagernamespace: promspec:selector:app: alertmanagerports:- port: 80targetPort: 9093type: "ClusterIP"
[root@k8s-master-01 alertmanager]# cat alertmanager-configmap.yamlapiVersion: v1kind: ConfigMapmetadata:name: alertmanager-confignamespace: promdata:config.yml: |-global:# 在没有报警的情况下声明为已解决的时间resolve_timeout: 5m# 配置邮件发送信息smtp_smarthost: 'smtp.163.com:25'smtp_from: 'xxx@163.com'smtp_auth_username: 'xxx@163.com'smtp_auth_password: 'xxxxxx'smtp_require_tls: false# 所有报警信息进入后的根路由,用来设置报警的分发策略route:# 这里的标签列表是接收到报警信息后的重新分组标签,例如,接收到的报警信息里面有许多具有 cluster=A 和 alertname=LatncyHigh 这样的标签的报警信息将会批量被聚合到一个分组里面group_by: ['alertname', 'cluster']# 当一个新的报警分组被创建后,需要等待至少group_wait时间来初始化通知,这种方式可以确保您能有足够的时间为同一分组来获取多个警报,然后一起触发这个报警信息。group_wait: 30s# 当第一个报警发送后,等待'group_interval'时间来发送新的一组报警信息。group_interval: 5m# 如果一个报警信息已经发送成功了,等待'repeat_interval'时间来重新发送他们repeat_interval: 5m# 默认的receiver:如果一个报警没有被一个route匹配,则发送给默认的接收器receiver: defaultreceivers:- name: 'default'email_configs:- to: 'xxxx@qq.com'send_resolved: true
告警规则为configMap资源对象,供prometheus使用;
[root@k8s-master-01 alertmanager]# cat alertmanager-rule.yamlapiVersion: v1kind: ConfigMapmetadata:name: prometheus-rulesnamespace: promdata:# 通用角色general.rules: |groups:- name: general.rulesrules:- alert: InstanceDownexpr: up == 0for: 1mlabels:severity: errorannotations:summary: "Instance {{ $labels.instance }} 停止工作"description: "{{ $labels.instance }} job {{ $labels.job }} 已经停止5分钟以上."# Node对所有资源的监控node.rules: |groups:- name: node.rulesrules:- alert: NodeFilesystemUsageexpr: 100 - (node_filesystem_free_bytes{fstype=~"ext4|xfs"} node_filesystem_size_bytes{fstype=~"ext4|xfs"} * 100) > 80for: 1mlabels:severity: warningannotations:summary: "Instance {{ $labels.instance }} : {{ $labels.mountpoint }} 分区使用率过高"description: "{{ $labels.instance }}: {{ $labels.mountpoint }} 分区使用大于80% (当前值: {{ $value }})"- alert: NodeMemoryUsageexpr: 100 - (node_memory_MemFree_bytes+node_memory_Cached_bytes+node_memory_Buffers_bytes) node_memory_MemTotal_bytes * 100 > 80for: 1mlabels:severity: warningannotations:summary: "Instance {{ $labels.instance }} 内存使用率过高"description: "{{ $labels.instance }}内存使用大于80% (当前值: {{ $value }})"- alert: NodeCPUUsageexpr: 100 - (avg(irate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) * 100) > 60for: 1mlabels:severity: warningannotations:summary: "Instance {{ $labels.instance }} CPU使用率过高"description: "{{ $labels.instance }}CPU使用大于60% (当前值: {{ $value }})"
[root@k8s-master-01 alertmanager]# cat ../prometheus/prometheus-cfg.yaml | egrep -v '^#|^[[:space:]]*#'---kind: ConfigMapapiVersion: v1metadata:labels:app: prometheusname: prometheus-confignamespace: promdata:prometheus.yml: |global:scrape_interval: 15sscrape_timeout: 10sevaluation_interval: 1mscrape_configs:- job_name: 'kubernetes-apiservers'kubernetes_sd_configs:- role: endpointsscheme: httpstls_config:ca_file: var/run/secrets/kubernetes.io/serviceaccount/ca.crtbearer_token_file: var/run/secrets/kubernetes.io/serviceaccount/tokenrelabel_configs:- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]action: keepregex: default;kubernetes;https- job_name: 'kubernetes-nodes'scheme: httpstls_config:ca_file: var/run/secrets/kubernetes.io/serviceaccount/ca.crtbearer_token_file: var/run/secrets/kubernetes.io/serviceaccount/tokenkubernetes_sd_configs:- role: noderelabel_configs:- action: labelmapregex: __meta_kubernetes_node_label_(.+)- target_label: __address__replacement: kubernetes.default.svc:443- source_labels: [__meta_kubernetes_node_name]regex: (.+)target_label: __metrics_path__replacement: api/v1/nodes/${1}/proxy/metrics- job_name: 'kubernetes-cadvisor'scheme: httpstls_config:ca_file: var/run/secrets/kubernetes.io/serviceaccount/ca.crtbearer_token_file: var/run/secrets/kubernetes.io/serviceaccount/tokenkubernetes_sd_configs:- role: noderelabel_configs:- action: labelmapregex: __meta_kubernetes_node_label_(.+)- target_label: __address__replacement: kubernetes.default.svc:443- source_labels: [__meta_kubernetes_node_name]regex: (.+)target_label: __metrics_path__replacement: api/v1/nodes/${1}/proxy/metrics/cadvisor- job_name: 'kubernetes-service-endpoints'kubernetes_sd_configs:- role: endpointsrelabel_configs:- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]action: keepregex: true- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]action: replacetarget_label: __scheme__regex: (https?)- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]action: replacetarget_label: __metrics_path__regex: (.+)- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]action: replacetarget_label: __address__regex: ([^:]+)(?::\d+)?;(\d+)replacement: $1:$2- action: labelmapregex: __meta_kubernetes_service_label_(.+)- source_labels: [__meta_kubernetes_namespace]action: replacetarget_label: kubernetes_namespace- source_labels: [__meta_kubernetes_service_name]action: replacetarget_label: kubernetes_name- job_name: 'kubernetes-pods'honor_labels: falsekubernetes_sd_configs:- role: podtls_config:insecure_skip_verify: truerelabel_configs:- source_labels: [__meta_kubernetes_namespace]action: replacetarget_label: namespace- source_labels: [__meta_kubernetes_pod_name]action: replacetarget_label: pod- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]action: keepregex: true- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]action: replacetarget_label: __metrics_path__regex: (.+)- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]action: replaceregex: ([^:]+)(?::\d+)?;(\d+)replacement: $1:$2target_label: __address__- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]action: replacetarget_label: __scheme__regex: (.+)alerting:alertmanagers:- static_configs:- targets: ["alertmanager:80"]rule_files:- etc/config/rules/*.rules
为了保证prometheus能够加载到告警规则,该实例中将prometheus-rules直接挂载在prometheus的容器上,也可使用statefulset来加载prometheus-rules;
[root@k8s-master-01 alertmanager]# cat ../prometheus/prometheus-deploy.yaml---apiVersion: apps/v1kind: Deploymentmetadata:name: prometheus-servernamespace: promlabels:app: prometheusspec:replicas: 1selector:matchLabels:app: prometheuscomponent: server#matchExpressions:#- {key: app, operator: In, values: [prometheus]}#- {key: component, operator: In, values: [server]}template:metadata:labels:app: prometheuscomponent: serverannotations:prometheus.io/scrape: 'false'spec:serviceAccountName: prometheuscontainers:- name: prometheusimage: prom/prometheus:v2.2.1imagePullPolicy: Alwayscommand:- prometheus- --config.file=/etc/prometheus/prometheus.yml- --storage.tsdb.path=/prometheus- --storage.tsdb.retention=720hports:- containerPort: 9090protocol: TCPresources:limits:memory: 2GivolumeMounts:- mountPath: etc/prometheus/prometheus.ymlname: prometheus-configsubPath: prometheus.yml- mountPath: prometheus/name: prometheus-storage-volume- mountPath: etc/config/rulesname: prometheus-alertmanagevolumes:- name: prometheus-configconfigMap:name: prometheus-configitems:- key: prometheus.ymlpath: prometheus.ymlmode: 0644- name: prometheus-alertmanageconfigMap:name: prometheus-rules- name: prometheus-storage-volumeemptyDir: {}
[root@k8s-master-01 alertmanager]# kubectl exec prometheus-server-75d864d655-h5cf7 -n prom -- ls etc/config/rulesgeneral.rulesnode.rules[root@k8s-master-01 alertmanager]# kubectl get pod -n promNAME READY STATUS RESTARTS AGEalertmanager-6656585ccd-2xp95 1/1 Running 0 3h5mcustom-metrics-apiserver-55c849446d-g2kn6 1/1 Running 0 5h41mcustom-metrics-apiserver-d6b994c76-tdmm2 1/1 Running 0 2d19hkube-state-metrics-7b99db8cdb-22vdz 1/1 Running 0 2d21hprometheus-node-exporter-42z4b 1/1 Running 0 5h42mprometheus-node-exporter-cdllq 1/1 Running 0 2d19hprometheus-node-exporter-gmnmv 1/1 Running 0 5h42mprometheus-node-exporter-jd7qt 1/1 Running 0 5h42mprometheus-server-75d864d655-h5cf7 1/1 Running 0 118m[root@k8s-master-01 alertmanager]# kubectl get svc -n promNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEalertmanager ClusterIP 10.97.198.54 <none> 80/TCP 3h5mcustom-metrics-apiserver ClusterIP 10.96.103.132 <none> 443/TCP 5h41mkube-state-metrics ClusterIP 10.100.241.139 <none> 8080/TCP 2d21hprometheus-node-exporter ClusterIP None <none> 9100/TCP 5h42m


[root@k8s-master-01 k8s-prom]# kubectl apply -f prometheus/configmap/prometheus-config createddeployment.apps/prometheus-server createdWarning: rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleclusterrole.rbac.authorization.k8s.io/prometheus createdserviceaccount/prometheus createdWarning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBindingclusterrolebinding.rbac.authorization.k8s.io/prometheus createdservice/prometheus created
[root@k8s-master-01 k8s-prom]# cat prometheus/prometheus-deploy.yaml---apiVersion: apps/v1kind: Deploymentmetadata:name: prometheus-servernamespace: promlabels:app: prometheusspec:replicas: 1selector:matchLabels:app: prometheuscomponent: server#matchExpressions:#- {key: app, operator: In, values: [prometheus]}#- {key: component, operator: In, values: [server]}template:metadata:labels:app: prometheuscomponent: serverannotations:prometheus.io/scrape: 'false'spec:serviceAccountName: prometheuscontainers:- name: prometheusimage: prom/prometheus:v2.2.1imagePullPolicy: Alwayscommand:- prometheus- --config.file=/etc/prometheus/prometheus.yml- --storage.tsdb.path=/prometheus- --storage.tsdb.retention=720hports:- containerPort: 9090protocol: TCPresources:limits:memory: 2GivolumeMounts:- mountPath: etc/prometheus/prometheus.ymlname: prometheus-configsubPath: prometheus.yml- mountPath: prometheus/name: prometheus-storage-volumevolumes:- name: prometheus-configconfigMap:name: prometheus-configitems:- key: prometheus.ymlpath: prometheus.ymlmode: 0644- name: prometheus-storage-volumeemptyDir: {}
[root@k8s-master-01 k8s-prom]# cat prometheus/prometheus-cfg.yaml---kind: ConfigMapapiVersion: v1metadata:labels:app: prometheusname: prometheus-confignamespace: promdata:prometheus.yml: |# A scrape configuration for running Prometheus on a Kubernetes cluster.# This uses separate scrape configs for cluster components (i.e. API server, node)# and services to allow each to use different authentication configs.## Kubernetes labels will be added as Prometheus labels on metrics via the# `labelmap` relabeling action.## If you are using Kubernetes 1.7.2 or earlier, please take note of the comments# for the kubernetes-cadvisor job; you will need to edit or remove this job.# Scrape config for API servers.## Kubernetes exposes API servers as endpoints to the default/kubernetes# service so this uses `endpoints` role and uses relabelling to only keep# the endpoints associated with the default/kubernetes service using the# default named port `https`. This works for single API server deployments as# well as HA API server deployments.global:scrape_interval: 15sscrape_timeout: 10sevaluation_interval: 1mscrape_configs:- job_name: 'kubernetes-apiservers'kubernetes_sd_configs:- role: endpoints# Default to scraping over https. If required, just disable this or change to# `http`.scheme: https# This TLS & bearer token file config is used to connect to the actual scrape# endpoints for cluster components. This is separate to discovery auth# configuration because discovery & scraping are two separate concerns in# Prometheus. The discovery auth config is automatic if Prometheus runs inside# the cluster. Otherwise, more config options have to be provided within the# <kubernetes_sd_config>.tls_config:ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt# If your node certificates are self-signed or use a different CA to the# master CA, then disable certificate verification below. Note that# certificate verification is an integral part of a secure infrastructure# so this should only be disabled in a controlled environment. You can# disable certificate verification by uncommenting the line below.## insecure_skip_verify: truebearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token# Keep only the default/kubernetes service endpoints for the https port. This# will add targets for each API server which Kubernetes adds an endpoint to# the default/kubernetes service.relabel_configs:- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]action: keepregex: default;kubernetes;https# Scrape config for nodes (kubelet).## Rather than connecting directly to the node, the scrape is proxied though the# Kubernetes apiserver. This means it will work if Prometheus is running out of# cluster, or can't connect to nodes for some other reason (e.g. because of# firewalling).- job_name: 'kubernetes-nodes'# Default to scraping over https. If required, just disable this or change to# `http`.scheme: https# This TLS & bearer token file config is used to connect to the actual scrape# endpoints for cluster components. This is separate to discovery auth# configuration because discovery & scraping are two separate concerns in# Prometheus. The discovery auth config is automatic if Prometheus runs inside# the cluster. Otherwise, more config options have to be provided within the# <kubernetes_sd_config>.tls_config:ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crtbearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/tokenkubernetes_sd_configs:- role: noderelabel_configs:- action: labelmapregex: __meta_kubernetes_node_label_(.+)- target_label: __address__replacement: kubernetes.default.svc:443- source_labels: [__meta_kubernetes_node_name]regex: (.+)target_label: __metrics_path__replacement: /api/v1/nodes/${1}/proxy/metrics# Scrape config for Kubelet cAdvisor.## This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics# (those whose names begin with 'container_') have been removed from the# Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to# retrieve those metrics.## In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor# HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics"# in that case (and ensure cAdvisor's HTTP server hasn't been disabled with# the --cadvisor-port=0 Kubelet flag).## This job is not necessary and should be removed in Kubernetes 1.6 and# earlier versions, or it will cause the metrics to be scraped twice.- job_name: 'kubernetes-cadvisor'# Default to scraping over https. If required, just disable this or change to# `http`.scheme: https# This TLS & bearer token file config is used to connect to the actual scrape# endpoints for cluster components. This is separate to discovery auth# configuration because discovery & scraping are two separate concerns in# Prometheus. The discovery auth config is automatic if Prometheus runs inside# the cluster. Otherwise, more config options have to be provided within the# <kubernetes_sd_config>.tls_config:ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crtbearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/tokenkubernetes_sd_configs:- role: noderelabel_configs:- action: labelmapregex: __meta_kubernetes_node_label_(.+)- target_label: __address__replacement: kubernetes.default.svc:443- source_labels: [__meta_kubernetes_node_name]regex: (.+)target_label: __metrics_path__replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor# Scrape config for service endpoints.## The relabeling allows the actual service scrape endpoint to be configured# via the following annotations:## * `prometheus.io/scrape`: Only scrape services that have a value of `true`# * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need# to set this to `https` & most likely set the `tls_config` of the scrape config.# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.# * `prometheus.io/port`: If the metrics are exposed on a different port to the# service then set this appropriately.- job_name: 'kubernetes-service-endpoints'kubernetes_sd_configs:- role: endpointsrelabel_configs:- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]action: keepregex: true- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]action: replacetarget_label: __scheme__regex: (https?)- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]action: replacetarget_label: __metrics_path__regex: (.+)- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]action: replacetarget_label: __address__regex: ([^:]+)(?::\d+)?;(\d+)replacement: $1:$2- action: labelmapregex: __meta_kubernetes_service_label_(.+)- source_labels: [__meta_kubernetes_namespace]action: replacetarget_label: kubernetes_namespace- source_labels: [__meta_kubernetes_service_name]action: replacetarget_label: kubernetes_name# Example scrape config for pods## The relabeling allows the actual pod scrape endpoint to be configured via the# following annotations:## * `prometheus.io/scrape`: Only scrape pods that have a value of `true`# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.# * `prometheus.io/port`: Scrape the pod on the indicated port instead of the# pod's declared ports (default is a port-free target if none are declared).- job_name: 'kubernetes-pods'# if you want to use metrics on jobs, set the below field to# true to prevent Prometheus from setting the `job` label# automatically.honor_labels: falsekubernetes_sd_configs:- role: pod# skip verification so you can do HTTPS to podstls_config:insecure_skip_verify: true# make sure your labels are in orderrelabel_configs:# these labels tell Prometheus to automatically attach source# pod and namespace information to each collected sample, so# that they'll be exposed in the custom metrics API automatically.- source_labels: [__meta_kubernetes_namespace]action: replacetarget_label: namespace- source_labels: [__meta_kubernetes_pod_name]action: replacetarget_label: pod# these labels tell Prometheus to look for# prometheus.io/{scrape,path,port} annotations to configure# how to scrape- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]action: keepregex: true- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]action: replacetarget_label: __metrics_path__regex: (.+)- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]action: replaceregex: ([^:]+)(?::\d+)?;(\d+)replacement: $1:$2target_label: __address__- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]action: replacetarget_label: __scheme__regex: (.+)
[root@k8s-master-01 k8s-prom]# cat prometheus/prometheus-svc.yaml---apiVersion: v1kind: Servicemetadata:name: prometheusnamespace: promlabels:app: prometheusspec:type: NodePortports:- port: 9090targetPort: 9090nodePort: 30090protocol: TCPselector:app: prometheuscomponent: server
[root@k8s-master-01 k8s-prom]# cat prometheus/prometheus-rbac.yaml---apiVersion: rbac.authorization.k8s.io/v1beta1kind: ClusterRolemetadata:name: prometheusrules:- apiGroups: [""]resources:- nodes- nodes/proxy- services- endpoints- podsverbs: ["get", "list", "watch"]- apiGroups:- extensionsresources:- ingressesverbs: ["get", "list", "watch"]- nonResourceURLs: ["/metrics"]verbs: ["get"]---apiVersion: v1kind: ServiceAccountmetadata:name: prometheusnamespace: prom---apiVersion: rbac.authorization.k8s.io/v1beta1kind: ClusterRoleBindingmetadata:name: prometheusroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: prometheussubjects:- kind: ServiceAccountname: prometheusnamespace: prom
[root@k8s-master-01 k8s-prom]# kubectl get pods -n prom -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESprometheus-server-59db489b4f-6xfrk 1/1 Running 0 3m6s 10.244.3.19 k8s-worker-02 <none> <none>[root@k8s-master-01 k8s-prom]# kubectl get svc -n prom -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORprometheus NodePort 10.102.109.46 <none> 9090:30090/TCP 9m18s app=prometheus,component=server
http://172.17.61.220:30090/targets

prometheus提供的PromQL无法直接作为自定义指标数据使用,它并非kubernetes系统的聚合API服务器,需要定一个中间层--kubernetes custom metrics adapter for prometheus,其中k8s-prometheus-adapter是一个很好的实现;
[root@k8s-master-01 k8s-prom]# kubectl apply -f k8s-prometheus-adapter/clusterrolebinding.rbac.authorization.k8s.io/custom-metrics:system:auth-delegator createdrolebinding.rbac.authorization.k8s.io/custom-metrics-auth-reader createddeployment.apps/custom-metrics-apiserver createdclusterrolebinding.rbac.authorization.k8s.io/custom-metrics-resource-reader createdserviceaccount/custom-metrics-apiserver createdservice/custom-metrics-apiserver createdWarning: apiregistration.k8s.io/v1beta1 APIService is deprecated in v1.19+, unavailable in v1.22+; use apiregistration.k8s.io/v1 APIServiceapiservice.apiregistration.k8s.io/v1beta1.custom.metrics.k8s.io createdclusterrole.rbac.authorization.k8s.io/custom-metrics-server-resources createdclusterrole.rbac.authorization.k8s.io/custom-metrics-resource-reader createdclusterrolebinding.rbac.authorization.k8s.io/hpa-controller-custom-metrics created
[root@k8s-master-01 k8s-prom]# cd /etc/kubernetes/pki/[root@k8s-master-01 pki]# (umask 077; openssl genrsa -out serving.key 2048)Generating RSA private key, 2048 bit long modulus...................................+++++.........................................+++++e is 65537 (0x10001)[root@k8s-master-01 pki]# openssl req -new -key serving.key -out serving.csr -subj "/CN=serving"[root@k8s-master-01 pki]# openssl x509 -req -in serving.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out serving.crt -days 3650Signature oksubject=/CN=servingGetting CA Private Key[root@k8s-master-01 pki]# kubectl create secret generic cm-adapter-serving-certs --from-file=serving.crt=./serving.crt --from-file=serving.key -n promsecret/cm-adapter-serving-certs created
[root@k8s-master-01 k8s-prometheus-adapter]# wget https://raw.githubusercontent.com/DirectXMan12/k8s-prometheus-adapter/master/deploy/manifests/custom-metrics-config-map.yaml[root@k8s-master-01 k8s-prometheus-adapter]# wget https://raw.githubusercontent.com/DirectXMan12/k8s-prometheus-adapter/master/deploy/manifests/custom-metrics-apiserver-deployment.yaml
[root@k8s-master-01 k8s-prometheus-adapter]# cat custom-metrics-apiserver-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:labels:app: custom-metrics-apiservername: custom-metrics-apiservernamespace: promspec:replicas: 1selector:matchLabels:app: custom-metrics-apiservertemplate:metadata:labels:app: custom-metrics-apiservername: custom-metrics-apiserverspec:serviceAccountName: custom-metrics-apiservercontainers:- name: custom-metrics-apiserverimage: directxman12/k8s-prometheus-adapter-amd64args:- --secure-port=6443- --tls-cert-file=/var/run/serving-cert/serving.crt- --tls-private-key-file=/var/run/serving-cert/serving.key- --logtostderr=true- --prometheus-url=http://prometheus.prom.svc:9090/- --metrics-relist-interval=1m- --v=10- --config=/etc/adapter/config.yamlports:- containerPort: 6443volumeMounts:- mountPath: /var/run/serving-certname: volume-serving-certreadOnly: true- mountPath: /etc/adapter/name: configreadOnly: true- mountPath: /tmpname: tmp-volvolumes:- name: volume-serving-certsecret:secretName: cm-adapter-serving-certs- name: configconfigMap:name: adapter-config- name: tmp-volemptyDir: {}
[root@k8s-master-01 k8s-prometheus-adapter]# cat custom-metrics-config-map.yamlapiVersion: v1kind: ConfigMapmetadata:name: adapter-confignamespace: promdata:config.yaml: |rules:- seriesQuery: '{__name__=~"^container_.*",container_name!="POD",namespace!="",pod_name!=""}'seriesFilters: []resources:overrides:namespace:resource: namespacepod_name:resource: podname:matches: ^container_(.*)_seconds_total$as: ""metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container_name!="POD"}[1m])) by (<<.GroupBy>>)- seriesQuery: '{__name__=~"^container_.*",container_name!="POD",namespace!="",pod_name!=""}'seriesFilters:- isNot: ^container_.*_seconds_total$resources:overrides:namespace:resource: namespacepod_name:resource: podname:matches: ^container_(.*)_total$as: ""metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container_name!="POD"}[1m])) by (<<.GroupBy>>)- seriesQuery: '{__name__=~"^container_.*",container_name!="POD",namespace!="",pod_name!=""}'seriesFilters:- isNot: ^container_.*_total$resources:overrides:namespace:resource: namespacepod_name:resource: podname:matches: ^container_(.*)$as: ""metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>,container_name!="POD"}) by (<<.GroupBy>>)- seriesQuery: '{namespace!="",__name__!~"^container_.*"}'seriesFilters:- isNot: .*_total$resources:template: <<.Resource>>name:matches: ""as: ""metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)- seriesQuery: '{namespace!="",__name__!~"^container_.*"}'seriesFilters:- isNot: .*_seconds_totalresources:template: <<.Resource>>name:matches: ^(.*)_total$as: ""metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)- seriesQuery: '{namespace!="",__name__!~"^container_.*"}'seriesFilters: []resources:template: <<.Resource>>name:matches: ^(.*)_seconds_total$as: ""metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)resourceRules:cpu:containerQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)nodeQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[1m])) by (<<.GroupBy>>)resources:overrides:instance:resource: nodenamespace:resource: namespacepod_name:resource: podcontainerLabel: container_namememory:containerQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>)nodeQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)resources:overrides:instance:resource: nodenamespace:resource: namespacepod_name:resource: podcontainerLabel: container_namewindow: 1mexternalRules:- seriesQuery: '{__name__=~"^.*_queue_(length|size)$",namespace!=""}'resources:overrides:namespace:resource: namespacename:matches: ^.*_queue_(length|size)$as: "$0"metricsQuery: max(<<.Series>>{<<.LabelMatchers>>})- seriesQuery: '{__name__=~"^.*_queue$",namespace!=""}'resources:overrides:namespace:resource: namespacename:matches: ^.*_queue$as: "$0"metricsQuery: max(<<.Series>>{<<.LabelMatchers>>})
[root@k8s-master-01 k8s-prometheus-adapter]# kubectl api-versions | grep customcustom.metrics.k8s.io/v1beta1
[root@k8s-master-01 k8s-prometheus-adapter]# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq '.resources[].name'"jobs.batch/go_memstats_buck_hash_sys_bytes""namespaces/process_virtual_memory_bytes""pods/go_memstats_lookups""jobs.batch/http_requests""pods/go_memstats_mspan_inuse_bytes""pods/http_requests_bucket""namespaces/http_requests_count""pods/http_requests_count""jobs.batch/kube_endpoint_address_available""pods/go_memstats_alloc_bytes""namespaces/go_memstats_last_gc_time_seconds""pods/go_memstats_other_sys_bytes""pods/scrape_samples_scraped""jobs.batch/kube_endpoint_address_not_ready""namespaces/kube_namespace_annotations""namespaces/http_requests"

rate(container_cpu_usage_seconds_total{image!=" ",pod_name!=" "}[1m])

sum by (pod)(rate(container_cpu_usage_seconds_total{image!=" ", pod_name!=" "}[1m] ))

[root@k8s-master-01 grafana]# cat grafana-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: grafana-corenamespace: promlabels:app: grafanacomponent: corespec:replicas: 1selector:matchLabels:app: grafanatemplate:metadata:labels:app: grafanacomponent: corespec:containers:- image: grafana/grafana:5.0.4name: grafana-coreimagePullPolicy: IfNotPresent# env:resources:# keep request = limit to keep this container in guaranteed classlimits:cpu: 100mmemory: 100Mirequests:cpu: 100mmemory: 100Mienv:# The following env variables set up basic auth twith the default admin user and admin password.- name: GF_AUTH_BASIC_ENABLEDvalue: "true"- name: GF_AUTH_ANONYMOUS_ENABLEDvalue: "false"# - name: GF_AUTH_ANONYMOUS_ORG_ROLE# value: Admin# does not really work, because of template variables in exported dashboards:# - name: GF_DASHBOARDS_JSON_ENABLED# value: "true"readinessProbe:httpGet:path: /loginport: 3000# initialDelaySeconds: 30# timeoutSeconds: 1volumeMounts:- name: grafana-persistent-storagemountPath: /varvolumes:- name: grafana-persistent-storageemptyDir: {}
[root@k8s-master-01 grafana]# cat grafana-svc.yamlapiVersion: v1kind: Servicemetadata:name: grafananamespace: promlabels:app: grafanacomponent: corespec:type: NodePortselector:app: grafanacomponent: coreports:- protocol: TCPport: 3000targetPort: 3000nodePort: 32220http://172.17.61.220:32220
[root@k8s-master-01 grafana]# kubectl get svc -n promNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEgrafana NodePort 10.101.121.39 <none> 3000:32220/TCP 11h
3.3.3 grafana展示界面配置
# User:admin# Password:admin

#配置prometheus源数据,https://prometheus:9090

#grafana官方站点有丰富的dashboard,可以自行下载导入。https://grafana.com/grafana/dashboards/162

<-------------------------------------------------------------------------->
Note:整套Prometheus创建完成后的所有资源状态:
[root@k8s-master-01 ~]# kubectl get deployment -n prom -o wideNAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTORalertmanager 1/1 1 1 21h alertmanager prom/alertmanager:v0.14.0 app=alertmanagercustom-metrics-apiserver 1/1 1 1 24h custom-metrics-apiserver directxman12/k8s-prometheus-adapter-amd64 app=custom-metrics-apiservergrafana-core 1/1 1 1 12h grafana-core grafana/grafana:5.0.4 app=grafanakube-state-metrics 1/1 1 1 3d15h kube-state-metrics gcr.io/google_containers/kube-state-metrics-amd64:v1.3.1 app=kube-state-metricsprometheus-server 1/1 1 1 20h prometheus prom/prometheus:v2.2.1 app=prometheus,component=server[root@k8s-master-01 ~]# kubectl get daemonset -n prom -o wideNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTORprometheus-node-exporter 4 4 4 4 4 <none> 24h prometheus-node-exporter prom/node-exporter:v0.15.2 app=prometheus,component=node-exporter[root@k8s-master-01 ~]# kubectl get pod -n prom -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESalertmanager-6656585ccd-2xp95 1/1 Running 0 21h 10.244.3.80 k8s-worker-02 <none> <none>custom-metrics-apiserver-55c849446d-g2kn6 1/1 Running 0 24h 10.244.3.69 k8s-worker-02 <none> <none>grafana-core-657675c8d9-8frnw 1/1 Running 0 12h 10.244.3.99 k8s-worker-02 <none> <none>kube-state-metrics-7b99db8cdb-22vdz 1/1 Running 0 3d15h 10.244.3.13 k8s-worker-02 <none> <none>prometheus-0 2/2 Running 0 19h 10.244.3.86 k8s-worker-02 <none> <none>prometheus-node-exporter-42z4b 1/1 Running 0 24h 172.17.61.223 k8s-worker-02 <none> <none>prometheus-node-exporter-cn5tl 1/1 Running 0 9m25s 172.17.61.222 k8s-worker-01 <none> <none>prometheus-node-exporter-gmnmv 1/1 Running 0 24h 172.17.61.220 k8s-master-01 <none> <none>prometheus-node-exporter-jd7qt 1/1 Running 0 24h 172.17.61.221 k8s-master-02 <none> <none>prometheus-server-75d864d655-h5cf7 1/1 Running 0 20h 10.244.3.85 k8s-worker-02 <none> <none>[root@k8s-master-01 ~]# kubectl get svc -n prom -o wideNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORalertmanager ClusterIP 10.97.198.54 <none> 80/TCP 21h app=alertmanagercustom-metrics-apiserver ClusterIP 10.96.103.132 <none> 443/TCP 24h app=custom-metrics-apiservergrafana NodePort 10.101.121.39 <none> 3000:32220/TCP 12h app=grafana,component=corekube-state-metrics ClusterIP 10.100.241.139 <none> 8080/TCP 3d16h app=kube-state-metricsprometheus NodePort 10.99.13.9 <none> 9090:30090/TCP 20h app=prometheus,component=serverprometheus-node-exporter ClusterIP None <none> 9100/TCP 24h app=prometheus,component=node-exporter[root@k8s-master-01 ~]# kubectl get configmap -n prom -o wideNAME DATA AGEadapter-config 1 24halertmanager-config 1 21hprometheus-config 1 20hprometheus-rules 2 21h
<-------------------------------------------------------------------------->
目前HPA分为两个版本v1、v2;
[root@k8s-master-01 HPA]# kubectl api-versions | grep autoscalautoscaling/v1autoscaling/v2beta1autoscaling/v2beta2
HPAv1默认使用Heapster进行数据采集,只能根据CPU指标进行缩放;
[root@k8s-master-01 HPA]# cat hpa-v1-deployment_web.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: webspec:replicas: 1selector:matchLabels:app: java-demotemplate:metadata:labels:app: java-demospec:containers:- image: lizhenliang/java-demoname: javaresources:requests:memory: "300Mi"cpu: "250m"---apiVersion: v1kind: Servicemetadata:name: webspec:type: NodePortports:- port: 80protocol: TCPtargetPort: 8080nodePort: 32227selector:app: java-demo
[root@k8s-master-01 HPA]# cat hpa-v1.yamlapiVersion: autoscaling/v1kind: HorizontalPodAutoscalermetadata:name: webspec:maxReplicas: 5minReplicas: 1scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: webtargetCPUUtilizationPercentage: 2[root@k8s-master-01 HPA]# kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEmetrics-app-hpa Deployment/metrics-app 500m/800m 2 10 2 9hweb Deployment/web 1%/2% 1 5 5 16m[root@k8s-master-01 HPA]# kubectl get hpa web -o yamlapiVersion: autoscaling/v1kind: HorizontalPodAutoscalermetadata:...managedFields:- apiVersion: autoscaling/v1fieldsType: FieldsV1...- apiVersion: autoscaling/v1fieldsType: FieldsV1...name: webnamespace: defaultspec:maxReplicas: 5minReplicas: 1scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: webtargetCPUUtilizationPercentage: 2status:currentCPUUtilizationPercentage: 1currentReplicas: 5desiredReplicas: 5lastScaleTime: "2020-11-22T23:43:25Z"
[root@k8s-master-01 HPA]# yum install httpd-tools[root@k8s-master-01 HPA]# ab -n 80000 -c 800 http://localhost:32227/This is ApacheBench, Version 2.3 <$Revision: 1430300 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking localhost (be patient)Completed 8000 requestsCompleted 16000 requestsCompleted 24000 requestsCompleted 32000 requestsCompleted 40000 requestsCompleted 48000 requestsCompleted 56000 requestsCompleted 64000 requestsCompleted 72000 requestsCompleted 80000 requestsFinished 80000 requests[root@k8s-master-01 HPA]# kubectl get podsNAME READY STATUS RESTARTS AGEweb-cc846d4fb-dx5bc 0/1 Pending 0 69sweb-cc846d4fb-f69fq 1/1 Running 0 22mweb-cc846d4fb-q9629 0/1 Pending 0 53sweb-cc846d4fb-qn7xr 1/1 Running 0 69sweb-cc846d4fb-qwst2 0/1 Pending 0 69s[root@k8s-master-01 HPA]# kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEweb Deployment/web 17%/2% 1 5 5 28m[root@k8s-master-01 HPA]# kubectl describe hpa web...Events:Type Reason Age From Message---- ------ ---- ---- -------Normal SuccessfulRescale 3m15s horizontal-pod-autoscaler New size: 1; reason: All metrics below targetNormal SuccessfulRescale 119s (x2 over 12m) horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above targetNormal SuccessfulRescale 103s (x2 over 11m) horizontal-pod-autoscaler New size: 5; reason: cpu resource utilization (percentage of request) above target
HPAv2从metrics-server中请求资源指标,从k8s-promehteus-adapter一类自定义API中获取自定义指标数据,从而可以基于核心指标CPU和内存资源以及任意自定义指标占用情况进行弹性伸缩;
#metrics-app可以输出特定的资源指标供HPA监控[root@k8s-master-01 HPA]# cat hpa-v2-deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:labels:app: metrics-appname: metrics-appspec:replicas: 2selector:matchLabels:app: metrics-apptemplate:metadata:labels:app: metrics-appannotations:prometheus.io/scrape: "true"prometheus.io/port: "80"prometheus.io/path: "/metrics"spec:containers:- image: ikubernetes/metrics-appname: metrics-appports:- name: webcontainerPort: 80resources:requests:cpu: 200mmemory: 256MireadinessProbe:httpGet:path: /port: 80initialDelaySeconds: 3periodSeconds: 5livenessProbe:httpGet:path: /port: 80initialDelaySeconds: 3periodSeconds: 5---apiVersion: v1kind: Servicemetadata:name: metrics-applabels:app: metrics-appspec:ports:- name: webport: 80targetPort: 80selector:app: metrics-app[root@k8s-master-01 HPA]# kubectl apply -f hpa-v2-deployment.yamldeployment.apps/metrics-app createdservice/metrics-app created[root@k8s-master-01 HPA]# kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d6hmetrics-app ClusterIP 10.106.192.12 <none> 80/TCP 20smyapp ClusterIP 10.109.50.132 <none> 80/TCP 49mmyapp-svc-nodeport NodePort 10.101.208.103 <none> 80:32223/TCP 25mpodinfo NodePort 10.109.61.187 <none> 9898:31198/TCP 155m#测试metrics-app输出资源指标的情况[root@k8s-master-01 HPA]# curl 10.106.192.12/metrics# HELP http_requests_total The amount of requests in total# TYPE http_requests_total counterhttp_requests_total 11# HELP http_requests_per_second The amount of requests per second the latest ten seconds# TYPE http_requests_per_second gaugehttp_requests_per_second 0.6
[root@k8s-master-01 HPA]# cat hpa-v2.yamlapiVersion: autoscaling/v2beta1kind: HorizontalPodAutoscalermetadata:name: metrics-app-hpaspec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: metrics-appminReplicas: 2maxReplicas: 10metrics:- type: Podspods:#HPA监控metics-app的http_requests_per_second指标metricName: http_requests_per_secondtargetAverageValue: 800m#800m即0.8个/秒
[root@k8s-master-01 HPA]# kubectl get hpa metrics-app-hpa -o yaml- apiVersion: autoscaling/v2beta1fieldsType: FieldsV1fieldsV1:...spec:maxReplicas: 10minReplicas: 2scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: metrics-appstatus:currentReplicas: 2desiredReplicas: 2lastScaleTime: "2020-11-22T14:57:31Z"
[root@k8s-master-01 HPA]# kubectl run client -it --image=cirros --rm -- /bin/sh/ # while true; do curl http://metrics-app; let i++; sleep 0.$RANDOM; done[root@k8s-master-01 HPA]# kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEmetrics-app-hpa Deployment/metrics-app 675m/800m 2 10 7 2m10s[root@k8s-master-01 HPA]# kubectl describe hpa metrics-app-hpaName: metrics-app-hpaNamespace: defaultLabels: <none>Annotations: <none>CreationTimestamp: Sun, 22 Nov 2020 22:45:25 +0800Reference: Deployment/metrics-appMetrics: ( current / target )"http_requests_per_second" on pods: 500m / 800mMin replicas: 2Max replicas: 10Deployment pods: 7 current / 7 desiredConditions:Type Status Reason Message---- ------ ------ -------AbleToScale True ScaleDownStabilized recent recommendations were higher than current one, applying the highest recent recommendationScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests_per_secondScalingLimited False DesiredWithinRange the desired count is within the acceptable rangeEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal SuccessfulRescale 65s horizontal-pod-autoscaler New size: 4; reason: pods metric http_requests_per_second above targetNormal SuccessfulRescale 50s horizontal-pod-autoscaler New size: 6; reason: pods metric http_requests_per_second above targetNormal SuccessfulRescale 35s horizontal-pod-autoscaler New size: 7; reason: pods metric http_requests_per_second above target#通过查看HPA的详情可以观察到HPA的弹性缩放效果已经生效;




