Kubernetes 集群与应用监控实战:从 Heapster 到 Prometheus 的云原生可观测体系
【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
Kubernetes 将复杂的应用环境管理变得简单,但要对集群自身的各组件以及运行在其上的应用做到良好"洞察"却并不容易。本文以 Kubernetes Handbook 的监控实践为主线,完整讲解 Kubernetes 监控的三大层次(集群组件、Pod、应用)、cAdvisor 数据模型与容器命名规则、Heapster/InfluxDB/Grafana 的部署与 API 使用、应用级监控架构以及基于 Weave Scope 的应用拓扑可视化,并梳理 Prometheus 作为新一代云原生监控方案的核心组件与适用边界。读完本文,你将掌握一套可落地的 Kubernetes 监控体系搭建与数据获取方法。
Kubernetes 监控为什么比传统监控更难
Kubernetes 对应用做了大量抽象(Deployment、Service、Pod 等),在生产环境下,这些不同抽象组件的健康状态监控是迫在眉睫的事。与物理机和虚拟机的监控不同,Kubernetes 集群的监控多了一层虚拟化抽象:在 docker 容器之上,Kubernetes 又抽象出 Pod 和 Service 的概念,监控复杂度显著提升。
实践中需要关注三个方面:
- Kubernetes 集群本身的监控:主要是 apiserver、kubelet、controller-manager、scheduler 等集群组件的健康与性能;
- 集群中 Pod 的监控:Pod 的 CPU、内存、网络、磁盘等资源指标;
- 集群内部应用的监控:针对应用本身的运行状态、业务指标进行监控。
在设计 Kubernetes 监控方案时,还应重点思考以下问题:
- 应该给 Pod 打上哪些 label?这些 label 将直接成为监控的 metric 标签;
- 应用的 Pod 漂移(重建、调度到其他节点)之后怎么办?Pod 的生命周期远比虚拟机、物理机短,如何持续追踪应用状态;
- 监控项如何覆盖更多层次:Kubernetes 本身、容器、应用;
- 监控指标从哪里取:是通过 Heapster 收集汇聚,还是直接从每台主机的 docker 上取原始数据。
理解数据源头:cAdvisor 与容器命名规则
要设计好监控方案,首先需要弄清楚 cAdvisor 收集的数据格式与字段含义。通过访问${NODE_IP}:4194/api/v1.3/docker获取的 JSON 结果中,某个容器包含如下字段:
"labels": { "annotation.io.kubernetes.container.hash": "f47f0602", "annotation.io.kubernetes.container.ports": "[{\"containerPort\":80,\"protocol\":\"TCP\"}]", "annotation.io.kubernetes.container.restartCount": "0", "annotation.io.kubernetes.container.terminationMessagePath": "/dev/termination-log", "annotation.io.kubernetes.container.terminationMessagePolicy": "File", "annotation.io.kubernetes.pod.terminationGracePeriod": "30", "io.kubernetes.container.logpath": "/var/log/pods/d8a2e995-3617-11e7-a4b0-ecf4bbe5d414/php-redis_0.log", "io.kubernetes.container.name": "php-redis", "io.kubernetes.docker.type": "container", "io.kubernetes.pod.name": "frontend-2337258262-771lz", "io.kubernetes.pod.namespace": "default", "io.kubernetes.pod.uid": "d8a2e995-3617-11e7-a4b0-ecf4bbe5d414", "io.kubernetes.sandbox.id": "843a0f018c0cef2a5451434713ea3f409f0debc2101d2264227e814ca0745677" }这些信息是 Kubernetes 创建容器时给 docker container 打的Labels,使用docker inspect $container_name命令同样可以看到。问题在于:这些 label 与容器名字有什么关系?在 node 节点上执行docker ps看到的容器名,又对应哪个应用的 Pod?
在 Kubernetes 的 kubelet 代码pkg/kubelet/dockertools/docker.go中,BuildDockerName方法定义了容器的名称规范,核心代码如下:
// Creates a name which can be reversed to identify both full pod name and container name. // This function returns stable name, unique name and a unique id. // Although rand.Uint32() is not really unique, but it's enough for us because error will // only occur when instances of the same container in the same pod have the same UID. The // chance is really slim. func BuildDockerName(dockerName KubeletContainerName, container *v1.Container) (string, string, string) { containerName := dockerName.ContainerName + "." + strconv.FormatUint(kubecontainer.HashContainerLegacy(container), 16) stableName := fmt.Sprintf("%s_%s_%s_%s", containerNamePrefix, containerName, dockerName.PodFullName, dockerName.PodUID) UID := fmt.Sprintf("%08x", rand.Uint32()) return stableName, fmt.Sprintf("%s_%s", stableName, UID), UID } // Unpacks a container name, returning the pod full name and container name we would have used to // construct the docker name. If we are unable to parse the name, an error is returned. func ParseDockerName(name string) (dockerName *KubeletContainerName, hash uint64, err error) { // For some reason docker appears to be appending '/' to names. // If it's there, strip it. name = strings.TrimPrefix(name, "/") parts := strings.Split(name, "_") if len(parts) == 0 || parts[0] != containerNamePrefix { err = fmt.Errorf("failed to parse Docker container name %q into parts", name) return nil, 0, err } if len(parts) < 6 { // We have at least 5 fields. We may have more in the future. glog.Warningf("found a container with the %q prefix, but too few fields (%d): %q", containerNamePrefix, len(parts), name) err = fmt.Errorf("Docker container name %q has less parts than expected %v", name, parts) return nil, 0, err } nameParts := strings.Split(parts[1], ".") containerName := nameParts[0] if len(nameParts) > 1 { hash, err = strconv.ParseUint(nameParts[1], 16, 32) if err != nil { glog.Warningf("invalid container hash %q in container %q", nameParts[1], name) } } podFullName := parts[2] + "_" + parts[3] podUID := types.UID(parts[4]) return &KubeletContainerName{podFullName, podUID, containerName}, hash, nil }从中可以看出容器名称的组成:字段之间用下划线隔开,至少包含 6 个字段(未来可能更多),其中四个基本字段为:
containerNamePrefix_containerName_PodFullName_PodUID所有由 Kubernetes 启动的容器的containerNamePrefix都是k8s。containerName字段由"容器名 + 容器配置 hash"构成(如php-redis.f47f0602),PodFullName则由 Deployment/ReplicaSet 生成的 pod 名与命名空间拼合而成。
下面以官方示例 guestbook 为例。Deployment 名为frontend,其中启动了名为php-redis的容器,副本数为 3,其配置如下:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend spec: template: metadata: labels: app: guestbook tier: frontend spec: containers: - name: php-redis image: harbor-001.jimmysong.io/library/gb-frontend:v4 resources: requests: cpu: 100m memory: 100Mi env: - name: GET_HOSTS_FROM value: dns ports: - containerPort: 80选取三个实例中的一个运行 php-redis 的 docker 容器,在节点上docker ps会看到类似:
k8s_php-redis_frontend-2337258262-154p7_default_d8a2e2dd-3617-11e7-a4b0-ecf4bbe5d414_0逐字段解析:
- containerNamePrefix:
k8s - containerName:
php-redis - podFullName:
frontend-2337258262-154p7 - computeHash:
154p7 - deploymentName:
frontend - replicaSetName:
frontend-2337258262 - namespace:
default - podUID:
d8a2e2dd-3617-11e7-a4b0-ecf4bbe5d414
理解了命名规则,就可以在监控采集时把 node 上的 docker 容器准确反查到其所属的 Pod、ReplicaSet、Deployment 与 namespace,从而把容器级原始指标与业务应用对应起来。
使用 Heapster 进行集群监控
Heapster 是 Kubernetes 官方提供的监控方案(仓库中的安装说明见 heapster 插件安装)。安装 Kubernetes 集群时默认会安装该插件,可对集群上的应用做基础监控:获取Pod 级别的内存、CPU和网络监控信息,同时通过 API 暴露 Kubernetes 中的基本资源监控指标。完整部署清单位于仓库的 manifests/heapster 目录,包括以下文件:
heapster-deployment.yaml、heapster-service.yaml:Heapster 主进程及其 Service;influxdb-deployment.yaml、influxdb-service.yaml、influxdb-cm.yaml:时序数据库 InfluxDB 及配置;grafana-deployment.yaml、grafana-service.yaml:可视化面板 Grafana;heapster-rbac.yaml:Heapster 所需的 RBAC 权限。
从 heapster-deployment.yaml 可以看出 Heapster 的启动方式与数据链路:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: heapster namespace: kube-system spec: replicas: 1 template: metadata: labels: task: monitoring k8s-app: heapster spec: serviceAccountName: heapster containers: - name: heapster image: harbor-001.jimmysong.io/library/heapster-amd64:v1.4.3 imagePullPolicy: IfNotPresent command: - /heapster - --source=kubernetes:https://kubernetes.default - --sink=influxdb:http://monitoring-influxdb:8086关键参数只有两个:--source指定数据源(通过 kubelet 的 cAdvisor 采集节点与容器指标),--sink指定数据输出端(本例为 InfluxDB)。Heapster 收集 Node 节点上的 cAdvisor 数据,并可按照 Kubernetes 的资源类型聚合资源,例如 Pod、Namespace 域,分别获取其 CPU、内存、网络和磁盘的 metric,默认的 metric 数据聚合时间间隔是 1 分钟。
在 Grafana 中按 label 增加 service 层分类
默认安装的 Grafana 面板只根据 Namespace 和 Pod 两层来分类展示指标,实在有些单薄。可以在不改变原有架构的基础上,通过应用的自定义 label 来区分不同应用的 Pod,从而在监控面板中增加 service 这一层分类维度。
Heapster 的部署细节:镜像替换与 InfluxDB 配置
官方镜像保存在 gcr.io 中,需要提前拷贝到私有仓库。部署时主要修改点包括:
- grafana-deployment:将镜像替换为私有仓库地址,并把
GF_SERVER_ROOT_URL设置为/api/v1/proxy/namespaces/kube-system/services/monitoring-grafana/。如果后续使用 kube-apiserver 或kubectl proxy访问 Grafana dashboard,则必须这样设置,否则访问 Grafana 时提示找不到.../api/dashboards/home页面; - influxdb-deployment:InfluxDB 从 v1.1.0 开始默认关闭 admin UI。开启办法是:先导出镜像内的 influxdb 配置文件,将
[admin]段的enabled = false改为true,然后通过kubectl create configmap influxdb-config --from-file=config.toml -n kube-system创建 ConfigMap,最后在 Deployment 中挂载到/etc/覆盖原始配置(仓库中的 influxdb-cm.yaml 即为修改后的完整配置); - influxdb-service:将 Service 类型改为
NodePort,并额外增加 8083(admin)端口映射,便于后续浏览器访问 admin UI。
部署时执行kubectl create -f .(或对每个文件kubectl apply)后,可通过如下命令检查结果:
$ kubectl get deployments -n kube-system | grep -E 'heapster|monitoring' heapster 1 1 1 1 2m monitoring-grafana 1 1 1 1 2m monitoring-influxdb 1 1 1 1 2m访问 Grafana 有两种途径:通过kubectl cluster-info获取 monitoring-grafana 服务 URL 后经 kube-apiserver 代理访问(形如http://172.20.0.113:8080/api/v1/proxy/namespaces/kube-system/services/monitoring-grafana);或先运行kubectl proxy --address='172.20.0.113' --port=8086 --accept-hosts='^*$',再经代理端口访问。
注意:安装 Grafana 后默认模板中 namespace 选择里只有
default和kube-system,这并非其他 namespace 的指标没被监控,只是没有开启显示。将 Templating 中 namespace 的 Data source 设置为 influxdb-datasource、Refresh 设置为 on Dashboard Load 并保存,刷新浏览器即可看到其他 namespace 选项。
通过 Heapster API 获取集群对象的 metric
Heapster 提供 RESTful API,可用kubectl cluster-info获取其地址:
$ kubectl cluster-info Heapster is running at https://172.20.0.113:6443/api/v1/proxy/namespaces/kube-system/services/heapster ...以获取spark-clusternamespace 的 memory usage 为例,构造完整 URL:
https://172.20.0.113:6443/api/v1/proxy/namespaces/kube-system/services/heapster/api/v1/model/namespaces/spark-cluster/metrics/memory/usage?start=2017-10-16T09:14:00Z&end=2017-10-16T09:16:00ZURL 分为三部分:
- API 地址:
https://172.20.0.113:6443/api/v1/proxy/namespaces/kube-system/services/heapster/ - API 参数:
/api/v1/model/namespaces/spark-cluster/metrics/memory/usage,表示查询spark-clusternamespace 中的memory/usage指标; - 时间片:
?start=...&end=...,使用 RFC-3339 时间格式,Linux 下可用date --rfc-3339="seconds"生成,将空格替换为T、时区偏移替换为Z;也可以只指定 start,end 自动取当前时间。
返回结果示例:
{ "metrics": [ { "timestamp": "2017-10-16T09:14:00Z", "value": 322592768 }, { "timestamp": "2017-10-16T09:15:00Z", "value": 322592768 }, { "timestamp": "2017-10-16T09:16:00Z", "value": 322592768 } ], "latestTimestamp": "2017-10-16T09:16:00Z" }注意:Heapster 中查询的所有值都以最小单位表示,例如 CPU 为 1 milicore,内存为 B(字节)。Heapster 同时被 Horizontal Pod Autoscaling 用作Resource Metrics API,在kube-controller-manager中配置指向 kube-aggregator 的--api-server,或在启动 heapster 时指定--api-server=true。
版本提示:Kubernetes 1.11 起不建议使用 Heapster。SIG Instrumentation 正持续转向新的 Kubernetes 监控模型,仍使用 Heapster 做自动扩展的集群应迁移到 metrics-server 与自定义指标 API。
Prometheus:面向云原生的新一代监控方案
Heapster 解决了"能监控"的问题,但 Prometheus 的出现提供了更强大的指标模型与查询能力。Prometheus 由 SoundCloud 开源,2012 年开始编写代码,2015 年在 GitHub 上开源,2016 年成为继 Kubernetes 之后第二个加入 CNCF 的项目成员,也是第二个正式毕业的项目。作为新一代开源解决方案,其很多设计理念与 Google SRE 运维之道不谋而合。
云原生时代,监控对象随微服务和容器化呈指数级增加,监控对象的生命周期也更短暂,因此需要一款统一监控指标与数据查询语言的工具。Prometheus 主要功能包括:
- 多维数据模型:时序由 metric 名字和 k/v 的 labels 构成;
- 灵活的查询语句 PromQL;
- 无依赖存储,支持 local 和 remote 不同模型;
- 采用 http 协议、pull 模式拉取数据,简单易懂;
- 监控目标支持服务发现或静态配置;
- 支持多种统计数据模型,图形化友好。
其核心组件包括:
- Prometheus Server:抓取数据、存储时序数据,并提供查询和 Alert Rule 配置管理;
- client libraries:用于对接 Prometheus Server,查询和上报数据;
- push gateway:批量、短期监控数据的汇总节点,主要用于业务数据汇报;
- exporters:各类指标导出器,如机器指标 node_exporter、MongoDB exporter 等;
- alertmanager:告警通知管理,负责聚合、去重、降噪后发送告警。
其工作逻辑是:Prometheus server 定期从静态配置或服务发现的目标拉取数据;当新拉取数据大于配置内存缓存区时将数据持久化到磁盘(remote storage 则持久化到云端);配置 rule 后定时查询数据,条件触发时将 alert 推送到 Alertmanager;最终可通过 API、Prometheus Console 或 Grafana 查询和聚合数据。
适用边界:Prometheus 的数据是基于时序的 float64 值,若你的数据还有其他类型则无法满足;它也不适合做审计计费——审计计费需要记录每个请求并长期存储数据,而 Prometheus 关注的是系统运行瞬时状态与趋势,能容忍少量数据丢失。这类场景需要专门的审计系统。
应用监控:基于 Kubernetes API 的指标采集架构
对于集群内应用的监控,可以采用如下架构:通过访问 Kubernetes API 获取应用 Pod 的 IP 和端口,将 Pod labels 作为监控 metric 的 tag,直接访问应用的 Pod IP 和端口获取应用监控数据,最后将 metrics 发送到存储与展示系统。这种方式有以下几个要点:
- 访问 Kubernetes API 获取应用 Pod 的 IP 和端口;
- Pod labels 作为监控 metric 的 tag;
- 直接访问应用的 Pod 的 IP 和端口获取应用监控数据;
- metrics 发送到存储与展示平台统一管理。
当应用 Pod 发生漂移时,由于始终通过 Kubernetes API 动态获取最新 Pod 地址,监控采集可跟随应用实例的生命周期持续工作,这正是容器化应用监控与传统监控的关键差异。
应用拓扑状态图:用 Weave Scope 一览集群全景
对于复杂的应用编排和依赖关系,我们希望能有清晰的图来一览应用状态和拓扑关系。可以使用 Weaveworks 开源的 scope。仓库提供了完整的部署清单 manifests/weave/scope.yaml,其中定义了:
- weave-scope-app Deployment(
weaveworks/scope:1.5.1,--no-probe)与对应的 Service(端口 80 → 容器 4040); - weave-scope-agent DaemonSet:以
hostNetwork: true、hostPID: true方式在每个节点运行,挂载 docker socket(--probe.docker=true)并启用 Kubernetes 探针(--probe.kubernetes=true); - 配套的 ServiceAccount、ClusterRole 与 ClusterRoleBinding(RBAC,安装于
kube-systemnamespace)。
安装方式为:
$ kubectl apply -f scope.yaml由于服务安装在kube-systemnamespace 下,可创建一个新的 Ingress(如kube-system.yaml)暴露访问入口:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: traefik-ingress namespace: kube-system spec: rules: - host: scope.weave.io http: paths: - path: / backend: serviceName: weave-scope-app servicePort: 80执行kubectl apply -f kube-system.yaml后,在主机/etc/hosts中添加一条记录:
172.20.0.119 scope.weave.io浏览器访问scope.weave.io即可打开应用拓扑界面。
如上图所示,scope 可以监控 Kubernetes 集群中一系列资源的状态、资源使用情况、应用拓扑、扩缩容,还可以直接通过浏览器进入容器内部进行调试等。
小结
一套完整的 Kubernetes 监控体系通常由三层组成:集群组件监控(apiserver、kubelet 等)、Pod 资源监控(CPU、内存、网络、磁盘)和应用业务监控。数据层面需要理解 cAdvisor 的原始数据模型与容器命名规则,才能把容器指标准确反查到 Pod/Deployment 维度;采集与存储层面,Heapster + InfluxDB + Grafana 是入门最轻的官方组合,而 Prometheus 凭借多维数据模型、PromQL 与服务发现能力,成为云原生监控的主流选择;可视化和拓扑层面,Weave Scope 提供了直观的集群与依赖关系视图。
仓库中 practice/monitor.md、practice/monitoring.md、practice/using-heapster-to-get-object-metrics.md 与 manifests/heapster 目录提供了完整的部署清单与 API 使用细节,practice/prometheus.md 给出了 Prometheus 的组件与架构总览,可作为继续深入实践的入口。
【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考