Go 监控的标配:实战 Prometheus

最近手头的项目开始从 PHP , Lua 迁移到 Golang , 心想正好趁此机会夯实监控 , 提到 Golang 的监控 , 不得不说 prometheus[1] 已经是标配 , 在 Golang 里集成[2]起来非常简单:
package mainimport ("net/http""github.com/prometheus/client_golang/prometheus/promhttp")func main() {http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":6060", nil)}如果想在本地 docker 里部署 prometheus , 那么只需一条 docker run 命令:
shell> docker run -p 9090:9090 prom/prometheus运行后打开浏览器浏览 http://localhost:9090/targets 即可 , 这里显示了相关的监控信息 , 缺省情况下 , 监控了 prometheus 本身 。
虽然在本地 docker 里部署非常简单 , 但是如果想在 kubenetes 里部署[3]的话却是另一番经景象了 , 加之官方文档[4]语焉不详 , 以至于我几次想中途而废 , 还好最后坚持下来了 , 本文记录了我在部署过程中遇到的一些坑坑洼洼以及解决方法 。
关于配置的问题Prometheus 缺省的配置文件是「/etc/prometheus/prometheus.yml」 , 如果我们要修改配置文件的话 , 那么按照官方文档[5]里的说明 , 需要自定义一个 Dockerfile 文件:
FROM prom/prometheusADD prometheus.yml /etc/prometheus/然后再构建新的镜像:
shell> docker build -t my-prometheus .shell> docker run -p 9090:9090 my-prometheus不得不说有点繁琐 , 实际上利用 kubenetes 的 ConfigMap[6] 即可:
apiVersion: v1kind: ConfigMapmetadata:name: prometheusnamespace: bpd-iedata:prometheus.yml: |# my global configglobal:scrape_interval:15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.# scrape_timeout is set to the global default (10s).# Alertmanager configurationalerting:alertmanagers:- static_configs:- targets:# - alertmanager:9093# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.rule_files:# - "first_rules.yml"# - "second_rules.yml"# A scrape configuration containing exactly one endpoint to scrape:# Here it's Prometheus itself.scrape_configs:# The job name is added as a label `job=` to any timeseries scraped from this config.- job_name: 'prometheus'# metrics_path defaults to '/metrics'# scheme defaults to 'http'.static_configs:- targets: ['localhost:9090']至于如何把 ConfigMap 挂到容器里 , 可以参考后面的配置 。
关于服务发现的问题传统监控软件往往采用的是 push 模式 , 而 prometheus 采用的是 pull 模式 。 好处是架构简单 , 被监控的节点不需要部署 agent 之类的代理进程 , 坏处是 prometheus 必须知道所有需要被监控的节点 , 比如缺省配置(/etc/prometheus/prometheus.yml)就会通过 static_configs[7] 抓取 prometheus 服务本身的节点信息:
scrape_configs:- job_name: 'prometheus'static_configs:- targets: ['localhost:9090']如果需要被监控的节点比较固定的话 , 那么通过 static_configs 来硬编码倒也无妨 , 不过在 kubenetes 中 , 各个业务需要被监控的容器个数随时可能会发生变化 , 相应的容器地址也随时可能会发生变化 , 此时如果再通过 static_configs 来硬编码的话 , 那么无疑是自讨苦吃 , 相对而言更合理的方法是使用 kubernetes_sd_config[8] 打通服务发现机制 , 从而实现自动配置节点信息 , 不过前提条件是我们必须先在 kubenetes 中配置 RBAC[9] 信息:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:name: prometheusrules:- apiGroups: [""]resources:- nodes- nodes/metrics- services- endpoints- podsverbs: ["get", "list", "watch"]- apiGroups:- extensions- networking.k8s.ioresources:- ingressesverbs: ["get", "list", "watch"]- nonResourceURLs: ["/metrics", "/metrics/cadvisor"]verbs: ["get"]---apiVersion: v1kind: ServiceAccountmetadata:name: prometheusnamespace: default---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: prometheusroleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: prometheussubjects:- kind: ServiceAccountname: prometheusnamespace: default不过我的 kubenetes 账号权限不够 , 配置 RBAC 信息的时候会报错:
clusterrolebindings.rbac.authorization.k8s.io “prometheus” is forbidden: User “…” cannot patch resource “clusterrolebindings” in API group “rbac.authorization.k8s.io” at the cluster scope
找 kubenetes 管理员来配置固然可以解决问题 , 但是以后有相关问题的话会不可避免的依赖上别人了 , 最好还是能自己解决问题:既然 kubernetes_sd_config 有困难 , 那么我们不妨考虑换一种服务发现机制 , 比如说 dns_sd_config[10] , 通过域名解析动态获取节点:
scrape_configs:- job_name: 'foo'dns_sd_configs:- names: ['foo.default.svc.cluster.local']type: Aport: 6060