使用Prometheus监控Kubernetes

文末福利,中秋快乐!

导语:在本文中,我们将研究堆栈中的Kubernetes部分以及如何对它进行监控。

为了简化监控示例,我们将Prometheus也部署到了Kubernetes集群中。

一 、监控Kubernetes

让我们首先谈谈监控Kubernetes本身。尽管它可能会经常更新迭代,但它作为一个主题,很多知识和内容是通用的。Kubernetes是一个容器编排和调度程序,有很多灵活的组件。我们将展示如何使用Prometheus作业监控Kubernetes的各个方面,并且将这些作业与一些记录规则和警报规则匹配。

本文将讲解如何处理每个组件,如何收集时间序列,以及从这些时间序列生成的规则和警报。我们不打算提供明确的监控方法,而是触及一些关键的要点,特别是在延伸Prometheus概念中值得探索的地方。

为了确定需要监控的内容,我们还将利用Prometheus为Kubernetes提供的内置服务发现机制。

让我们从监控运行Kubernetes的节点开始。

二 、监控Kubernetes节点

我们的Kubernetes集群由9个AWS EC2实例组成。为了监控它们,我们将使用Node Exporter,可以通过多种方式将Node Exporter部署到这些实例上。可以在配置时将Node Exporter安装到实例上,或者可以将Node Exporter安装到每个节点上的Kubernetes pod中。我们可以利用Kubernetes DaemonSet控制器在集群中的每个节点上自动部署pod。当你无法控制实例时,这个方法很有用,例如,如果你使用托管的Kubernetes解决方案。

警告:使用这种方法需要特别注意!Node Exporter访问许多root级别的资源,在Docker容器中运行它需要将这些资源挂载到容器中,对于systemd收集器来说,需要以root身份运行容器。这带来了潜在的安全风险,如果你无法接受该风险,则应将Node Exporter直接安装到实例上。

1 、Node Exporter DaemonSet

DaemonSet使用容忍(toleration)确保pod在所有节点上运行,可能也包含主节点。它非常适合监控或日志代理等项目。让我们看一下DaemonSet的元素。

注:可以在GitHub上找到Node Exporter的完整配置。

代码清单12.2 Node Exporter DaemonSet toleration


 

apiVersion: extensions/v1beta1

kind: DaemonSet

metadata:

name: node-exporter

namespace: monitoring

. . .

spec:

tolerations:

- key: node-role.kubernetes.io/master

effect: NoSchedule

hostNetwork: true

hostPID: true

hostIPC: true

securityContext:

runAsUser: 0

首先,可以看到我们给DaemonSet指定了一个名称node-exporter,并且使用toleration来确保pod也会被调度到Kubernetes主节点,而不仅仅是工作节点。

这里就可以看到刚刚警告中提到的情况。我们以用户0或root运行pod(这允许访问systemd),并且还启用了hostNetwork、hostPID和hostIPC,以指定实例的网络、进程和IPC命名空间在容器中可用。这些都是潜在的安全风险,你必须考虑是否可以承担此风险。如果这种风险是不可接受的,那么将Node Exporter放到实例的镜像中可能是一种更好的方法。

让我们来看看pod中的容器。

代码清单12.3 Node Exporter DaemonSet容器


 

containers:

- image: prom/node-exporter:latest

name: node-exporter

volumeMounts:

- mountPath: /run/systemd/private

name: systemd-socket

readOnly: true

args:

- "--collector.systemd"

- "--collector.systemd.unit-whitelist=(docker|ssh|

rsyslog|kubelet).service"

ports:

- containerPort: 9100

hostPort: 9100

name: scrape

这里,我们使用DockerHub中的Node Exporter镜像prom/node_exporter,并获取最新版本。我们还为与主机上相同目录的/run/systemd/private挂载了一个卷,这允许Node Exporter访问systemd并在实例上收集systemd管理服务的服务状态。

我们还为node_exporter二进制文件指定了一些参数,这些参数在第4章中都有介绍:启用systemd收集器,并指定要监控的特定服务的正则表达式,而不是主机上的所有服务。

我们还指定了希望暴露指标的端口9100,它也是默认端口。

为了帮助Node Exporter pod保持健康并提高它们的正常运行时间,我们还在Node Exporter容器中添加了liveness和readiness探针,其中liveness探针检测容器内应用程序的状态。

代码清单12.4 Node Exporter的liveness和readiness探针


 

livenessProbe:

httpGet:

path: /metrics

port: 9100

initialDelaySeconds: 30

timeoutSeconds: 10

periodSeconds: 1

readinessProbe:

failureThreshold: 5

httpGet:

path: /metrics

port: 9100

initialDelaySeconds: 10

timeoutSeconds: 10

periodSeconds: 2

在示例中,我们对端口9100上的/metrics路径使用HTTP GET探测,以确认Node Exporter是否正常工作。探针每隔periodSeconds时间运行一次,在示例中是1秒。如果liveness检查失败,Kubernetes将重新启动容器。

注:我们也会在监控的应用程序中看到这些探针。它们通过减少可能的监控误报来帮助管理应用程序的运行状况,例如服务在启动时没有达到就绪要求而触发警报。这些检查还可以重新启动有问题的容器,可能会帮助在触发警报之前修复问题。

Readiness探针确认应用程序正常运行。这意味着,在将容器标记为可用并发送流量之前,HTTP GET可以连接到端口9100上的/metrics路径。其余设置控制探针的行为,在检查准备就绪之前,它将等待10秒(initialDelaySecond),然后,它会每隔2秒(periodSeconds)检查一次。如果探针在10秒(timeoutSeconds)后超时超过5次(failureThreshold),则容器将被标记为Unready。

注:你可以在GitHub上找到Node Exporter的完整配置。

2  、Node Exporter服务

我们还需要创建一个服务来暴露Node Exporter,以便进行指标抓取。

代码清单12.5 Node Exporter服务


 

apiVersion: v1

kind: Service

metadata:

annotations:

prometheus.io/scrape: 'true'

labels:

app: node-exporter

name: node-exporter

name: node-exporter

namespace: monitoring

spec:

clusterIP: None

ports:

- name: scrape

port: 9100

protocol: TCP

selector:

app: node-exporter

type: ClusterIP

服务相对来说比较简单。我们添加了一个注解prometheus.io/scrape: 'true',作为服务的元数据,它将告诉Prometheus应该抓取这个服务。后面我们将看到它是如何在Prometheus作业中用来抓取Node Exporter的。

我们还将端口9100作为ClusterIP暴露,这意味着它仅用于内部集群网络。由于Prometheus位于本地Kubernetes集群上,它将能够在内部抓取Node Exporter,因此无需对外暴露。

注:你可以在GitHub上找到完整的Node Exporter服务配置。

3  、部署Node Exporter

让我们使用kubectl命令在Kubernetes集群上创建DaemonSet和服务。我们将在monitoring命名空间内创建它们。

代码清单12.6 部署Node Exporter DaemonSet和服务


 

$ kubectl create -f ./node-exporter.yml -n monitoring

daemonset "node-exporter" created

service "node-exporter" created

如果你不想继续指定-n monitoring命名空间,则可以将其指定为默认值。

代码清单12.7 默认命名空间


 

$ kubectl config set-context $(kubectl config current-context) --

namespace=monitoring

现在查看我们的pod是否正在运行。

代码清单12.8 检查Node Exporter窗格


 

$ kubectl get pods -n monitoring

NAME READY STATUS RESTARTS AGE

alertmanager-6854b5d59b-jvjcw 1/1 Running 0 7d

node-exporter-4fx57 1/1 Running 0 5s

node-exporter-4nzfk 1/1 Running 0 5s

node-exporter-5n7kl 1/1 Running 0 5s

node-exporter-f2mvb 1/1 Running 0 5s

node-exporter-km7sc 1/1 Running 0 5s

node-exporter-lvrsq 1/1 Running 0 5s

node-exporter-mvstg 1/1 Running 0 5s

node-exporter-tj4cs 1/1 Running 0 5s

node-exporter-wh56c 1/1 Running 0 5s

prometheus-core-785bc8584b-7vfr4 1/1 Running 0 8d

可以看到总共有9个pod,集群中每个实例一个:3个主节点和6个工作节点。我们还可以看到Prometheus服务和Alertmanager的pod:prometheus-core和alertmanager。

我们可以通过捕捉日志来检查Node Exporter pod是否正常运行。

代码清单12.9 Node Exporter pod日志


 

$ kubectl logs node-exporter-4fx57 -n monitoring

time="2018-01-18T22:46:05Z" level=info msg="Starting

node_exporter (version=0.15.2, branch=HEAD, revision=98

bc64930d34878b84a0f87dfe6e1a6da61e532d)" source="node_exporter.

go:43"

time="2018-01-18T22:46:05Z" level=info msg="Build context (go=

go1.9.2, user=root@d5c4792c921f, date=20171205-14:50:53)" source

="node_exporter.go:44"

. . .

可以看到我们的Node Exporter守护程序正在运行,也可以确认服务已经就绪。

代码清单12.10 检查Node Exporter服务


 

$ kubectl get services -n monitoring

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

node-exporter ClusterIP None <none> 9100/TCP 8s

这里,可以看到Node Exporter服务是ClusterIP类型的,并且暴露9100端口给Kubernetes集群内部,随时可以被抓取。然而,我们还没有开始抓取,因为还没有添加Prometheus的作业。

4  、Node Exporter作业

在Prometheus配置中,我们现在想要添加一个作业来抓取Node Exporter端点。通过定义一项抓取Kubernetes暴露的所有服务端点的作业,这将会一举多得。我们还会控制Prometheus仅抓取具有特定注解prometheus.io/scrape设置为true的端点。然后,我们使用内置的Kubernetes服务发现来查找端点,并将它们作为Prometheus的潜在目标返回。

注:所有这些工作都是基于Prometheus自带的Kubernetes作业案例。感谢该项目的贡献者开发它们。

现在让我们来看看这个作业内容。

代码清单12.11 Kubernetes服务端点作业


 

- 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

我们称这个工作为kubernetes-service-endpoints,指定服务发现使用kubernetes_sd_discovery机制,这是内置的服务发现机制,专门用于监控Kubernetes。它向Kubernetes API查询符合特定搜索条件的目标。

由于Prometheus服务器在Kubernetes内部运行,我们能够以最少的配置自动获取与特定角色匹配的Kubernetes目标。节点、pod、服务和入口都有不同的角色,由role参数指定,我们要求服务发现返回所有Kubernetes端点。Endpoint role角色返回服务的所有列出的端点的目标,每个端点地址的每个端口都是一个目标。如果端点也是由pod提供,就像我Node Exporter服务那样,那么任何其他容器端口也会被发现作为目标。在示例中,我们只暴露了9100端口。

服务发现还会填充各种元数据,可以使用元数据重新标记并标识每个端点。首先我们看看重新标记规则的作用并进一步探索元数据。

第一条规则检查我们在Node Exporter服务中设置的注解prometheus.io/scrape: 'true'。在服务发现过程中,prometheus.io/scrape注解将被转换为prometheus_io_scrape,以创建一个有效的标签名称,这是因为点和斜杠在Prometheus指标标签中不是合法字符。由于这是Kubernetes服务的注解,因此Prometheus服务进程还会在标签中添加__meta_kubernetes_service_annotation_前缀。

我们的作业只保留具有元数据标签的目标,即__meta_kubernetes_service_annotation_设置为true。所有其他目标都会被丢弃,这使得你只抓取所需的端点。

接下来的三个规则检查是否存在其他注解:prometheus.io/scheme、prometheus.io/path和prometheus.io/port。如果这些标签存在,它将使用这些注解的内容作为要抓取的scheme、path和port。这使我们能够从服务端点精确控制要抓取的内容,从而作业变得更加灵活。

我们的下一个规则使用labelmap操作将服务上的标签映射到同名的Prometheus标签。在示例中,这会将__meta_kubernetes_service_label_app元数据标签映射为一个简单的app标签。下一个规则将__meta_kubernetes_namespace标签复制到kubernetes_namespace,将_meta_kubernetes_service_name元数据标签复制到kubernetes_name。

我们现在将作业添加到用于Prometheus服务器配置的ConfigMap中,然后替换现有的配置。

代码清单12.12 替换ConfigMap

$ kubectl replace -f ./prom-config-map-v1.yml -n monitoring

通常我们必须删除Prometheus pod,以便重新创建并加载新配置。稍后我们将在Prometheus表达式浏览器上看到一些新的目标。

 图1  Kubernetes端点目标

可以看到我们列出了13个目标,其中9个是实例上的Node Exporter端点,第10和第11个是Prometheus和Alertmanager。Prometheus和Alertmanager目标被自动发现,是因为它们的接口也作为服务暴露出来。

代码清单12.13 监控服务


 

$ kubectl get services -n monitoring

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

alertmanager LoadBalancer 100.68.82.44 a6f953a641191...

9093:32288/TCP 27m

node-exporter ClusterIP None <none> 9100/TCP 15h

prometheus LoadBalancer 100.68.154.121 a953a66970c13...

9090:30604/TCP 4d

这个作业非常有价值,因为我们只需要定义一次,未来所有Kubernetes服务端点都将被自动发现和监控。

我们将在本章后面章节和下一章中看到这些价值。在作业加载后,我们还会看到node_时间序列开始出现在表达式浏览器中。

5  、Node Exporter规则

我们不会为Kubernetes节点添加任何新的记录或警报规则。相反,我们将在第4章中创建的规则添加到ConfigMap,用来填充Prometheus规则文件。所以我们添加了之前创建的所有CPU、内存和磁盘规则,并且还为Kubernetes服务添加了一些可用性警报规则。让我们来看看这些规则。

代码清单12.14 Kubernetes可用性警报规则


 

- alert: KubernetesServiceDown

expr: up{job="kubernetes-service-endpoints"} == 0

for: 10m

labels:

severity: critical

annotations:

summary: Pod {{ $labels.instance }} is down!

- alert: KubernetesServicesGone

expr: absent(up{job="kubernetes-service-endpoints"})

for: 10m

labels:

severity: critical

annotations:

summary: No Kubernetes services are reporting!

description: Werner Heisenberg says - OMG Where are my

servicez?

当kubernetes-service-endpoints作业的up指标值为0时,将触发第一个警报,它表示Prometheus未能抓取服务。第二个警报检查服务是否消失,并使用absent函数检查up指标是否存在。

我们还使用node_systemd_unit_state指标为各个节点上监控的服务添加了警报规则,该指标跟踪systemd服务的状态。

代码清单12.15 Kubernetes可用性警报规则


 

- alert: CriticalServiceDown

expr: node_systemd_unit_state{state="active"} != 1

for: 2m

labels:

severity: critical

annotations:

summary = {{ $labels.instance }}: Service {{ $labels.name }}

failed to start.

description = {{ $labels.instance }} failed to (re)start

service {{ $labels.name }}.

当它检测到Node Exporter正在监控的任何服务(Docker、Kubelet、RSyslog和SSH)处于故障状态时,它将发出警报。

配置中还有其他规则和警报,你可以进一步探索,以了解更多关于节点监控的信息。

12.6 、小结

在本文中,我们开始研究如何监控应用程序堆栈,首先从计算平台Kubernetes开始。我们将Prometheus部署到Kubernetes集群中,以便更轻松地进行监控。我们研究了如何在Kubernetes中部署Node Exporter以及如何使用Node Exporter监控Kubernetes节点。

我们创建了几个Prometheus作业,包括几个使用Kubernetes服务发现来自动发现构成我们环境的节点、API服务器和服务的作业。通过使用使用注解选择正确的地址、端口和路径,服务发现还允许我们配置作业,自动开始抓取特定的Kubernetes服务或应用程序服务。

以上内容摘自《Prometheus监控实战》一书,经出版方授权发布

推荐语:

Docker公司前服务与支持副总裁、Kickstarter前首席技术官、Empatico首席技术官撰写,全方位介绍继Kubernetes之后的第二个CNCF毕业项目--Prometheus。

【中秋节福利】

本次联合【机械工业出版社华章公司】为大家送上10本正版《Prometheus监控实战》图书。

留言谈谈你对监控的理解或需要这本书的理由,点赞前10名的读者可获赠正版图书1本!

时间截止:9月15日12:00;

祝大家中秋节快乐,阖家团圆!

END

企业级K8S线上直播培训推荐

本次课程围绕:Docker容器、Docker镜像、Docker网络、数据持久化、Docker最佳实践、Kubernetes集群安装、服务部署、Pod、集群资源管理、控制器、网络、调度、服务发现、存储、Helm、监控、DevOps等。 课程全部采用直播方式,实时互动,专属交流群课后答疑,专属课件文档,每章节课后作业跟踪,课后视频无限回看。 点击了解更多详情

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章