概述
已經(jīng)有了cadvisor匾效、heapster惩妇、metric-server,幾乎容器運(yùn)行的所有指標(biāo)都能拿到冒版,但是下面這種情況卻無(wú)能為力:
- 我調(diào)度了多少個(gè)replicas液茎?現(xiàn)在可用的有幾個(gè)?
- 多少個(gè)Pod是running/stopped/terminated狀態(tài)辞嗡?
- Pod重啟了多少次捆等?
- 我有多少job在運(yùn)行中
而這些則是kube-state-metrics提供的內(nèi)容,它基于client-go開發(fā)续室,輪詢Kubernetes API栋烤,并將Kubernetes的結(jié)構(gòu)化信息轉(zhuǎn)換為metrics。
功能
kube-state-metrics提供的指標(biāo)挺狰,按照階段分為三種類別:
1.實(shí)驗(yàn)性質(zhì)的:k8s api中alpha階段的或者spec的字段明郭。
2.穩(wěn)定版本的:k8s中不向后兼容的主要版本的更新
3.被廢棄的:已經(jīng)不在維護(hù)的买窟。
指標(biāo)類別包括:
- CronJob Metrics
- DaemonSet Metrics
- Deployment Metrics
- Job Metrics
- LimitRange Metrics
- Node Metrics
- PersistentVolume Metrics
- PersistentVolumeClaim Metrics
- Pod Metrics
- Pod Disruption Budget Metrics
- ReplicaSet Metrics
- ReplicationController Metrics
- ResourceQuota Metrics
- Service Metrics
- StatefulSet Metrics
- Namespace Metrics
- Horizontal Pod Autoscaler Metrics
- Endpoint Metrics
- Secret Metrics
- ConfigMap Metrics
以pod為例:
- kube_pod_info
- kube_pod_owner
- kube_pod_status_phase
- kube_pod_status_ready
- kube_pod_status_scheduled
- kube_pod_container_status_waiting
- kube_pod_container_status_terminated_reason
- ...
使用
部署清單:
kube-state-metrics/
├── kube-state-metrics-cluster-role-binding.yaml
├── kube-state-metrics-cluster-role.yaml
├── kube-state-metrics-deployment.yaml
├── kube-state-metrics-role-binding.yaml
├── kube-state-metrics-role.yaml
├── kube-state-metrics-service-account.yaml
├── kube-state-metrics-service.yaml
主要鏡像有:
image: quay.io/coreos/kube-state-metrics:v1.5.0
image: k8s.gcr.io/addon-resizer:1.8.3(參考metric-server文章,用于擴(kuò)縮容)
對(duì)于pod的資源限制薯定,一般情況下:
200MiB memory 0.1 cores
超過(guò)100節(jié)點(diǎn)的集群:
2MiB memory per node 0.001 cores per node
kube-state-metrics做過(guò)一次性能優(yōu)化始绍,具體內(nèi)容參考下文
部署成功后,prometheus的target會(huì)出現(xiàn)如下標(biāo)志
因?yàn)閗ube-state-metrics-service.yaml中有prometheus.io/scrape: 'true'
標(biāo)識(shí)话侄,因此會(huì)將metric暴露給prometheus亏推,而Prometheus會(huì)在kubernetes-service-endpoints這個(gè)job下自動(dòng)發(fā)現(xiàn)kube-state-metrics,并開始拉取metrics满葛,無(wú)需其他配置。
使用kube-state-metrics后的常用場(chǎng)景有:
- 存在執(zhí)行失敗的Job: kube_job_status_failed{job="kubernetes-service-endpoints",k8s_app="kube-state-metrics"}==1
- 集群節(jié)點(diǎn)狀態(tài)錯(cuò)誤: kube_node_status_condition{condition="Ready",status!="true"}==1
- 集群中存在啟動(dòng)失敗的Pod:kube_pod_status_phase{phase=~"Failed|Unknown"}==1
- 最近30分鐘內(nèi)有Pod容器重啟: changes(kube_pod_container_status_restarts[30m])>0
配合報(bào)警可以更好地監(jiān)控集群的運(yùn)行
與metric-server的對(duì)比
- metric-server(或heapster)是從api-server中獲取cpu罢屈、內(nèi)存使用率這種監(jiān)控指標(biāo)嘀韧,并把他們發(fā)送給存儲(chǔ)后端,如influxdb或云廠商缠捌,他當(dāng)前的核心作用是:為HPA等組件提供決策指標(biāo)支持锄贷。
- kube-state-metrics關(guān)注于獲取k8s各種資源的最新狀態(tài),如deployment或者daemonset曼月,之所以沒有把kube-state-metrics納入到metric-server的能力中谊却,是因?yàn)樗麄兊年P(guān)注點(diǎn)本質(zhì)上是不一樣的。metric-server僅僅是獲取哑芹、格式化現(xiàn)有數(shù)據(jù)炎辨,寫入特定的存儲(chǔ),實(shí)質(zhì)上是一個(gè)監(jiān)控系統(tǒng)聪姿。而kube-state-metrics是將k8s的運(yùn)行狀況在內(nèi)存中做了個(gè)快照碴萧,并且獲取新的指標(biāo),但他沒有能力導(dǎo)出這些指標(biāo)
- 換個(gè)角度講末购,kube-state-metrics本身是metric-server的一種數(shù)據(jù)來(lái)源破喻,雖然現(xiàn)在沒有這么做。
- 另外盟榴,像Prometheus這種監(jiān)控系統(tǒng)曹质,并不會(huì)去用metric-server中的數(shù)據(jù),他都是自己做指標(biāo)收集擎场、集成的(Prometheus包含了metric-server的能力)羽德,但Prometheus可以監(jiān)控metric-server本身組件的監(jiān)控狀態(tài)并適時(shí)報(bào)警停蕉,這里的監(jiān)控就可以通過(guò)kube-state-metrics來(lái)實(shí)現(xiàn)凌蔬,如metric-serverpod的運(yùn)行狀態(tài)粥脚。
深入解析
kube-state-metrics本質(zhì)上是不斷輪詢api-server盗冷,代碼結(jié)構(gòu)也很簡(jiǎn)單
主要代碼目錄
.
├── collectors
│ ├── builder.go
│ ├── collectors.go
│ ├── configmap.go
│ ......
│ ├── testutils.go
│ ├── testutils_test.go
│ └── utils.go
├── constant
│ └── resource_unit.go
├── metrics
│ ├── metrics.go
│ └── metrics_test.go
├── metrics_store
│ ├── metrics_store.go
│ └── metrics_store_test.go
├── options
│ ├── collector.go
│ ├── options.go
│ ├── options_test.go
│ ├── types.go
│ └── types_test.go
├── version
│ └── version.go
└── whiteblacklist
├── whiteblacklist.go
└── whiteblacklist_test.go
所有類型:
var (
DefaultNamespaces = NamespaceList{metav1.NamespaceAll}
DefaultCollectors = CollectorSet{
"daemonsets": struct{}{},
"deployments": struct{}{},
"limitranges": struct{}{},
"nodes": struct{}{},
"pods": struct{}{},
"poddisruptionbudgets": struct{}{},
"replicasets": struct{}{},
"replicationcontrollers": struct{}{},
"resourcequotas": struct{}{},
"services": struct{}{},
"jobs": struct{}{},
"cronjobs": struct{}{},
"statefulsets": struct{}{},
"persistentvolumes": struct{}{},
"persistentvolumeclaims": struct{}{},
"namespaces": struct{}{},
"horizontalpodautoscalers": struct{}{},
"endpoints": struct{}{},
"secrets": struct{}{},
"configmaps": struct{}{},
}
)
構(gòu)建對(duì)應(yīng)的收集器
Family即一個(gè)類型的資源集合聊闯,如job下的kube_job_info缸兔、kube_job_created陨囊,都是一個(gè)FamilyGenerator實(shí)例
metrics.FamilyGenerator{
Name: "kube_job_info",
Type: metrics.MetricTypeGauge,
Help: "Information about job.",
GenerateFunc: wrapJobFunc(func(j *v1batch.Job) metrics.Family {
return metrics.Family{&metrics.Metric{
Name: "kube_job_info",
Value: 1,
}}
}),
},
func (b *Builder) buildCronJobCollector() *Collector {
// 過(guò)濾傳入的白名單
filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, cronJobMetricFamilies)
composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies)
// 將參數(shù)寫到header中
familyHeaders := extractMetricFamilyHeaders(filteredMetricFamilies)
// NewMetricsStore實(shí)現(xiàn)了client-go的cache.Store接口爷怀,實(shí)現(xiàn)本地緩存。
store := metricsstore.NewMetricsStore(
familyHeaders,
composedMetricGenFuncs,
)
// 按namespace構(gòu)建Reflector匀伏,監(jiān)聽變化
reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1beta1.CronJob{}, store, b.namespaces, createCronJobListWatch)
return NewCollector(store)
}
性能優(yōu)化:
kube-state-metrics在之前的版本中暴露出兩個(gè)問(wèn)題:
- /metrics接口響應(yīng)慢(10-20s)
- 內(nèi)存消耗太大洒忧,導(dǎo)致超出limit被殺掉
問(wèn)題一的方案就是基于client-go的cache tool實(shí)現(xiàn)本地緩存,具體結(jié)構(gòu)為:
var cache = map[uuid][]byte{}
問(wèn)題二的的方案是:對(duì)于時(shí)間序列的字符串够颠,是存在很多重復(fù)字符的(如namespace等前綴篩選)熙侍,可以用指針或者結(jié)構(gòu)化這些重復(fù)字符。
優(yōu)化點(diǎn)和問(wèn)題
- 1.因?yàn)閗ube-state-metrics是監(jiān)聽資源的add履磨、delete蛉抓、update事件,那么在kube-state-metrics部署之前已經(jīng)運(yùn)行的資源剃诅,豈不是拿不到數(shù)據(jù)巷送?kube-state-metric利用client-go可以初始化所有已經(jīng)存在的資源對(duì)象,確保沒有任何遺漏
- 2.kube-state-metrics當(dāng)前不會(huì)輸出metadata信息(如help和description)
- 3.緩存實(shí)現(xiàn)是基于golang的map矛辕,解決并發(fā)讀問(wèn)題當(dāng)期是用了一個(gè)簡(jiǎn)單的互斥鎖笑跛,應(yīng)該可以解決問(wèn)題,后續(xù)會(huì)考慮golang的sync.Map安全map聊品。
- 4.kube-state-metrics通過(guò)比較resource version來(lái)保證event的順序
- 5.kube-state-metrics并不保證包含所有資源
監(jiān)控?cái)?shù)據(jù)展示
基于kube-state-metrics的監(jiān)控?cái)?shù)據(jù)飞蹂,可以組裝一些常用的監(jiān)控面板,如下面的grafana面板
本文為容器監(jiān)控實(shí)踐系列文章翻屈,完整內(nèi)容見:container-monitor-book