部署好了 kube-prometheus 與 k8s-prometheus-adapter (詳見之前的博文 k8s 安裝 prometheus 過程記錄),使用下面的配置文件部署 HPA(Horizontal Pod Autoscaling) 卻失敗。
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: blog-web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: blog-web
minReplicas: 2
maxReplicas: 12
metrics:
- type: Pods
pods:
metric:
name: http_requests
target:
type: AverageValue
averageValue: 100
錯誤信息如下:
unable to get metric http_requests: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests for pods
通過下面的命令查看 custom.metrics.k8s.io api 支持的 http_requests(每秒請求數QPS)監控指標:
$kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/ | jq . | egrep pods/.*http_requests
"name": "pods/alertmanager_http_requests_in_flight",
"name": "pods/prometheus_http_requests"
發現只有 prometheus_http_requests 指標 ,沒有所需的 http_requests 開頭的指標。
打開 prometheus 控制台,發現 /service-discovery 中沒有出現我們想監控的應用 blog-web ,網上查找資料后知道了需要部署 ServiceMonitor 讓 prometheus 發現所監控的 service 。
添加下面的 ServiceMonitor 配置文件:
kind: ServiceMonitor
apiVersion: monitoring.coreos.com/v1
metadata:
name: blog-web-monitor
labels:
app: blog-web-monitor
spec:
selector:
matchLabels:
app: blog-web
endpoints:
- port: http
部署后還是沒有被 prometheus 發現,查看 prometheus 的日志發現下面的錯誤:
Failed to list *v1.Pod: pods is forbidden: User \"system:serviceaccount:monitoring:prometheus-k8s\" cannot list resource \"pods\" in API group \"\" at the cluster scope
在園子里的博文 PrometheusOperator服務自動發現-監控redis樣例 中找到了解決方法,將 prometheus-clusterRole.yaml 改為下面的配置:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-k8s
rules:
- apiGroups:
- ""
resources:
- nodes
- services
- endpoints
- pods
- nodes/proxy
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
- nodes/metrics
verbs:
- get
- nonResourceURLs:
- /metrics
verbs:
- get
重新部署即可
kubectl apply -f prometheus-clusterRole.yaml
注1:如果采用上面的方法還是沒被發現,需要強制刷新 prometheus 的配置,參考 部署 ServiceMonitor 之后如何讓 Prometheus 立即發現 。
注2:也可以將 prometheus 配置為自動發現 service 與 pod ,參考園子里的博文 prometheus配置pod和svc的自動發現和監控 與 PrometheusOperator服務自動發現-監控redis樣例 。
但是這時還有問題,雖然 service 被 prometheus 發現了,但 service 所對應的 pod 一個都沒被發現。
production/blog-web-monitor/0 (0/19 active targets)
排查后發現是因為 ServiceMonitor 與 Service 配置不對應,Service 配置文件中缺少 ServiceMonitor 配置中 matchLabels 所對應的 label ,ServiceMonitor 中的 port 沒有對應 Service 中的 ports 配置,修正后的配置如下:
service-blog-web.yaml
apiVersion: v1
kind: Service
metadata:
name: blog-web
labels:
app: blog-web
spec:
type: NodePort
selector:
app: blog-web
ports:
- name: http-blog-web
nodePort: 30080
port: 80
targetPort: 80
servicemonitor-blog-web.yaml
kind: ServiceMonitor
apiVersion: monitoring.coreos.com/v1
metadata:
name: blog-web-monitor
labels:
app: blog-web
spec:
selector:
matchLabels:
app: blog-web
endpoints:
- port: http-blog-web
用修正后的配置部署后,pod 終於被發現了:
production/blog-web-monitor/0 (0/5 up)
但是這些 pod 全部處於 down 狀態。
Endpoint State Scrape Duration Error
http://192.168.107.233:80/metrics DOWN server returned HTTP status 400 Bad Request
通過園子里的博文 使用Kubernetes演示金絲雀發布 知道了原來需要應用自己提供 metrics 監控指標數據讓 prometheus 抓取。
標准Tomcat自帶的應用沒有/metrics這個路徑,prometheus獲取不到它能識別的格式數據,而指標數據就是從/metrics這里獲取的。所以我們使用標准Tomcat不行或者你就算有這個/metrics這個路徑,但是返回的格式不符合prometheus的規范也是不行的。
我們的應用是用 ASP.NET Core 開發的,所以選用了 prometheus-net ,由它提供 metrics 數據給 prometheus 抓取。
- 安裝 nuget 包
dotnet add package prometheus-net.AspNetCore
- 添加 HttpMetrics 中間件
app.UseRouting();
app.UseHttpMetrics();
- 添加 MapMetric 路由
app.UseEndpoints(endpoints =>
{
endpoints.MapMetrics();
};
當通過下面的命令確認通過 /metrics 路徑可以獲取監控數據時,
$ docker exec -t $(docker ps -f name=blog-web_blog-web -q | head -1) curl 127.0.0.1/metrics | grep http_request_duration_seconds_sum
http_request_duration_seconds_sum{code="200",method="GET",controller="AggSite",action="SiteHome"} 0.44973779999999997
http_request_duration_seconds_sum{code="200",method="GET",controller="",action=""} 0.0631272
Prometheus 控制台 /targets 頁面就能看到 blog-web 對應的 pod 都處於 up 狀態。
production/blog-web-monitor/0 (5/5 up)
這時通過 custom metrics api 可以查詢到一些 http_requests 相關的指標。
$ kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/ | jq . | egrep pods/*/http_requests
"name": "pods/http_requests_in_progress",
"name": "pods/http_requests_received"
這里的 http_requests_received 就是 QPS(每秒請求數) 指標數據,用下面的命令請求 custom metrics api 獲取數據:
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/production/pods/*/http_requests_received | jq .
其中1個 pod 的 http_requests_received 指標數據如下:
{
"kind": "MetricValueList",
"apiVersion": "custom.metrics.k8s.io/v1beta1",
"metadata": {
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/namespaces/production/pods/%2A/http_requests_received"
},
"items": [
{
"describedObject": {
"kind": "Pod",
"namespace": "production",
"name": "blog-web-65f7bdc996-8qp5c",
"apiVersion": "/v1"
},
"metricName": "http_requests_received",
"timestamp": "2020-01-18T14:35:34Z",
"value": "133m",
"selector": null
}
]
}
其中的 133m 表示 0.133 。
然后就可以在 HPA 配置文件中基於這個指標進行自動伸縮
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: blog-web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: blog-web
minReplicas: 5
maxReplicas: 12
metrics:
- type: Pods
pods:
metric:
name: http_requests_received
target:
type: AverageValue
averageValue: 100
終於搞定了!
# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
blog-web Deployment/blog-web 133m/100 5 12 5 4d
