はじめに

こんにちは、バックエンドエンジニアのまさです。
今回は業務で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はどのシステムに対しても非常に組み込みやすくなっており、導入コストが低く汎用性が高い監視システムだと思いますので、一度お試ししてみてはいかがでしょうか。

SHARE

  • facebook
  • twitter

SQRIPTER

AGEST Engineers

AGEST

記事一覧

AGESTのエンジニアが情報発信してます!
AGESTのサービスやソリューションのお問い合わせページはこちらです。

株式会社AGEST

Sqriptsはシステム開発における品質(Quality)を中心に、エンジニアが”理解しやすい”Scriptに変換して情報発信するメディアです

  • 新規登録/ログイン
  • 株式会社AGEST