You need to enable JavaScript to run this app.
导航

使用托管 Prometheus 监控 Golang 应用

最近更新时间2024.03.01 14:07:17

首次发布时间2023.06.09 15:54:45

当您在容器服务集群中部署 Golang 应用时,可以使用 托管 Prometheus(VMP) 服务对 Golang 应用进行监控。本文为您介绍在集群中监控 Golang 应用的方法和操作步骤。

背景信息

Prometheus 提供了 官方版 Golang 库 用于采集并暴露监控数据。当您开发 Golang 应用时,可以使用该 Golang 库来暴露 Golang runtime 相关的数据。

说明

Golang Client API 相关的文档详见 GoDoc

安装依赖

您可以通过 go get 命令来安装相关依赖,示例如下:

go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/collectors
go get github.com/prometheus/client_golang/prometheus/promhttp

运行时指标

  1. 创建一个 HTTP 服务,路径使用 /metrics。可以直接使用 prometheus/promhttp 里提供的 Handler 函数。

    如下是一个简单的示例,通过 http://localhost:2023/metrics 暴露 Golang 应用的一些默认指标数据,包括:运行时指标、进程相关指标以及构建相关的指标。

    package main
    
    import (
            "math"
            "math/rand"
            "net/http"
            "time"
    
            "github.com/prometheus/client_golang/prometheus"
            "github.com/prometheus/client_golang/prometheus/collectors"
            "github.com/prometheus/client_golang/prometheus/promhttp"
    )
    
    func main() {
            // Create a new registry.
            reg := prometheus.NewRegistry()
    
            // Add Go module build info.
            reg.MustRegister(collectors.NewBuildInfoCollector())
            // Add go runtime metrics and process collectors.
            reg.MustRegister(
                    collectors.NewGoCollector(),
                    collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
            )
    
            http.Handle("/metrics", promhttp.HandlerFor(
                    reg, promhttp.HandlerOpts{},
            ))
            http.ListenAndServe(":2023", nil)
    }
    
  2. 执行以下命令,启动应用。

    go run main.go
    
  3. 执行以下命令,即可查看运行时的指标数据。

    curl http://localhost:2023/metrics
    

应用层指标

  1. 上述示例仅仅暴露了一些基础的内置指标。应用层面的指标还需要额外添加。
    如下示例暴露了一个名为 rpc_durations_seconds 的指标,用于对服务的 RPC 延迟进行统计。
    package main
    
    import (
            "math"
            "math/rand"
            "net/http"
            "time"
    
            "github.com/prometheus/client_golang/prometheus"
            "github.com/prometheus/client_golang/prometheus/collectors"
            "github.com/prometheus/client_golang/prometheus/promhttp"
    )
    
    var rpcDurations = prometheus.NewSummaryVec(
            prometheus.SummaryOpts{
                    Name:       "rpc_durations_seconds",
                    Help:       "RPC latency distributions.",
                    Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
            },
            []string{"service"},
    )
    
    func main() {
            // Create a new registry.
            reg := prometheus.NewRegistry()
    
            // Add Go module build info.
            reg.MustRegister(collectors.NewBuildInfoCollector())
            // Add go runtime metrics and process collectors.
            reg.MustRegister(
                    collectors.NewGoCollector(),
                    collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
            )
    
            reg.MustRegister(rpcDurations)
    
            start := time.Now()
    
            oscillationFactor := func() float64 {
                    return 2 + math.Sin(math.Sin(2*math.Pi*float64(time.Since(start))/float64(10*time.Minute)))
            }
    
            // Periodically record some sample latencies for the three services.
            go func() {
                    for {
                            v := rand.Float64() * 0.0002
                            rpcDurations.WithLabelValues("uniform").Observe(v)
                            time.Sleep(time.Duration(100*oscillationFactor()) * time.Millisecond)
                    }
            }()
    
            go func() {
                    for {
                            v := (rand.NormFloat64() * 0.0002) + 0.00001
                            rpcDurations.WithLabelValues("normal").Observe(v)
                            time.Sleep(time.Duration(75*oscillationFactor()) * time.Millisecond)
                    }
            }()
    
            go func() {
                    for {
                            v := rand.ExpFloat64() / 1e6
                            rpcDurations.WithLabelValues("exponential").Observe(v)
                            time.Sleep(time.Duration(50*oscillationFactor()) * time.Millisecond)
                    }
            }()
    
            http.Handle("/metrics", promhttp.HandlerFor(
                    reg, promhttp.HandlerOpts{},
            ))
            http.ListenAndServe(":2023", nil)
    }
    
  2. 执行以下命令,启动应用。
    go run main.go
    
  3. 执行以下命令,即可查看运行时的指标数据。
    curl http://localhost:2023/metrics
    
    从输出结果我们可以看到 rpc_durations_seconds 计数器相关的信息,包括帮助文档、类型信息、指标名和当前值。
    # HELP rpc_durations_seconds RPC latency distributions.
    # TYPE rpc_durations_seconds summary
    rpc_durations_seconds{service="exponential",quantile="0.5"} 7.427294276581254e-07
    rpc_durations_seconds{service="exponential",quantile="0.9"} 2.3157390817424027e-06
    

监控 Golang 应用示例

前提条件

打包应用

  1. 您可以将上面的 Golang 源代码,使用如下形式的 Dockerfile 打包为镜像,方便部署在容器服务 VKE 集群中。

    说明

    该 Dockerfile 仅为示例,您需要按需修改里面的参数。

    FROM golang:1.19 as builder
    COPY . /go/src/demo
    WORKDIR /go/src/demo
    RUN go env -w GOPROXY=https://goproxy.cn,direct && \
        go mod init && \
        go mod tidy && \
        go mod vendor && \
        go build -v -o /golang-demo
    
    FROM buildpack-deps:bullseye-curl
    RUN mkdir -p /app
    COPY --from=builder /golang-demo /app
    WORKDIR     /app
    ENV TZ Asia/Shanghai
    EXPOSE 2023
    ENTRYPOINT  ["/app/golang-demo"]
    
    
  2. 镜像创建完成后,可以上传至 火山引擎 镜像仓库 中使用。也可以使用其他公有云或自建镜像仓库。

    说明

    火山引擎镜像仓库的镜像推送方式,请参见 推送和拉取镜像

部署应用

您可以使用镜像仓库中的镜像,在容器服务 VKE 集群中部署应用。步骤如下:

  1. 登录 容器服务控制台
  2. 单击左侧导航栏中的 集群
  3. 在集群列表页面,单击目标集群,进入集群管理页面。
  4. 在左侧菜单栏中选择 工作负载 > 无状态负载。 单击 使用 Yaml 创建 ,部署应用。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: golang-demo # 配置应用的名称
      namespace: volcano-metrics # 配置应用所在的命名空间
      labels:
        app: golang-demo # 配置应用的标签
    spec:
      replicas: 2 # 配置应用副本数
      selector:
        matchLabels:
          app: golang-demo
      template:
        metadata:
          labels:
            app: golang-demo
        spec:
          containers:
          - name: golang-demo # 配置容器名称
            image: doc-cn-beijing.cr.volces.com/vmp/golang-demo:1.0 # 配置应用镜像的地址和版本
            ports:
            - containerPort: 2023 # 配置容器端口
    
  5. 在左侧导航栏中,选择 服务与路由 > 服务,单击 使用 Yaml 创建 ,配置服务。
    apiVersion: v1
    kind: Service
    metadata:
      name: golang-service-demo
      namespace: volcano-metrics # 配置 Service 的命名空间
      labels: 
        app: golang-service-demo # 配置 Service 的标签
    spec:
      selector:
        app: golang-demo
      ports:
        - protocol: TCP
          port: 2023
          targetPort: 2023
          name: metrics # 配置服务端口名称
      type: ClusterIP
    

配置服务发现

当应用部署并正常运行后,可以使用 ServiceMonitor 配置无法发现,具体的操作步骤如下:

  1. 在左侧菜单栏中选择 工作负载 > 对象浏览器。 单击 使用 Yaml 创建 ,通过 ServiceMonitor 配置服务发现。
    • 类型 下拉菜单中选择 自定义
    • Yaml 配置框内输入 Yaml 配置。
      apiVersion: monitoring.coreos.com/v1
      kind: ServiceMonitor
      metadata:
        name: golang-demo    # 填写一个唯一名称
        namespace: default # 配置 ServiceMonitor 命名空间
        labels: 
          volcengine.vmp: "true" # 配置 ServiceMonitor 的标签,允许被 Prometheus-agent 发现
      spec:
        endpoints:
        - interval: 30s
          port: metrics # 配置服务端口名称
          path: /metrics
          relabelings:
          - action: replace
            sourceLabels:  [__meta_kubernetes_pod_label_app]
            targetLabel: application
        namespaceSelector:
          matchNames:
          - volcano-metrics # 配置服务所在的命名空间
        selector:
          matchLabels:
            app: golang-service-demo # 配置服务的 Label 值,以定位目标服务
      

查看监控数据

您可以使用托管 Prometheus 服务的 Explore 功能来查看监控指标数据。详情请参见 指标查询
alt

您也可以使用 Grafana 读取托管 Prometheus 服务中存储的数据,并创建指标大盘。详情请参见 将托管 Prometheus 数据接入自建 Grafana