监控集群基础设施

    在本章的“部署Prometheus”小节,我们使用了Kubernetes内置的控制器之一Deployment。Deployment能够确保Prometheus的Pod能够按照预期的状态在集群中运行,而Pod实例可能随机运行在任意节点上。而与Prometheus的部署不同的是,对于Node Exporter而言每个节点只运行一个唯一的实例,此时,就需要使用Kubernetes的另外一种控制器Daemonset。顾名思义,Daemonset的管理方式类似于操作系统中的守护进程。Daemonset会确保在集群中所有(也可以指定)节点上运行一个唯一的Pod实例。

    创建node-exporter-daemonset.yml文件,并写入以下内容:

    由于Node Exporter需要能够访问宿主机,因此这里指定了hostNetwork和hostPID,让Pod实例能够以主机网络以及系统进程的形式运行。同时YAML文件中也创建了NodeExporter相应的Service。这样通过Service就可以访问到对应的NodeExporter实例。

    1. service "node-exporter" created
    2. daemonset "node-exporter" created

    查看Daemonset以及Pod的运行状态

    1. $ kubectl get daemonsets
    2. NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
    3. node-exporter 1 1 1 1 1 <none> 15s
    4. $ kubectl get pods
    5. NAME READY STATUS RESTARTS AGE
    6. ...
    7. node-exporter-9h56z 1/1 Running 0 51s

    由于Node Exporter是以主机网络的形式运行,因此直接访问MiniKube的虚拟机IP加上Pod的端口即可访问当前节点上运行的Node Exporter实例:

    1. $ minikube ip
    2. 192.168.99.100
    3. $ curl http://192.168.99.100:9100/metrics
    4. ...
    5. process_start_time_seconds 1.5251401593e+09
    6. # HELP process_virtual_memory_bytes Virtual memory size in bytes.
    7. # TYPE process_virtual_memory_bytes gauge
    8. process_virtual_memory_bytes 1.1984896e+08

    在Kubernetes下Service是作为一个内部负载均衡器的存在,它对外暴露一个唯一访问地址(ClusterIP),后端则通过Endpoint指向多个Pod实例。

    例如,通过以下命令可以查看Node Exporter实例对应的IP地址:

    由于Service中指定了标签选择器(app: node-exporter),Kubernetes就会自动找到该选择器对应的Pod实例的访问信息(这里是192.168.99.100:9100),并创建Service对应的Endpoint,通过以下命令查看:

    1. $ kubectl get endpoints node-exporter
    2. NAME ENDPOINTS AGE
    3. node-exporter 192.168.99.100:9100 4m

    最后查看Service的详细信息:

    1. $ kubectl describe svc node-exporter
    2. Name: node-exporter
    3. Namespace: default
    4. Labels: app=node-exporter
    5. name=node-exporter
    6. Annotations: prometheus.io/scrape=true
    7. Selector: app=node-exporter
    8. IP: 10.100.42.83
    9. Port: scrape 9100/TCP
    10. TargetPort: 9100/TCP
    11. Session Affinity: None
    12. Events: <none>

    将Service与Endpoint分离还带来另外一个好处,如果我们希望集群内的应用程序,能够通过Service的形式访问到集群外的资源(如,外部部署的MySQL)。这是我们可以创建一个不包含Selector的Service即可,并且手段创建该Service需要代理的外部服务即可。

    例如,创建服务mysql-production,并且指向集群外运行的MySQL服务:

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. name: mysql-production
    5. spec:
    6. ports:
    7. - port: 3306
    8. ---
    9. kind: Endpoints
    10. apiVersion: v1
    11. metadata:
    12. name: mysql-production
    13. subsets:
    14. - addresses:
    15. - ip: 192.168.1.25
    16. ports:
    17. - port: 3306

    在了解了Kubernetes下Service与Endpoint的关系以后,我们就能大概理解,在Kubernetes下部署应用程序时,通过Endpoint是能够找到特定服务的多个访问地址的。这样我们就可以通过这些地址获取到相应的监控指标。 而Service作为负载均衡器,则适用于作为服务可用性的探测标准,因此可以将Blackbox与Service相结合,监控服务的可用性。

    在Prometheus中,通过设置kubernetes_sd_config的role为endpoints指定当前的服务发现模式:

    1. metadata:
    2. annotations:
    3. prometheus.io/scrape: 'true'

    通过Kubernetes获取到的Endpoint对象,如下所示,是通过Kubernetes自动发现的Endpoint对象的所有metadata标签:

    1. __address__="192.168.99.100:9100"
    2. __meta_kubernetes_endpoint_port_name="scrape"
    3. __meta_kubernetes_endpoint_port_protocol="TCP"
    4. __meta_kubernetes_endpoint_ready="true"
    5. __meta_kubernetes_endpoints_name="node-exporter"
    6. __meta_kubernetes_namespace="default"
    7. __meta_kubernetes_pod_container_name="node-exporter"
    8. __meta_kubernetes_pod_container_port_number="9100"
    9. __meta_kubernetes_pod_container_port_protocol="TCP"
    10. __meta_kubernetes_pod_host_ip="192.168.99.100"
    11. __meta_kubernetes_pod_label_app="node-exporter"
    12. __meta_kubernetes_pod_label_controller_revision_hash="4286002507"
    13. __meta_kubernetes_pod_label_pod_template_generation="1"
    14. __meta_kubernetes_pod_name="node-exporter-st4cd"
    15. __meta_kubernetes_pod_node_name="minikube"
    16. __meta_kubernetes_pod_ready="true"
    17. __meta_kubernetes_pod_uid="7fe1c063-4ce5-11e8-a82a-08002717c1c9"
    18. __meta_kubernetes_service_annotation_prometheus_io_scrape="true"
    19. __meta_kubernetes_service_label_app="node-exporter"
    20. __meta_kubernetes_service_label_name="node-exporter"
    21. __meta_kubernetes_service_name="node-exporter"
    22. __metrics_path__="/metrics"
    23. __scheme__="http"
    24. job="kubernetes-service-endpoints"

    由于该Endpoint属于特定的Servie,并且backend指向了具体的Pod实例,所以返回的metadata标签中包含了关联的Service的信息(以__meta_kubernetes_service作为前缀)以及后端Pod的相关信息(以__meta_kubernetes_pod作为浅醉)。

    通过relabeling的keep模式,选择只获取包含了标签__meta_kubernetes_service_annotation_prometheus_io_scrape并且其值为true的Endpoint作为监控目标:

    1. - job_name: 'kubernetes-service-endpoints'
    2. kubernetes_sd_configs:
    3. - role: endpoints
    4. relabel_configs:
    5. - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
    6. action: keep
    7. regex: true
    8. - source_labels: [__meta_kubernetes_endpoints_name]
    9. target_label: job

    Relabeling保留符合规则的Endpoint

    这种基于Service的annotations来控制Prometheus的方式,还可以扩展出更多的玩法。例如,如果应用程序并没有通过/metrics暴露监控样本数据。 下面是一个更完整的采集任务配置如下所示:

    通过以上步骤,用户可以通过在Service添加注解的形式,更灵活的控制Prometheus的任务采集信息,例如,通过添加注解自定义采集数据的相关配置:

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. annotations:
    5. prometheus.io/scrape: 'true'
    6. prometheus.io/scheme: 'https'