はじめに
こんにちは、バックエンドエンジニアのまさです。
今回は業務でGo言語でAPIサーバーを構築する機会がありましたので、このAPIサーバーに対してシステム監視を適用する検証を行ってみました。
実運用時にはトラフィックの監視やシステム動作状況の監視等が必要になると思いますが、Go言語のechoフレームワークでは簡単にシステム監視ツールのPrometheusと連携できるとのことでしたので実践してみましたので、その内容について記載したいと思います。
Go言語のechoについて
Go言語のサーバーフレームワークの一つであるechoは人気も高く、扱いやすいサーバーフレームワークです。 githubのリポジトリ:https://github.com/labstack/echo
比較的軽量なサーバーフレームワークであり、APIサーバー等に適しているのではないかと思いました。コーディング自体も非常に簡潔な記述でサーバーを起動させることが可能です。
Prometheusについて
Prometheusもシステム監視ツールとして非常に人気があるGo言語製のPull型の監視システムです。ブラウザからアクセスしてPromQLというクエリによって柔軟に情報を取得でき視覚的に確認しやすいツールとなっています。
環境構築
Go言語のechoフレームワークでのサーバー構築
今回はPrometheusによる監視の検証を行うだけですので、シンプルな構成でサーバーを構築したいと思います。まずはGoのモジュールの初期化と依存ライブラリのダウンロードを行います。モジュール名はserverとしていますが任意の名前で問題ありません。
$ mkdir server
$ cd server
$ go mod init server
$ go get github.com/labstack/echo/v4
$ go get github.com/labstack/echo/v4/middleware
次にルートのGETエンドポイントのみ作成し”OK”という文字列をステータス200で返却するだけの処理としてmainプログラムを作成します。
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.GET("/", func(c echo.Context) error { return index(c) })
e.Logger.Fatal(e.Start(":1323"))
}
func index(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
作成したプログラムを実行することでサーバーが起動します。
$ go run main.go
curlを用いてサーバーへのアクセスを確認します。
$ curl -XGET -i "<http://localhost:1323/>"
上記で正常にレスポンスが確認できればサーバーの構築は完了ですが、さらにPrometheusによる監視のためのハンドラを追加します。まずはPrometheusのハンドラ用のMiddlewareを追加します。
$ go get github.com/labstack/echo-contrib/prometheus
次にプログラムを変更します。
main.go
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
// 下記を追加
"github.com/labstack/echo-contrib/prometheus"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// 下記を追加
p := prometheus.NewPrometheus("echo", nil)
p.Use(e)
e.GET("/", func(c echo.Context) error { return index(c) })
e.Logger.Fatal(e.Start(":1323"))
}
func index(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
再度プログラムを実行しサーバーを起動します。
$ go run main.go
curlを用いてprometheus用のエンドポイントが有効になっていることを確認します。
$ curl -XGET -i "<http://localhost:1323/metrics>"
prometheusが情報を取得するための出力が表示されればサーバーの構築は完了です。
アプリケーションのdockerコンテナ組み込み
先程作成したgoアプリケーションをdockerコンテナとして組み込みます。dockerコンテナ用のディレクトリを起点として、下記のようにgoアプリケーションを格納したディレクトリ構成にします。
gosv/ # <-- dockerコンテナ用ディレクトリ
├── Dockerfile
└── server # <-- goアプリケーションを作成したディレクトリ
├── go.mod
├── go.sum
└── main.go
dockerコンテナ用のディレクトリの直下にはDockerfileを作成します。
Dockerfile
FROM golang:1.18.3-alpine as dev
ENV ROOT=/go/src/app
ENV CGO_ENABLED 0
RUN apk update && apk add git make
RUN mkdir -p /go/src/
WORKDIR /go/src
COPY ./server ./server
ENV DEV_ROOT=/go/src/server
WORKDIR ${DEV_ROOT}
RUN go mod download
CMD ["go", "run", "main.go"]
prometheusの設定の作成
prometheusもdockerコンテナとして構築しますが、こちらはコンテナイメージを使うので作成するものとしては設定ファイルのみです。最低限必要な監視対象のサーバー設定項目のみ調整しておきます。
prometheus.yml
# my global config
global:
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 configuration
alerting:
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=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["gosv:1323"] # <--- 監視対象のサーバーを記述する
こちらもdockerコンテナ用のディレクトリに格納しておきます。
prometheus/ # <-- dockerコンテナ用ディレクトリ
└── prometheus.yml
docker-compose.ymlの作成
上記二つのサーバーをdocker-composeでまとめて操作するため、docker-compose.ymlを作成します。
docker-compose.yml
version: '3.8'
services:
gosv:
build:
context: ./gosv
target: dev
ports:
- 1323:1323
prom:
image: prom/prometheus
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- 9090:9090
command: "--config.file=/etc/prometheus/prometheus.yml"
最終的なディレクトリ構成は以下のようになります。
work/
├── docker-compose.yml
├── gosv
│ ├── Dockerfile
│ └── server
│ ├── go.mod
│ ├── go.sum
│ └── main.go
└── prometheus
└── prometheus.yml
サーバーの起動
docker-compose.ymlを作成したら下記のコマンドでサーバーの起動を行います。
$ docker compose up -d
# 旧バージョンのdocker-composeの場合は下記で起動
# docker-compose up -d
サーバーが起動したらprometheusにブラウザで接続してみます。ブラウザでdockerの環境に応じたアドレスにアクセスします。
例: http://localhost:9090/
上記の画面が表示されればprometheusへの接続ができています。
またGo言語のサーバーとの通信状況も確認するため、下記のアドレスにアクセスしてみます。
例: http://localhost:9090/targets?search=
Goのサーバーと正常に接続できていることが確認できます。
それでは先ほどの画面に戻り、実際にサーバーの稼働状況の取得を行ってみます。
グラフ画面の検索クエリボックスに取得クエリを入力することでグラフが表示されます。
process_resident_memory_bytes(メモリ使用量)
echo_requests_total(リクエスト数の合計)
更に用途に応じて様々なグラフを出力することが可能ですので、監視要件に応じて調整してみてください。
おわりに
今回はGo言語サーバーに対して低コストで監視システムを適用する方法として、Prometheusの適用方法を紹介させていただきました。Prometheusはどのシステムに対しても非常に組み込みやすくなっており、導入コストが低く汎用性が高い監視システムだと思いますので、一度お試ししてみてはいかがでしょうか。