CLOVER🍀

That was when it all began.

Grafana Mimir+MinIOをUbuntu Linux 24.04 LTSにインストールして、Prometheusのリモート書き込み先として使う

これは、なにをしたくて書いたもの?

Grafana OSSを見ていて、Prometheusのストレージとして使えるGrafana Mimirというものがあると知ったので、ちょっと
見てみようかなということで。

Grafana Mimir

Grafana Mimirのページはこちら。

Grafana Mimir OSS | Prometheus long-term storage

ドキュメントはこちら。

Grafana Mimir documentation | Grafana Mimir documentation

Grafana Mimirは高可用性、マルチテナント、耐久性のあるストレージ、長期間にわたる高速なクエリーパフォーマンスを持った、
10億以上のアクティブシリーズに拡張できるものだとされています。

Mimir lets you scale metrics to 1 billion active series and beyond, with high availability, multi-tenancy, durable storage, and blazing fast query performance over long periods of time.

Grafana Mimirの特徴は以下のようです。

  • Prometheusとの互換性
    • リモート書き込み、PromQL、アラート機能
  • レプリケーションによる高可用性
  • Amazon S3Google Cloud Storage、Amazon Blob Storage、OpenStack Swiftを使った長期データ保存
  • 水平方向にスケーラブルなシャードクエリーエンジンによる超高速クエリー
  • 水平スケーラブルなコンパクターによる無制限のカーディナリティー、10億のアクティブシリーズでテスト済み
  • 高度なマルチテナントと分離性
  • 水平スケーラブルなクラスター化されたアーキテクチャ
  • Influx、OpenTelemetry、Graphite、Datadogと互換性のあるメトリクスの取り込み

Grafana Mimirのアーキテクチャーを見てみます。

Grafana Mimir architecture | Grafana Mimir documentation

Grafana Mimirはマイクロサービスベースのアーキテクチャーを採用し、個別に並列実行可能なコンポーネントで構成されています。

Grafana Mimir has a microservices-based architecture. The system has multiple horizontally scalable microservices that can run separately and in parallel. Grafana Mimir microservices are called components.

バイナリー自体は単一であり、-targetパラメーターでどのコンポーネントとして動作するか決めるようです。

Grafana Mimir’s design compiles the code for all components into a single binary. The -target parameter controls which component(s) that single binary will behave as.

To get started easily, run Grafana Mimir in monolithic mode with all components running simultaneously in one process, or in read-write mode, which groups components into read, write, and backend paths.

すべてのコンポーネントをひとつのプロセスで動作させるモノリシックモード、各コンポーネントをそれぞれの役割で実行する
マイクロサービスモード、コンポーネントを読み込み、書き込み、バックエンドパスにグループ化するRead-Writeモードの
3つの実行形態があるようです。

詳しくはこちらへ。ただし、Read-Writeモードはまだ実験段階です。

Grafana Mimir deployment modes | Grafana Mimir documentation

Grafana Mimirを構成するコンポーネントはこちら。

Grafana Mimir components | Grafana Mimir documentation

多くのコンポーネントはステートレスだそうですが、一部ステートフルなものがあるようです。各コンポーネントの概要はこちら。

  • compactor
    • ブロックを結合することでクエリーのパフォーマンスを向上させ、長期のストレージの使用量を削減する
  • distributor
    • PrometheusまたはGrafana Alloyから時系列データを受信し、ingesterに並列送信する
  • ingester(ステートフル)
    • 受信した時系列データを書き込みパス上のLong-termストレージに書き込み、読み取りパス上の時系列データサンプルを返す
  • querier
    • 読み取りパスで時系列データとラベルを取得してPromQL式を評価する
  • query-frontend
    • 読み取りパスを高速化する。必須ではないが利用を推奨しており、クエリーリクエストをquerierではなくquery-frontendに送信する
  • store-gateway(ステートフル)
    • Long-termストレージからブロックをクエリーする
  • (オプション)alertmanager
    • Prometheus Alertmanagerにマルチテナントサポートと水平スケーラビリティを追加したもの
  • (オプション)qverrides-exporter
    • テナントごとにオーバーライドを行い、制限を設定できる。制限はPrometheusメトリクスとして公開され、テナントがどれくらい制限に近づいているか確認できる
  • (オプション)query-scheduler
    • 実行するクエリーのキューを保持し、利用可能なquerierにワークロードを分散する
  • (オプション)ruler
    • レコーディングルールとアラートルールとして定義されたPromQL式を評価する

これらのコンポーネントの役割を見た後にアーキテクチャーの図を見ると、少しわかりやすくなると思います。

Grafana Mimir architecture / Grafana Mimir components

書き込みパス。

各リクエストはテナントに属していて、ingesterはローカルに保持するテナント固有のTSDBに保存します。メモリーとWALにも
保持します。

また各時系列データはデフォルトでは3つのingesterに複製され、各ingesterは独自のブロックをLong-termストレージに
書き込みます。その後、compactorが複数のingesterのブロックをひとつのブロックにマージし、重複するサンプルを
削除するようです。

読み込みパス。

query-frontendは長い期間に渡るクエリーを複数の小さなクエリーに分割します。query-frontendはキャッシュも持つようです。

querierはキューからクエリーを取得し、必要なデータを得るためにstore-gatewayとingesterに接続します。

querierの実行結果はquery-frontendが集計してクライアントに返します。

Prometheusの役割について。

Prometheusはリモート書き込みAPIを使用して、スクレイピングしたメトリクスをGrafana Mimirにプッシュします。
リモート書き込みAPIは、HTTP PUTリクエストのボディにSnappyで圧縮されたProtocol Buffersメッセージをバッチ形式で
出力します。

Grafana Mimir architecture / The role of Prometheus

Prometheusのリモート書き込みAPIについてはこちら。

Storage / Remote storage integrations

Grafana Mimirでは各リクエストにテナントを識別するための、テナントIDを指定するヘッダーが必要です。

認証・認可はGrafana Mimirの機能としては持っていません。

Long-termストレージについて。

Grafana Mimirのストレージ形式は、PrometheusのTSDBストレージにもとづいています。TSDBはテナント別に保持するようです。
ディスク上のブロックに時系列データを保存し、各ブロックの範囲はデフォルトで2時間です。

Grafana Mimir architecture / Long-term storage

ブロックファイルには、以下のオブジェクトストアが利用できます。

詳しくはこちらも参照。

Configure Grafana Mimir object storage backend | Grafana Mimir documentation

Configure Grafana Mimir metrics storage retention | Grafana Mimir documentation

ちなみに、Grafana MimirはCortexのフォークらしいです。

Grafana Mimir Q&A with Grafana Labs CEO Raj Dutt | Grafana Labs

ひとまずドキュメントを見るのはこれくらいにして、Grafana Mimirを使ってみましょう。

お題

今回は以下のお題で試してみます。

  • Grafana MimirをPrometheusのリモート書き込み先として使用する
    • Long-termストレージにはMinIOを使う
  • Prometheusの自分自身のメトリクスを収集し、Grafanaで認識していることを確認する
  • Grafana Mimirの自分自身のメトリクスを収集し、Grafanaで認識していることを確認する
  • GrafanaのデータソースにはPrometheusを使い、接続先をGrafana Mimirとする

ここまで登場する要素は、すべて単一のUbuntu Linux 24.04 LTSのサーバーにインストールします。
またGrafana Mimir以外については、インストールは簡単に済ませます。

環境

今回の環境はこちら。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 24.04.2 LTS
Release:        24.04
Codename:       noble


$ uname -srvmpio
Linux 6.8.0-64-generic #67-Ubuntu SMP PREEMPT_DYNAMIC Sun Jun 15 20:23:31 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

準備

ひとまず、各構成要素をインストールします。

Grafana。

$ sudo apt install apt-transport-https software-properties-common wget
$ sudo mkdir -p /etc/apt/keyrings/
$ wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
$ echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt update
$ sudo apt install grafana
$ sudo systemctl enable grafana-server
$ sudo systemctl start grafana-server
$ grafana-server --version
Version 12.1.0 (commit: ccd7b6ce7ea6184b8c7eb1de044174147dd9a648, branch: HEAD)

Prometheus。

$ curl -LO https://github.com/prometheus/prometheus/releases/download/v3.5.0/prometheus-3.5.0.linux-amd64.tar.gz
$ tar xf prometheus-3.5.0.linux-amd64.tar.gz
$ cd prometheus-3.5.0.linux-amd64
$ ./prometheus

MinIO。

$ curl -LO https://dl.min.io/server/minio/release/linux-amd64/minio_20250723155402.0.0_amd64.deb
$ sudo dpkg -i minio_20250723155402.0.0_amd64.deb
$ sudo systemctl enable minio

$ sudo useradd -s /bin/false minio-user
$ sudo mkdir -p /var/lib/minio
$ sudo chown minio-user:minio-user /var/lib/minio

/etc/default/minio

MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin

MINIO_VOLUMES=/var/lib/minio

MINIO_OPTS='--console-address :9001'

起動。

$ sudo systemctl start minio

MinIOクライアント。

$ curl -LO https://dl.min.io/client/mc/release/linux-amd64/mcli_20250721052808.0.0_amd64.deb
$ sudo dpkg -i mcli_20250721052808.0.0_amd64.deb

ひとまずインストールまではできました。

Grafana Mimirをインストールする

では、Grafana Mimirをインストールしましょう。

Grafana Mimirのインストール方法についてですが、ドキュメントを見てもHelmなどしか見当たりません。

Set up Mimir | Grafana Mimir documentation

ダウンロードページを見に行くと、GitHubリポジトリーのReleasesページへリンクされています。

Grafana get started | Cloud, Self-managed, Enterprise

ここからバイナリーをダウンロードするのがよさそうですね…。

https://github.com/grafana/mimir/releases/tag/mimir-2.16.1

今回の用途で使えそうなバイナリーは、実行可能バイナリーとOSパッケージの2種類があります。

実行可能バイナリー。

$ curl -LO https://github.com/grafana/mimir/releases/download/mimir-2.16.1/mimir-linux-amd64
$ chmod +x mimir-linux-amd64
$ ./mimir-linux-amd64 --version
Mimir, version 2.16.1 (branch: release-2.16, revision: 876d470fb1)
  go version:       go1.23.7
  platform:         linux/amd64

OSパッケージ。

$ curl -LO https://github.com/grafana/mimir/releases/download/mimir-2.16.1/mimir-2.16.1_amd64.deb

今回はOSパッケージを使うことにします。

$ sudo dpkg -i mimir-2.16.1_amd64.deb

含まれているファイルはこちらでした。

$ dpkg -L mimir
/etc
/etc/default
/etc/default/mimir
/etc/logrotate.d
/etc/logrotate.d/mimir
/etc/mimir
/etc/mimir/config.example.yaml
/etc/mimir/config.yml
/etc/mimir/runtime_config.yml
/lib
diverted by base-files to: /lib.usr-is-merged
/lib/systemd
/lib/systemd/system
/lib/systemd/system/mimir.service
/usr
/usr/local
/usr/local/bin
/usr/local/bin/mimir

インストールすると、systemdユニットとしての設定と起動まで完了しています。

$ sudo systemctl status mimir
● mimir.service - Horizontally scalable, highly available, multi-tenant, long term Prometheus.
     Loaded: loaded (/usr/lib/systemd/system/mimir.service; enabled; preset: enabled)
     Active: active (running) since Sun 2025-07-27 06:32:01 UTC; 48s ago
       Docs: https://grafana.com/oss/mimir/
   Main PID: 5860 (mimir)
      Tasks: 9 (limit: 9478)
     Memory: 28.5M (peak: 28.9M)
        CPU: 446ms
     CGroup: /system.slice/mimir.service
             └─5860 /usr/local/bin/mimir --config.file=/etc/mimir/config.yml --runtime-config.file=/etc/mimir/runtime_config.yml --log.level info

Jul 27 06:32:00 server mimir[5860]: ts=2025-07-27T06:32:00.143055152Z caller=compactor.go:513 level=info component=compactor msg="compactor is ACTIVE in the ring"
Jul 27 06:32:00 server mimir[5860]: ts=2025-07-27T06:32:00.143159955Z caller=compactor.go:637 level=info component=compactor msg="discovering users from bucket"
Jul 27 06:32:00 server mimir[5860]: ts=2025-07-27T06:32:00.143189801Z caller=compactor.go:647 level=info component=compactor msg="discovered users from bucket" users=0
Jul 27 06:32:00 server mimir[5860]: ts=2025-07-27T06:32:00.143254177Z caller=blocks_cleaner.go:227 level=info component=cleaner run_id=1753597920 task=clean_up_users msg="star>
Jul 27 06:32:00 server mimir[5860]: ts=2025-07-27T06:32:00.143269097Z caller=blocks_cleaner.go:233 level=info component=cleaner run_id=1753597920 task=clean_up_users msg="succ>
Jul 27 06:32:01 server mimir[5860]: ts=2025-07-27T06:32:01.144002503Z caller=gateway.go:287 level=info msg="waiting until store-gateway is ACTIVE in the ring"
Jul 27 06:32:01 server systemd[1]: Started mimir.service - Horizontally scalable, highly available, multi-tenant, long term Prometheus..
Jul 27 06:32:01 server mimir[5860]: ts=2025-07-27T06:32:01.333185969Z caller=gateway.go:291 level=info msg="store-gateway is ACTIVE in the ring"
Jul 27 06:32:01 server mimir[5860]: ts=2025-07-27T06:32:01.333377022Z caller=mimir.go:941 level=info msg="Application started"
Jul 27 06:32:30 server mimir[5860]: ts=2025-07-27T06:32:30.134094169Z caller=memberlist_client.go:552 level=info msg="initiating cleanup of obsolete entries"

Grafana MimirをPrometheusのリモートストレージとして設定する

それでは、インストールしたGrafana MimirをPrometheusのリモートストレージとして設定していきましょう。

設定に関するページはこちら。

About Grafana Mimir configurations | Grafana Mimir documentation

リファレンス。

Grafana Mimir configuration parameters | Grafana Mimir documentation

ランタイム設定。

About Grafana Mimir runtime configuration | Grafana Mimir documentation

Grafana Mimirには2種類の設定ファイルがあり、起動時に1度だけ読み込まれるもの、実行中に動的に再読み込みされる
ランタイム設定というものがあるようです。

systemdのステータスを見ると、/etc/mimir/config.yml/etc/mimir/runtime_config.ymlという2つのファイルで動作している
ようですね。後者がランタイム設定でしょう。

     CGroup: /system.slice/mimir.service
             └─5860 /usr/local/bin/mimir --config.file=/etc/mimir/config.yml --runtime-config.file=/etc/mimir/runtime_config.yml --log.level info

今回はこちらを見て、MinIOのオブジェクトストレージを設定します。

Configure Grafana Mimir object storage backend | Grafana Mimir documentation

まずはMinIOのバケットを作成しましょう。

$ mcli alias set myminio http://localhost:9000 minioadmin minioadmin
$ mcli mb myminio/mimir-blocks
$ mcli mb myminio/mimir-ruler

Grafana Mimirの設定ファイルは、デフォルトではなにも書かれていなかったので

/etc/mimir/config.yml

---
# This file should contain Mimir's configuration.
# https://grafana.com/docs/mimir/latest/references/configuration-parameters/

このように変更。

/etc/mimir/config.yml

---
# This file should contain Mimir's configuration.
# https://grafana.com/docs/mimir/latest/references/configuration-parameters/
common:
  storage:
    backend: s3
    s3:
      endpoint: localhost:9000
      insecure: true
      access_key_id: "minioadmin"
      secret_access_key: "minioadmin"

ingester:
  ring:
    replication_factor: 1

blocks_storage:
  s3:
    bucket_name: mimir-blocks

ruler_storage:
  s3:
    bucket_name: mimir-ruler

ingesterの設定は、レプリカ数を減らしています。デフォルトでは3になっていて、今回はクラスターを構成しないのでingesterの
数が足りず書き込みができなくなります。

Prometheusで使った時にはこんなエラーを見ることになる、という感じですね。

time=2025-07-27T07:20:15.849Z level=WARN source=queue_manager.go:2027 msg="Failed to send batch, retrying" component=remote remote_name=5c082c url=http://localhost:8080/api/v1/push err="server returned HTTP status 500 Internal Server Error: send data to ingesters: at least 2 live replicas required, could only find 1\n"

Grafana Mimirを再起動。

$ sudo systemctl restart mimir

起動に成功すれば、設定は完了しています。

MinIOへの接続情報やバケットの情報が誤っていると起動に失敗します。

次は、Prometheusの設定を変更します。

デフォルトはこのような設定ファイルでした。

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: ["localhost:9090"]
       # The label name is added as a label `label_name=<label_value>` to any timeseries scraped from this config.
        labels:
          app: "prometheus"

これを以下のように変更。

prometheus.yml

global:
  scrape_interval: 5s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 5s # Evaluate rules every 15 seconds. The default is every 1 minute.

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]
        labels:
          app: "prometheus"
  - job_name: mimir
    static_configs:
      - targets: ["localhost:8080"]
        labels:
          app: "mimir"

remote_write:
  - url: http://localhost:8080/api/v1/push
    # Add X-Scope-OrgID header so that Mimir knows what tenant the remote write data should be stored in.
    # In this case, our tenant is "demo"
    headers:
      X-Scope-OrgID: mymimir

設定はこちらを参考にしています。

Configuration / Configuration file / <remote_write>

https://github.com/grafana/mimir/blob/mimir-2.16.1/docs/sources/mimir/get-started/play-with-grafana-mimir/config/prometheus.yaml

そういえば、Grafana Mimirのポートは8080のようです。

「Remote write」のパスについてはこちら。

Grafana Mimir HTTP API | Grafana Mimir documentation

こちらはテナントのIDを指定しているものです。

    headers:
      X-Scope-OrgID: mymimir

ひとまず、今回のテナントIDは「mymimir」ですが。

Grafana Mimir authentication and authorization | Grafana Mimir documentation

あとはGrafanaでアクセスしてみます。

データソースでPrometheusを選択。Prometheusと互換性があるので、Grafana MimirではなくPrometheusでOKです。

Grafana Mimirへの接続設定を行います。パスは/prometheusですね。

これは<prometheus-http-prefix>のデフォルト値が/prometheusだからです。

Grafana Mimir HTTP API | Grafana Mimir documentation

Grafana Mimir configuration parameters | Grafana Mimir documentation

テナントIDの指定も必要です。これがないと認証エラーになります。

これで、Prometheusでスクレイピングしたメトリクスが認識できるようになります。

Grafana Mimirのメトリクス。

Prometheusのメトリクス。

オマケ

今回、テナントIDを指定しましたがmultitenancy_enabledfalseにすることでマルチテナントを無効にできるようです。

Grafana Mimir configuration parameters | Grafana Mimir documentation

このあたりはいずれ確認してみましょう。

おわりに

Grafana Mimir+MinIOをUbuntu Linux 24.04 LTSにインストールして、Prometheusのリモートストレージとして使ってみました。

Grafana Mimir自体が複雑で概要を把握するのに時間がかかったのと、Prometheusのリモート書き込み先を使ったことがなかったので
このあたりでかなりハマりました。

ドキュメントをちゃんと見ていると全体像がなんとなくわかってきたので、だいぶ進めやすくはなりましたが…。

頑張って押さえていこうと思います。