使用 OpenTelemetry Collector 采集 Kubernetes 指标数据
Kubernetes 已成为一个被广泛采用的行业工具,对可观测性工具的需求也在不断增加。为此,OpenTelemetry 创建了许多不同的工具,来帮助 Kubernetes 用户观察他们的集群和服务。
接下来我们将开始使用 OpenTelemetry 监控 Kubernetes 集群,将专注于收集 Kubernetes 集群、节点、pod 和容器的指标和日志,并使集群能够支持发出 OTLP 数据的服务。
Kubernetes 以多种不同的方式暴露了许多重要的遥测数据。它具有用于许多不同对象的日志、事件和指标,以及其工作负载生成的数据。 为了收集这些数据,我们将使用 OpenTelemetry Collector。该收集器可以高效地收集所有这些数据。
为了收集所有的数据,我们将需要安装两个收集器,一个作为 Daemonset,一个作为 Deployment。收集器的 DaemonSet 将用于收集服务、日志和节点、Pod 和容器的指标,而 Deployment 将用于收集集群的指标和事件。
为了安装收集器,我们这里将使用 OpenTelemetry Collector Helm 图表(https://github.com/open-telemetry/opentelemetry-helm-charts/tree/main/charts/opentelemetry-collector
),该图表带有一些配置选项,可以更轻松地配置收集器。
首先需要添加 OpenTelemetry Helm 仓库:
$ helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
$ helm repo update
收集 Kubernetes 遥测数据的第一步是部署一个 OpenTelemetry Collector 的 DaemonSet 实例,以收集与节点和运行在这些节点上的工作负载相关的遥测数据。使用 DaemonSet 可以确保此收集器实例被安装在所有节点上。每个 DaemonSet 中的收集器实例将仅从其运行的节点收集数据。
通过 OpenTelemetry Collector Helm Chat 配置所有这些组件非常简单,它还会处理所有与 Kubernetes 相关的细节,例如 RBAC、挂载和主机端口等。不过需要注意的是,默认情况下这个 Chart 图表不会将数据发送到任何后端。
指标采集
我们这里首先创建一个 Prometheus 实例来收集指标数据,如下所示,我们使用 Helm Chart 来快速部署 Prometheus:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
$ helm repo update
然后创建一个 prometheus-values.yaml
文件来配置 Prometheus Helm Chart:
# prometheus-values.yaml
kubeStateMetrics:
enabled: false
nodeExporter:
enabled: false
kubelet:
enabled: false
kubeApiServer:
enabled: false
kubeControllerManager:
enabled: false
coreDns:
enabled: false
kubeDns:
enabled: false
kubeEtcd:
enabled: false
kubeScheduler:
enabled: false
kubeProxy:
enabled: false
sidecar:
datasources:
label: grafana_datasource
labelValue: "1"
dashboards:
enabled: true
prometheus:
prometheusSpec:
enableFeatures:
- remote-write-receiver
prometheusOperator:
enabled: true
admissionWebhooks:
patch:
enabled: true
image:
registry: cnych
repository: ingress-nginx-kube-webhook-certgen
tag: v20221220-controller-v1.5.1-58-g787ea74b6
grafana:
ingress:
enabled: true
ingressClassName: nginx
hosts:
- grafana.k8s.local
注意这里我们没有定制任何 Exporter,因为我们将使用 OpenTelemetry Collector 来收集指标数据,然后再将其发送到 Prometheus 中。此外为了能够将收集器指标发送到 Prometheus ,我们需要启用远程写入功能,正常只需要在 Prometheus 启动参数中指定 --web.enable-remote-write-receiver
即可,但是我们这里是通过 Prometheus Operator 方式部署的,所以我们需要去修改 Prometheus 的 CR 实例对象,启用 remote-write-receiver
特性。另外我们还为 Grafana 启用了 Ingress,这样我们就可以通过 grafana.k8s.local
来访问 Grafana 了,默认用户名为 admin
,密码为 prom-operator
。
接下来直接使用下面的命令一键部署 Prometheus 即可:
$ helm upgrade --install prometheus prometheus-community/kube-prometheus-stack -f prometheus-values.yaml --namespace kube-otel --create-namespace
Release "prometheus" does not exist. Installing it now.
NAME: prometheus
LAST DEPLOYED: Wed Aug 23 09:42:23 2023
NAMESPACE: kube-otel
STATUS: deployed
REVISION: 1
NOTES:
kube-prometheus-stack has been installed. Check its status by running:
kubectl --namespace kube-otel get pods -l "release=prometheus"
Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create & configure Alertmanager and Prometheus instances using the Operator.
部署后的资源对象如下所示:
$ kubectl get pods -n kube-otel
NAME READY STATUS RESTARTS AGE
alertmanager-prometheus-kube-prometheus-alertmanager-0 2/2 Running 0 6m3s
prometheus-grafana-5d95cbc57f-v2bw8 3/3 Running 0 61s
prometheus-kube-prometheus-operator-74fcfc7ff6-2bzfj 1/1 Running 0 6m19s
prometheus-prometheus-kube-prometheus-prometheus-0 2/2 Running 0 6m3s
$ kubectl get ingress -n kube-otel
NAME CLASS HOSTS ADDRESS PORTS AGE
prometheus-grafana nginx grafana.k8s.local 10.98.12.94 80 114s
现在我们需要将指标数据发送到 Prometheus,所以我们需要在 Otel 采集器里面去配置导出器,可以使用到 prometheus
或者 prometheusremotewrite
导出器。我们这里将使用如下的 otel-collector-ds-values.yaml
文件来配置 OpenTelemetry Collector Helm Chart:
# otel-collector-ds-values.yaml
mode: daemonset
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
clusterRole:
create: true
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
verbs:
- get
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- list
- watch
- get
presets:
hostMetrics:
enabled: true
kubernetesAttributes:
enabled: true
kubeletMetrics:
enabled: true
ports:
prom: # 添加一个 9090 端口,用于 Prometheus 抓取
enabled: true
containerPort: 9090
servicePort: 9090
protocol: TCP
service: # 创建一个 Service,后面 ServiceMonitor 会用到
enabled: true
config:
receivers:
prometheus:
config:
scrape_configs:
- job_name: opentelemetry-collector
scrape_interval: 10s
static_configs:
- targets:
- ${env:MY_POD_IP}:8888
exporters:
logging:
loglevel: debug
prometheus:
endpoint: "0.0.0.0:9090"
metric_expiration: 180m
resource_to_telemetry_conversion:
enabled: true
# prometheusremotewrite:
# endpoint: http://prometheus-kube-prometheus-prometheus:9090/api/v1/write
# tls:
# insecure: true
processors:
metricstransform:
transforms:
include: .+
match_type: regexp
action: update
operations:
- action: add_label
new_label: k8s.cluster.id
new_value: abcd1234
- action: add_label
new_label: k8s.cluster.name
new_value: youdian-k8s
service:
pipelines:
metrics:
exporters:
- prometheus
processors:
- memory_limiter # 内存限制一般放在最前面
- metricstransform
- k8sattributes
- batch # 批量处理器放在最后
receivers:
- otlp
- hostmetrics
- kubeletstats
- prometheus
直接使用上面的配置文件来部署 OpenTelemetry Collector DaemonSet:
$ helm upgrade --install opentelemetry-collector open-telemetry/opentelemetry-collector -f otel-ds-values.yaml --namespace kube-otel --create-namespace
$ kubectl get pods -n kube-otel
NAME READY STATUS RESTARTS AGE
opentelemetry-collector-agent-22rsm 1/1 Running 0 18h
opentelemetry-collector-agent-v4nkh 1/1 Running 0 18h
opentelemetry-collector-agent-xndlq 1/1 Running 0 18h
安装后我们可以查看当前采集器的配置信息,使用命令 kubectl get cm -n kube-otel opentelemetry-collector-agent -oyaml
:
exporters:
logging:
loglevel: debug
prometheus:
endpoint: 0.0.0.0:9090
metric_expiration: 180m
resource_to_telemetry_conversion:
enabled: true
extensions:
health_check: {}
memory_ballast:
size_in_percentage: 40
processors:
batch: {}
k8sattributes:
extract:
metadata:
- k8s.namespace.name
- k8s.deployment.name
- k8s.statefulset.name
- k8s.daemonset.name
- k8s.cronjob.name
- k8s.job.name
- k8s.node.name
- k8s.pod.name
- k8s.pod.uid
- k8s.pod.start_time
filter:
node_from_env_var: K8S_NODE_NAME
passthrough: false
pod_association:
- sources:
- from: resource_attribute
name: k8s.pod.ip
- sources:
- from: resource_attribute
name: k8s.pod.uid
- sources:
- from: connection
memory_limiter:
check_interval: 5s
limit_percentage: 80
spike_limit_percentage: 25
metricstransform:
transforms:
action: update
include: .+
match_type: regexp
operations:
- action: add_label
new_label: k8s.cluster.id
new_value: abcd1234
- action: add_label
new_label: k8s.cluster.name
new_value: youdian-k8s
receivers:
hostmetrics:
collection_interval: 10s
root_path: /hostfs
scrapers:
cpu: null
disk: null
filesystem:
exclude_fs_types:
fs_types:
- autofs
- binfmt_misc
- bpf
- cgroup2
- configfs
- debugfs
- devpts
- devtmpfs
- fusectl
- hugetlbfs
- iso9660
- mqueue
- nsfs
- overlay
- proc
- procfs
- pstore
- rpc_pipefs
- securityfs
- selinuxfs
- squashfs
- sysfs
- tracefs
match_type: strict
exclude_mount_points:
match_type: regexp
mount_points:
- /dev/*
- /proc/*
- /sys/*
- /run/k3s/containerd/*
- /var/lib/docker/*
- /var/lib/kubelet/*
- /snap/*
load: null
memory: null
network: null
kubeletstats:
auth_type: serviceAccount
collection_interval: 20s
endpoint: ${K8S_NODE_NAME}:10250
otlp:
protocols:
grpc:
endpoint: ${env:MY_POD_IP}:4317
http:
endpoint: ${env:MY_POD_IP}:4318
prometheus:
config:
scrape_configs:
- job_name: opentelemetry-collector
scrape_interval: 10s
static_configs:
- targets:
- ${env:MY_POD_IP}:8888
service:
extensions:
- health_check
- memory_ballast
pipelines:
metrics:
exporters:
- prometheus
processors:
- memory_limiter
- metricstransform
- k8sattributes
- batch
receivers:
- otlp
- hostmetrics
- kubeletstats
- prometheus
telemetry:
metrics:
address: ${env:MY_POD_IP}:8888
# ...... 省略其他
上面的配置信息是 OpenTelemetry Collector 真正运行时的配置信息,我们这里只保留了和 metrics 相关的配置。从上面配置文件可以看出我们定义了 4 个接收器:
- hostmetrics 接收器
- kubeletstats 接收器
- otlp 接收器
- prometheus 接收器
4 个处理器:
- batch 处理器
- memory_limiter 处理器
- k8sattributes 处理器
- metricstransform 处理器
2 个导出器:
- logging 导出器
- prometheus 导出器
下面我们来详细介绍一下其他组件。
otlp 接收器
otlp 接收器是在 OTLP 格式中收集跟踪、指标和日志的最佳解决方案。如果您在以其他格式发出应用程序遥测数据,那么收集器很有可能也有一个相应的接收器。这个前面我们已经详细介绍过了,我们这里定义了 http
和 grpc
两种协议,分别监听 4317
和 4318
端口。配置如下所示:
receivers:
otlp:
protocols:
grpc:
endpoint: ${env:MY_POD_IP}:4317
http:
endpoint: ${env:MY_POD_IP}:4318
hostmetrics 接收器
hostmetrics
接收器用于收集主机级别的指标,例如 CPU 使用率、磁盘使用率、内存使用率和网络流量。我们这里的配置如下所示:
receivers:
hostmetrics:
collection_interval: 10s
root_path: /hostfs
scrapers:
cpu: null
disk: null
filesystem:
exclude_fs_types:
fs_types:
- autofs
- binfmt_misc
- bpf
- cgroup2
- configfs
- debugfs
- devpts
- devtmpfs
- fusectl
- hugetlbfs
- iso9660
- mqueue
- nsfs
- overlay
- proc
- procfs
- pstore
- rpc_pipefs
- securityfs
- selinuxfs
- squashfs
- sysfs
- tracefs
match_type: strict
exclude_mount_points:
match_type: regexp
mount_points:
- /dev/*
- /proc/*
- /sys/*
- /run/k3s/containerd/*
- /var/lib/docker/*
- /var/lib/kubelet/*
- /snap/*
load: null
memory: null
network: null
配置红通过 collection_interval
指定了每 10 秒收集一次指标,并使用根路径 /hostfs
来访问主机文件系统。
hostmetrics 接收器包括多个抓取器,用于收集不同类型的指标。例如,cpu 抓取器用于收集 CPU 使用率指标,disk 抓取器用于收集磁盘使用率指标,memory 抓取器用于收集内存使用率指标,load 抓取器用于收集 CPU 负载指标。在这个配置文件中,我们只启用了 filesystem 抓取器,用于收集文件系统使用率指标。
filesystem 抓取器的配置中,指定了要排除某些文件系统类型和挂载点的指标收集。具体来说,它排除了文件系统类型 autofs
、binfmt_misc
、bpf
、cgroup2
......,它还排除了挂载点 /dev/*
、/proc/*
、/sys/*
、/run/k3s/containerd/*
、/var/lib/docker/*
、/var/lib/kubelet/*
和 /snap/*
,这些排除操作确保只收集相关的文件系统使用率指标。
kubeletstats 接收器
Kubelet Stats Receiver 用于从 kubelet 上的 API 服务器中获取指标。通常用于收集与 Kubernetes 工作负载相关的指标,例如 CPU 使用率、内存使用率和网络流量。这些指标可用于监视 Kubernetes 集群和工作负载的健康状况和性能。
Kubelet Stats Receiver 默认支持在端口 10250 暴露的安全 Kubelet 端点和在端口 10255 暴露的只读 Kubelet 端点。如果 auth_type
设置为 none,则将使用只读端点。如果 auth_type
设置为以下任何值,则将使用安全端点:
-
tls
告诉接收方使用 TLS 进行身份验证,并要求设置ca_file
、key_file
和cert_file
字段。 -
serviceAccount
告诉该接收者使用默认的 ServiceAccount 令牌来向 kubelet API 进行身份验证。 -
kubeConfig
告诉该接收器使用kubeconfig
文件(KUBECONFIG
环境变量或~/.kube/config
)进行身份验证并使用 APIServer 代理来访问 kubelet API。 -
initial_delay
(默认 = 1 秒),定义接收器在开始之前等待的时间。
此外还可以指定以下参数:
-
collection_interval
(默认= 10s),收集数据的时间间隔。 -
insecure_skip_verify
(默认= false),是否跳过证书验证。
默认情况下,所有生成的指标都基于 kubelet 的 /stats/summary
端点提供的资源标签。对于某些场景而言,这可能还不够。因此,可以利用其他端点来获取附加的元数据,并将它们设置为指标资源的额外标签。当前支持的元数据包括以下内容:
-
container.id
- 使用从通过/pods
暴露的容器状态获取的容器 ID 标签来增强指标。 -
k8s.volume.type
- 从通过/pods
暴露的 Pod 规范收集卷类型,并将其作为卷指标的标签。如果端点提供的信息不仅仅是卷类型,这些信息也会根据可用字段和卷类型进行同步。例如,aws.volume.id
将从awsElasticBlockStore
同步,gcp.pd.name
将从gcePersistentDisk
同步。
如果你希望将 container.id
标签添加到你的指标中,请使用 extra_metadata_labels
字段来启用它,例如:
receivers:
kubeletstats:
collection_interval: 10s
auth_type: "serviceAccount"
endpoint: "${env:K8S_NODE_NAME}:10250"
insecure_skip_verify: true
extra_metadata_labels:
- container.id
如果没有设置 extra_metadata_labels
,则不会进行额外的 API 调用来获取额外的元数据。
默认情况下,该收集器将收集来自容器、pod 和节点的指标。我们可以通过设置一个 metric_groups
来指定要收集的数据来源,可以指定的值包括 container
、pod
、node
和 volume
。比如希望仅从接收器收集节点和 Pod 指标,则可以使用以下配置:
receivers:
kubeletstats:
collection_interval: 10s
auth_type: "serviceAccount"
endpoint: "${env:K8S_NODE_NAME}:10250"
insecure_skip_verify: true
metric_groups:
- node
- pod
K8S_NODE_NAME
环境变量在 Kubernetes 集群里面我们可以通过 Downward API 来注入。
prometheus 接收器
Prometheus 接收器以 Prometheus 格式接收指标数据。该接收器旨在最大限度地成为 Prometheus 的替代品,但是目前不支持下面这些 Prometheus 的高级功能:
-
alert_config.alertmanagers
-
alert_config.relabel_configs
-
remote_read
-
remote_write
-
rule_files
该接收器是让 Prometheus 抓取你的服务的直接替代品。它支持 scrape_config
中的全部 Prometheus 配置,包括服务发现。就像在启动 Prometheus 之前在 YAML 配置文件中写入一样,例如:
prometheus --config.file=prom.yaml
注意:由于收集器配置支持 env 变量替换,prometheus 配置中的
$
字符将被解释为环境变量。如果要在 prometheus 配置中使用 $
字符,则必须使用 $$
对其进行转义。
比如我们可以通过下面的配置来让收集器接收 Prometheus 的指标数据,使用方法和 Prometheus 一样,只需要在 scrape_configs
中添加一个任务即可:
receivers:
prometheus:
config:
scrape_configs:
- job_name: opentelemetry-collector
scrape_interval: 10s
static_configs:
- targets:
- ${env:MY_POD_IP}:8888
- job_name: k8s
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
[__meta_kubernetes_pod_annotation_prometheus_io_scrape]
regex: "true"
action: keep
metric_relabel_configs:
- source_labels: [__name__]
regex: "(request_duration_seconds.*|response_duration_seconds.*)"
action: keep
我们这里添加的 opentelemetry-collector
任务,是去抓取 8888
端口的数据,而 8888
端口就是 OpenTelemetry Collector 的端口,这个端口我们在 service.telemetry
中已经定义了,这样我们就可以通过该接收器来抓取 OpenTelemetry Collector 本身的指标数据了。
文章转载自公众号:k8s技术圈