Kubernetes上で動くGoサーバーでプロファイラを動かしWeb UIで表示する

Goにはプロファイラとして標準パッケージにpprofが搭載されています。
pprofの使い方としてはすでに多数の優良記事が存在するため、ここでは扱いません。

今回はpprofをk8s上で動くサーバーに対して実行し、結果をWebUIで表示する必要があったのでそのやり方を紹介します。

環境

インフラ構成

  • GoサーバーのHTTP API用のPortが80
  • pprof用のPortが6060
  • プロファイラ結果のWeb UI用のPortが8080
    • このPortをServiceのNodePortでMacに公開

やり方

pprofの設定

まずは通常通りpprofの設定をしてGoをビルドします。

import (
    ...
    _ "net/http/pprof"
)

func main() {
    ...

    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()

    ...
}

このバイナリがk8sのPodで動いているとします。

Serviceの定義

通常のAPIへのアクセスに使うServiceが以下です。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-service
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80

これに追加してpprofのWebページにアクセスするためのServiceを定義します。
このServiceのTypeをNodePortにすることでお手軽にアクセスできるようになります。

apiVersion: v1
kind: Service
metadata:
  name: my-service-pprof
spec:
  selector:
    app: my-service-api
  type: NodePort
  ports:
    - name: http-pprof
      protocol: TCP
      port: 8080
      targetPort: 8080
      nodePort: 30080

pprofの実行

Goのバイナリが動くPodに入り以下のコマンドでpprofを実行します。

$ pprof -http=0.0.0.0:8080 /usr/local/bin/my-api http://localhost:6060/debug/pprof/profile

ここで大事なのはpprofのWebページのアドレスを 0.0.0.0 にすることです。ここを 127.0.0.1 にしていると外部からアクセスできなくなってしまいます。

あとは計測したいエンドポイントにアクセスし以下のようなメッセージが表示された後、ホストからNodePortの 30080 にアクセスすればプロファイル結果がWebUIで表示されます。

Saved profile in /root/pprof/pprof.my-api.samples.cpu.001.pb.gz
Serving web UI on http://0.0.0.0:8080
Couldn't find a suitable web browser!
Set the BROWSER environment variable to your desired browser.