k8s 监控(四)监控宿主机
原文链接:https://juejin.cn/post/6844904057098731534
k8s 监控的第四篇文章,这篇文章讲的是监控宿主机的指标。官方和大部分使用者都会使用 node_exporter 完成此项工作,但是我更喜欢 telegraf。原因在于 node_exporter 有以下几大痛点:
- 指标太多,仅 cpu 而言,每个 cpu 核心都有 6 个指标,如果 72 核心,那么光 cpu 的指标就有 432 个,难以理解;
- 无法自定义要收集的指标,你要么收集这类指标,要么就不收集,而不能只收集这类指标的某些部分;
- 不支持自定义监控脚本;
- 没有 tcp 的 11 种状态的指标(或许我不知道怎么看?),也不知道搞那么多网络指标干啥,一个都看不懂。
而 telegraf 就没有这方面的困扰。有鉴于此,本篇文章会将两者都部署一遍,怎么选择就看你了。
老规矩,所有 yml 文件都已上传到 github。
node_exporter
只需要注意以下几点就行:
- 使用 daemonset,确保每个 k8s 节点都部署;
- 要将宿主机的 /proc 和 /sys 都挂载,貌似还要挂载根;
- 使用宿主机网络名称空间。
部署文件只有 5 个,都以 node-exporter-
开头,具体作用一看便知,就不多说了。先 kubectl apply
,等待 pod 运行 ok 之后,可以直接访问宿主机的 9100 端口,查看都有哪些指标:
curl 127.0.0.1:9100/metrics
确保指标收集到位之后,修改 prometheus-config.yml,添加如下配置:
- job_name: node_exporter
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- monitoring
scrape_interval: 30s
scrape_timeout: 30s
tls_config:
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: keep
source_labels:
- __meta_kubernetes_service_label_k8s_app
regex: node-exporter
这里注意将 service 的标签名 k8s-app
中的 -
换为这里的 _
,否则 reload prometheus 会报错。
修改完毕后执行 kubectl apply -f prometheus-config.yml
,此时你最好登陆 prometheus 容器中查看配置文件是否生效,确保生效后,可以在宿主机上 reload:
curl -XPOST POD_IP:9090/-/reload
然后在 prometheus web 页面的 target 中就可以看到了。
telegraf
node_exporter 中太多不明所以的指标,会占用许多额外的资源,所以我选择定制性更高的 telegraf。telegraf 是 InfluxData 使用 go 开发的一个指标收集工具,InfluxData 的另一款产品 influxdb 非常有名,这两者和剩下的 Chronograf、Kapacitor 共同构成 InfluxData 的监控系统 tick。
tick 这里就不多提了,我们只会用到 telegraf。telegraf 有些类似于 logstash,分为 Input、Processor、Aggregator、Output 四个部分,而每个部分又由各个插件提供具体的功能。可以理解为,telegraf 的所有功能都是由插件提供,只不过插件分为四类。
本文会用到 Input、Output 和 Processor,至于 Aggregator(聚合,用来计算一段时间内的最大、最小、平均值等)有兴趣童鞋的可以研究研究。
这里我们使用 telegraf 收集宿主机的性能指标,由于指标种类很多,包括 cpu、内存、磁盘、网络等,所以会使用多个 input 插件。有些插件会提供一些选项,让我们能够更好的控制需要收集的指标,这是非常方便的,比 node_exporter 一股脑收集有用多了。
获得这些指标后,因为需要通过 prometheus 收集,所以会用到 prometheus Output,也就是将所有收集到的指标通过 metirc 页面展示出来。
首先来说说它的配置文件,它的所有配置都在这个配置文件中了。在了解配置文件之前,我们得知道 telegraf 自身也有一些概念:
- field:指标的名称;
- tag:指标中的标签。
为避免重复展示,我就直接将 configmap 的内容贴出来了,我们只需要从 [agent]
开始看起就行。
apiVersion: v1
kind: ConfigMap
metadata:
name: telegraf
namespace: monitoring
labels:
name: telegraf
data:
telegraf.conf: |+
[agent]
interval = "10s"
round_interval = true
collection_jitter = "1s"
omit_hostname = true
[[outputs.prometheus_client]]
listen = ":9273"
collectors_exclude = ["gocollector", "process"]
metric_version = 2
[[inputs.cpu]]
percpu = false
totalcpu = true
collect_cpu_time = false
report_active = false
[[inputs.disk]]
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
[inputs.disk.tagdrop]
path = ["/etc/telegraf", "/dev/termination-log", "/etc/hostname", "/etc/hosts", "/etc/resolv.conf"]
[[inputs.diskio]]
[[inputs.kernel]]
[[inputs.mem]]
fielddrop = ["slab", "wired", "commit_limit", "committed_as", "dirty", "high_free", "high_total", "huge_page_size", "huge_pages_free", "low_free", "low_total", "mapped", "page_tables", "sreclaimable", "sunreclaim", "swap_cached", "swap_free", "vmalloc_chunk", "vmalloc_total", "vmalloc_used", "write_back", "write_back_tmp"]
[[inputs.processes]]
[[inputs.system]]
[[inputs.netstat]]
[[inputs.net]]
ignore_protocol_stats = true
interfaces = ["eth*", "bond*", "em*"]
fielddrop = ["packets_sent", "packets_recv"]
配置文件
telegraf 配置文件的官方文档在此,内容并不多,你可以看看。你不想看也没关系,我会将我这里的配置都一一说明。telegraf 采用的是 toml 的配置文件格式,[]
表示字典,[[]]
表示列表。转换成 yml 就长这样:
agent:
# 采集间隔
interval: 30s
# 没有这个貌似就只会采集一次
round_interval: true
# 多个 input 如果在同一时间进行采集,可能会造成 cpu 尖刺,使用这个时间错开
collection_jitter: 1s
# 不会为所有的指标添加 hostname tag(标签)
omit_hostname: true
inputs:
- disk:
# 不收集指定的文件系统
ignore_fs: []
# 只要标签中有 path 为以下值的,不收集对应的指标
tagdrop:
path: ["/etc/telegraf", "/dev/termination-log", "/etc/hostname", "/etc/hosts", "/etc/resolv.conf"]
- system: {}
- cpu:
# 不为每颗 cpu 都单独创建指标,node_exporter 就使用这种方式,你还无法关掉,但是 telegraf 可以
percpu: false
# 这是绝对要开启的,统计总的 cpu 使用
totalcpu: true
# 统计 cpu 时间,看你需要,一般不开启
collect_cpu_time: false
# 是否新增一个 active 的指标,它的值是除了 idle 之外的值相加的结果,如果不统计 cpu 时间的话,可以直接用 100 减去
# idle,得到的值就是 active 的值
report_active: false
- mem:
# 字段名中包含这些的都不收集,至于字段有哪些,那就要看 mem inputs 的文档了
# 由于老夫学艺不精,很多内存指标都看不懂,干脆都干掉了,你们自行掂量
fielddrop: []
outputs:
- prometheus_client:
listen: :9273
# 排除 go 本身(goroutine、gc 等)和 process 这两种指标
collectors_exclude: ["gocollector", "process"]
telegraf 的四大部分中,只有 Processor 没有对应的关键字,目前它只有过滤的作用,用于 Input、Output 和 Aggregator 中。上面配置文件 Input 中的 fielddrop、tagdrop 都属于 Processor,用于过滤指标。过滤的关键字有:
namepass
:以指标名称作为过滤条件,pass 是白名单,名称中包含哪些关键字的才收集,它的值是一个列表,列表中的元素可以使用通配符;namedrop
:黑名单。需要注意的是,name 和 field 并不相同,比如内存指标中有 total 这个 field,但是它的 name 为 mem_total;fieldpass
:根据字段名进行过滤,它的值类型同样为列表;fielddrop
:黑名单;tagpass
:如果 tag 中包含某个 key/value,那么就不收集该指标。注意它的值类型为字典,详见上面使用;tagdrop
:黑名单;taginclude
:这是删除 tag 的,值类型为列表。列表中的 tag 都保留;tagexclude
:列表中的 tag 都删除。
我只使用了 tagdrop
和 fielddrop
,其他有需要的你们可以使用。通过 Processor 可以很轻松的删除我们不需要的指标,这是非常方便的。
结合这些,你应该很容易就很看懂我这里使用的配置。这里我只收集了一些常见的系统指标,如果你有其他的需要,可以查看官方 input 文档,各种插件任你挑选。
pod
telegraf 很显然也是使用 daemonset,它的 pod 配置有些关键点需要提一下。
- 需要将根挂载到容器中,单独挂载 /proc 和 /sys,disk 指标会有问题;
- 通过 HOST_PROC、HOST_SYS 和 HOST_MOUNT_PREFIX 环境变量让 telegraf 收集挂载进来的宿主机的目录;
- hostNetwork、hostPID 都得为 true;
- 使用 securityContext 让 pod 使用非 root 用户运行,指定的 uid 是宿主机的上用户的 uid,镜像中有没有这个用户都有不影响。pod 运行后你可以在 pod 所在的宿主机上通过
ps -ef|grep telegraf
查看运行的用户。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: telegraf
namespace: monitoring
labels:
k8s-app: telegraf
spec:
selector:
matchLabels:
name: telegraf
template:
metadata:
labels:
name: telegraf
spec:
containers:
- name: telegraf
image: telegraf:1.13.2-alpine
resources:
limits:
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
env:
- name: "HOST_PROC"
value: "/host/proc"
- name: "HOST_SYS"
value: "/host/sys"
- name: "HOST_MOUNT_PREFIX"
value: "/host"
volumeMounts:
- name: config
mountPath: /etc/telegraf
readOnly: true
- mountPath: /host
name: root
readOnly: true
hostNetwork: true
hostPID: true
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
runAsUser: 65534
tolerations:
- operator: Exists
terminationGracePeriodSeconds: 30
volumes:
- name: config
configMap:
name: telegraf
- hostPath:
path: /
name: root
对于 service 我就不多提了,service 用来让 prometheus 对其进行发现。将这三个文件都 apply 之后,修改 prometheus 配置。
修改 prometheus 配置
根据用法的不同,prometheus 配置可能会有不同,先上配置:
- job_name: telegraf
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- monitoring
scrape_interval: 30s
scrape_timeout: 30s
tls_config:
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: keep
source_labels:
- __meta_kubernetes_service_label_k8s_app
regex: telegraf
- source_labels:
- __meta_kubernetes_endpoint_node_name
target_label: instance
这里只增加了一个配置,就是将 instance 标签换成了 node name,而非默认的 __address__
。如果要保留默认的 instance,你可以将 instance 换成你想要的名称。我是嫌指标太多,所以才将默认的 instance 换成了 node name。
之所以要用 node name,是因为配合使用 kubectl top node
命令(这涉及到本系列的上一篇文章)。因此,instance 标签的值要和你使用 kubectl get node
出现的值是一一对应的(基本上都是一致的)。当然,你如果可以直接使用 kubectl top node 命令,那么就没必要增加这个标签了。
修改之后 apply,然后同样是 exec 进入 prometheus 容器中,查看 /etc/prometheus/config/prometheus.yml
是否已经更改。等待更改之后,回到宿主机上执行;
curl -XPOST PROMETHEUS_CONTAINER_IP:9090/-/reload
reload 之后你就可以直接通过宿主机 ip 来访问指标页面了。
curl IP:9273/metrics
可以看到指标清晰易懂,且数量很少,比 node_exporter 强出一大截。
修改 prometheus adapter 配置
在上一篇文章中,我们部署了 prometheus adapter,并使用它提供 resource metric api,也就是可以通过它使用 kubectl top 命令。但是由于我删除了存在 id="/"
标签的指标,所以默认的 node 指标的查询语句就失效了。
想要使用的话,可以恢复之前删除的指标,默认查询语句是这样的:
# cpu
sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[1m])) by (<<.GroupBy>>)
# memory
sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)
但是如果将其恢复都恢复,指标数量会增加很多,有些得不偿失。既然我们收集了宿主机的指标了,完全可以让其查询宿主机的指标,根本没有必要查询容器的。因此我们只需要将这两个查询语句换成下面这两个:
# cpu
100-cpu_usage_idle{cpu="cpu-total", <<.LabelMatchers>>}
# mem
mem_used{<<.LabelMatchers>>}
但是你得确保下面配置必须存在:
resources:
overrides:
instance:
resource: nodes
这个配置的作用是将 node 的资源映射为 instance 标签的值。当你执行 kubectl top node 时,它会先获得所有的 node,然后将每个 node 带入到查询表达式中,比如查询 node 名称为 k8s-node1 的 cpu:
100-cpu_usage_idle{cpu="cpu-total", instance="k8s-node1"}
完整的配置可以在 github 上看到,其实就是修改了两个查询语句而已。
apply 之后,需要删除 prometheus adapter pod 让其重启,之后就可以执行 kubectl top node 命令了,只不过 cpu 的显示并不准确,可能是缺少了 cpu_usage_total?不是很懂 adapter 的实现逻辑,有兴趣的童鞋可以研究研究?不过内存是准的,大家看看内存就好。
链接:https://juejin.cn/post/6844904057098731534
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。