zccheu 2019-06-30
已经有了cadvisor、heapster、metric-server,几乎容器运行的所有指标都能拿到,但是下面这种情况却无能为力:
而这些则是kube-state-metrics提供的内容,它基于client-go开发,轮询Kubernetes API,并将Kubernetes的结构化信息转换为metrics。
kube-state-metrics提供的指标,按照阶段分为三种类别:
指标类别包括:
以pod为例:
部署清单:
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文章,用于扩缩容)
对于pod的资源限制,一般情况下:
`
200MiB memory
0.1 cores`
超过100节点的集群:
`
2MiB memory per node
0.001 cores per node`
kube-state-metrics做过一次性能优化,具体内容参考下文
部署成功后,prometheus的target会出现如下标志
因为kube-state-metrics-service.yaml中有prometheus.io/scrape: 'true'
标识,因此会将metric暴露给prometheus,而Prometheus会在kubernetes-service-endpoints这个job下自动发现kube-state-metrics,并开始拉取metrics,无需其他配置。
使用kube-state-metrics后的常用场景有:
配合报警可以更好地监控集群的运行
kube-state-metrics本质上是不断轮询api-server,代码结构也很简单
主要代码目录
. ├── 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{}{}, } )
构建对应的收集器
Family即一个类型的资源集合,如job下的kube_job_info、kube_job_created,都是一个FamilyGenerator实例
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 { // 过滤传入的白名单 filteredMetricFamilies := filterMetricFamilies(b.whiteBlackList, cronJobMetricFamilies) composedMetricGenFuncs := composeMetricGenFuncs(filteredMetricFamilies) // 将参数写到header中 familyHeaders := extractMetricFamilyHeaders(filteredMetricFamilies) // NewMetricsStore实现了client-go的cache.Store接口,实现本地缓存。 store := metricsstore.NewMetricsStore( familyHeaders, composedMetricGenFuncs, ) // 按namespace构建Reflector,监听变化 reflectorPerNamespace(b.ctx, b.kubeClient, &batchv1beta1.CronJob{}, store, b.namespaces, createCronJobListWatch) return NewCollector(store) }
性能优化:
kube-state-metrics在之前的版本中暴露出两个问题:
问题一的方案就是基于client-go的cache tool实现本地缓存,具体结构为:
`var cache = map[uuid][]byte{}
`
问题二的的方案是:对于时间序列的字符串,是存在很多重复字符的(如namespace等前缀筛选),可以用指针或者结构化这些重复字符。
本文为容器监控实践系列文章,完整内容见:container-monitor-book