容器監(jiān)控
說到容器監(jiān)控自然會想到cAdvisor,前面也說過cAdvisor已經(jīng)內(nèi)置在了 kubelet 組件之中,所以不需要單獨去安裝,cAdvisor的數(shù)據(jù)路徑為/api/v1/nodes/<node>/proxy/metrics,同樣這里使用 node 的服務(wù)發(fā)現(xiàn)模式,因為每一個節(jié)點下面都有 kubelet,自然都有cAdvisor采集到的數(shù)據(jù)指標(biāo),配置如下:
$ vim prometheus-configmap.yaml 添加如下內(nèi)容
- job_name: kubernetes-nodes-cadvisor
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __metrics_path__
replacement: /metrics/cadvisor
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
上面的配置和之前配置 node-exporter 的時候幾乎是一樣的,區(qū)別是這里使用了 https 的協(xié)議,另外需要注意的是配置了 ca.cart 和 token 這兩個文件,這兩個文件是 Pod 啟動后自動注入進來的,通過這兩個文件我們可以在 Pod 中訪問 apiserver,比如這里的__address__不在是 nodeip 了,而是 kubernetes 在集群中的服務(wù)地址,然后加上__metrics_path__的訪問路徑:/api/v1/nodes/${1}/proxy/metrics/cadvisor,現(xiàn)在同樣更新下配置,然后查看 Targets 路徑:

然后可以切換到 Graph 路徑下面查詢?nèi)萜飨嚓P(guān)數(shù)據(jù),比如查詢集群中所有 Pod 的 CPU 使用情況,這里用的數(shù)據(jù)指標(biāo)是 container_cpu_usage_seconds_total,然后去除一些無效的數(shù)據(jù),查詢1分鐘內(nèi)的數(shù)據(jù),由于查詢到的數(shù)據(jù)都是容器相關(guān)的,最好要安裝 Pod 來進行聚合,對應(yīng)的promQL語句如下:
sum by (pod_name)(rate(container_cpu_usage_seconds_total{image!="", pod_name!=""}[1m] ))

可以看到上面的結(jié)果就是集群中的所有 Pod 在1分鐘之內(nèi)的 CPU 使用情況的曲線圖,當(dāng)然還有很多數(shù)據(jù)可以獲取到。
apiserver 監(jiān)控
$ vim prometheus-configmap.yaml 添加如下內(nèi)容
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
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, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https

Service 的監(jiān)控
上面的 apiserver 實際上是一種特殊的 Service,現(xiàn)在同樣來配置一個任務(wù)用來專門發(fā)現(xiàn)普通類型的 Service:
$ vim prometheus-configmap.yaml 添加如下內(nèi)容
- 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
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: kubernetes_name
注意這里在relabel_configs區(qū)域做了大量的配置,特別是第一個保留__meta_kubernetes_service_annotation_prometheus_io_scrape為true的才保留下來,這就是說要想自動發(fā)現(xiàn)集群中的 Service,就需要在 Service 的annotation區(qū)域添加prometheus.io/scrape=true的聲明。
可以看到kubernetes-service-endpoints這一個任務(wù)下面只發(fā)現(xiàn)了一個服務(wù),這是因為我們在relabel_configs中過濾了 annotation 有prometheus.io/scrape=true的 Service,而現(xiàn)在我們系統(tǒng)中只有這樣一個服務(wù)符合要求,所以只出現(xiàn)了一個實例。
現(xiàn)在在之前創(chuàng)建的 redis 這個 Service 中添加上prometheus.io/scrape=true這個 annotation:(prome-redis.yaml)
kind: Service
apiVersion: v1
metadata:
name: redis
namespace: kube-ops
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9121"
spec:
selector:
app: redis
ports:
- name: redis
port: 6379
targetPort: 6379
- name: prom
port: 9121
targetPort: 9121
由于 redis 服務(wù)的 metrics 接口在9121這個 redis-exporter 服務(wù)上面,所以我們還需要添加一個prometheus.io/port=9121這樣的annotations,然后更新這個 Service:
$ kubectl apply -f prome-redis-exporter.yaml
deployment.extensions "redis" unchanged
service "redis" changed
更新完成后,去 Prometheus 查看 Targets 路徑,可以看到 redis 服務(wù)自動出現(xiàn)在了kubernetes-service-endpoints這個任務(wù)下面
這樣以后有了新的服務(wù),服務(wù)本身提供了/metrics接口,就完全不需要用靜態(tài)的方式去配置了,到這里就可以將之前配置的 redis 的靜態(tài)配置去掉了。
kube-state-metrics
上面配置了自動發(fā)現(xiàn) Service(Pod也是一樣的)的監(jiān)控,但是這些監(jiān)控數(shù)據(jù)都是應(yīng)用內(nèi)部的監(jiān)控,需要應(yīng)用本身提供一個/metrics接口,或者對應(yīng)的 exporter 來暴露對應(yīng)的指標(biāo)數(shù)據(jù),但是在 Kubernetes 集群上 Pod、DaemonSet、Deployment、Job、CronJob 等各種資源對象的狀態(tài)也需要監(jiān)控,這也反映了使用這些資源部署的應(yīng)用的狀態(tài)。但通過查看前面從集群中拉取的指標(biāo)(這些指標(biāo)主要來自 apiserver 和 kubelet 中集成的 cAdvisor),并沒有具體的各種資源對象的狀態(tài)指標(biāo)。對于 Prometheus 來說,當(dāng)然是需要引入新的 exporter 來暴露這些指標(biāo),Kubernetes 提供了一個kube-state-metrics就是我們需要的。
kube-state-metrics 已經(jīng)給出了在 Kubernetes 部署的 manifest 定義文件,我們直接將代碼 Clone 到集群中(能用 kubectl 工具操作就行):
$ git clone https://github.com/kubernetes/kube-state-metrics.git
$ cd kube-state-metrics/kubernetes
$ kubectl create -f .
clusterrolebinding.rbac.authorization.k8s.io "kube-state-metrics" created
clusterrole.rbac.authorization.k8s.io "kube-state-metrics" created
deployment.apps "kube-state-metrics" created
rolebinding.rbac.authorization.k8s.io "kube-state-metrics" created
role.rbac.authorization.k8s.io "kube-state-metrics-resizer" created
serviceaccount "kube-state-metrics" created
service "kube-state-metrics" created
將 kube-state-metrics 部署到 Kubernetes 上之后,就會發(fā)現(xiàn) Kubernetes 集群中的 Prometheus 會在kubernetes-service-endpoints 這個 job 下自動服務(wù)發(fā)現(xiàn) kube-state-metrics,并開始拉取 metrics,這是因為部署 kube-state-metrics 的 manifest 定義文件 kube-state-metrics-service.yaml 對 Service 的定義包含prometheus.io/scrape: 'true'這樣的一個annotation,因此 kube-state-metrics 的 endpoint 可以被 Prometheus 自動服務(wù)發(fā)現(xiàn)。
關(guān)于 kube-state-metrics 暴露的所有監(jiān)控指標(biāo)可以參考 kube-state-metrics 的文檔kube-state-metrics Documentation。