---
title: "Grafana Lokiとは？仕組み・Alloyでの導入手順とLogQLの書き方【v3.7】"
url: "https://www.issoh.co.jp/tech/details/9570/"
published: 2025-10-29
updated: 2026-09-28
categories: ["監視・オブザーバビリティ"]
publisher: "株式会社一創"
---

# Grafana Lokiとは？仕組み・Alloyでの導入手順とLogQLの書き方【v3.7】

Grafana Lokiは、Grafana Labsが開発するログ集約基盤です。ログ本文には索引を作らず、`service_name` や `env` といったラベルだけを索引するので、Elasticsearchより保存コストを抑えやすくなります。2026年9月28日時点の最新安定版は、9月17日公開のv3.7.8です。

この記事では、Loki 3.7.8・Grafana Alloy 1.20.0・logcli 3.7.8を実際に動かして確かめた挙動をもとに、仕組み、Prometheusとの関係、docker composeでの導入、LogQLの書き方、ラベルと保持期間の設計を順に説明します。PromtailはすでにEOL（2026年3月2日）なので、古い手順記事をそのまま写すと、保守されない収集エージェントで構築することになります。

## まとめ：Grafana Lokiの要点と2026年時点の構成

- **仕組み**：ラベルだけを索引し、ログ本文は圧縮したチャンクとしてオブジェクトストレージに置きます。検索はラベルで対象を絞ってから本文を走査します。
- **現行版**：v3.7.8（2026-09-17）。ライセンスはAGPL-3.0で、クライアント類の一部はApache-2.0です。
- **収集**：PromtailはEOLになりました。新規構築はGrafana Alloyを使い、既存のPromtail設定は `alloy convert` で変換できます。
- **検索**：LogQLで `{ラベル} |= "文字列" | json` と絞り込み、`count_over_time` で件数を集計でき、レイテンシは `unwrap` と `quantile_over_time` などで集計できます。
- **設計で詰まる点**：ラベル数の上限は既定で1ストリーム15個です。trace IDのように値が増え続ける属性はラベルにせず、structured metadataに入れます。保持期間を有効にするときは `delete_request_store` も設定しないと起動しません。

## Grafana Lokiの仕組みとPrometheus・Elasticsearchとの違い

### ラベルだけを索引しチャンクをオブジェクトストレージに置く構造

Lokiは、同じラベルの組み合わせを持つログを1本の「ストリーム」として扱います。索引（TSDB形式）に入るのはラベルとチャンクの位置だけで、ログ本文は圧縮したチャンクとしてS3・GCS・Azure Blobなどのオブジェクトストレージに書き出されます。公式ドキュメントは、索引ストアの推奨をTSDBに一本化し、スキーマもv13を推奨しています。

書き込みは、Distributorで受信し、Ingesterでチャンクにまとめてからストレージへ書き出す流れです。検索はQuerierが担い、索引でストリームを特定してから該当チャンクだけを展開します。本文を索引しない分だけ書き込みと保存が軽くなりますが、そのぶん広い期間を全文で探すクエリは遅くなります。

### Prometheus・Grafanaとの役割分担

Lokiはリポジトリの説明文でも「Like Prometheus, but for logs.」と名乗っているとおり、Prometheusの設計を下敷きにしています。ラベルで系列を識別する考え方と、`{job="api"}` のようなセレクタの書き方が共通です。PrometheusとLokiに同じラベル（`namespace`・`pod` など）を付けておくと、Grafana上でメトリクスのグラフからその時間帯のログへそのまま移れます。

役割を分けると、Prometheusは数値の時系列（CPU使用率やリクエスト数）、Lokiはログ行、Grafanaは両者を表示するUIです。Lokiにも独自のUIはなく、検索や可視化はGrafanaのExploreかダッシュボード、またはCLIのlogcliで行います。Prometheus側の構築は[Prometheusで監視を構築する手順｜exporter設計・PromQL・保持期間の見積り](/tech/details/17516/)で扱っています。トレースを加えて3つのシグナルをつなぐなら、[Grafana Tempoとは？分散トレーシングの仕組み・TraceQL・導入判断を実装者向けに解説](/tech/details/15584/)が対になる記事です。

### Elasticsearch（ELK）との違いと選び分け

| 観点    | Grafana Loki  | Elasticsearch（ELK）           |
| ----- | ------------- | ---------------------------- |
| 索引の対象 | ラベルのみ         | 本文など、マッピングで索引対象にしたフィールド      |
| 保存先   | オブジェクトストレージ   | ノードのディスク（シャード）               |
| 得意な検索 | サービス・期間を絞った検索 | 任意語の全文検索・集計                  |
| 検索言語  | LogQL         | Query DSL・ES\|QL             |
| UI    | Grafana       | Kibana                       |
| ライセンス | AGPL-3.0      | 配布版：ELv2／無料部分のソース：3ライセンスから選択 |

障害時に「どのサービスの、どの時間帯か」が分かっている調査なら、Lokiはラベルと時間範囲で読むチャンクを絞れるので、本文の索引を持たない分の遅さが問題になりにくい使い方です。逆に、全サービスを横断して任意の語で頻繁に検索する運用や、フィールド単位の集計が中心の運用ではElasticsearchが向きます。ELKの収集経路とインデックス設計は[Elasticsearchのログ収集｜ELKスタックの収集経路とインデックス分割・保持期間の設計](/tech/details/17017/)で扱っています。

## Loki 3.7系の現行版とライセンス・Promtail終了の影響

GitHub Releasesで「Latest」になっているのはv3.7.8（2026-09-17）です。同じ日にv3.6.17も出ているので、3.6系にも修正が入っている状態です。

ライセンスは2021年4月20日のコミットでApache-2.0からAGPL-3.0へ変わり、v2.3.0（2021年8月）以降のリリースはAGPLです。改変せずに社内で使う分には、ライセンス費用もソース提供の義務もありません。改変したLokiをネットワーク経由で利用させる場合は、AGPL第13条により、その利用者へ対応するソースを取得する機会を提供する必要があります。`clients/` 以下など一部のディレクトリはApache-2.0のままです。

運用面で影響が大きいのは次の3点です。

- **Promtail**：2026年3月2日にEOLとなり、サポートも更新も終了しました。後継はGrafana Alloyです（AWS Lambda向けのlambda-promtailは対象外）。
- **Helmチャート**：OSS版のチャートは `grafana-community/helm-charts` へ移り、現行は18.13.7（appVersion 3.7.8）です。旧リポジトリの `grafana/loki` チャートは7.3.0で止まっており、`loki-stack` と `promtail` のチャートには `deprecated: true` が付いています。
- **Simple Scalable（SSD）モード**：非推奨化が進んでおり、Loki 4.0で削除されます。これから組む環境では選ばないのが無難です（後述）。

Grafana本体の版の追い方は[Grafana 12とは？最新版13との違い・v11からの変更点とバージョン確認方法](/tech/details/8395/)にまとめています。

## docker composeでLoki・Alloy・Grafanaを動かす手順

手元で試すなら、Loki・Alloy・Grafanaの3コンテナ構成が最短です。AlloyがDockerソケット経由で各コンテナの標準出力を読み、Lokiへ送ります。以下の設定ファイルはすべて同じディレクトリに置きます。

### loki.yaml：TSDB・schema v13・保持期間の設定

公式イメージの既定設定に、保持期間（31日）を足したものです。Loki 3.7.8の `-verify-config` で検証しました。

```
auth_enabled: false
server:
  http_listen_port: 3100
common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory
schema_config:
  configs:
    - from: 2026-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h
compactor:
  working_directory: /loki/compactor
  retention_enabled: true
  delete_request_store: filesystem
limits_config:
  retention_period: 744h
```

`auth_enabled: false` はテナント分離を切る設定で、手元の検証用です。本番では認証用リバースプロキシを前段に置きます。マルチテナントにするなら `true` にし、認証済み利用者に応じてプロキシ側で `X-Scope-OrgID` ヘッダーにテナントIDを付けます。

### config.alloy：コンテナログを集めてLokiへ送る設定

```
discovery.docker "containers" {
  host = "unix:///var/run/docker.sock"
}

discovery.relabel "containers" {
  targets = []

  rule {
    source_labels = ["__meta_docker_container_name"]
    regex         = "/(.*)"
    target_label  = "container"
  }
}

loki.source.docker "containers" {
  host          = "unix:///var/run/docker.sock"
  targets       = discovery.docker.containers.targets
  relabel_rules = discovery.relabel.containers.rules
  labels        = {env = "dev"}
  forward_to    = [loki.write.local.receiver]
}

loki.write "local" {
  endpoint {
    url = "http://loki:3100/loki/api/v1/push"
  }
}
```

Alloy 1.20.0で4つのコンポーネントの設定評価を確認しました。ただし検証環境にはDockerソケットがなく、コンテナログの収集・転送は未確認です。コンテナ名の先頭に付く `/` を `discovery.relabel` で外し、`container` ラベルにしています。

### compose.yamlとGrafanaのデータソース登録

```
services:
  loki:
    image: grafana/loki:3.7.8
    ports: ["3100:3100"]
    volumes:
      - ./loki.yaml:/etc/loki/local-config.yaml:ro
      - loki-data:/loki
  alloy:
    image: grafana/alloy:v1.20.0
    command: run /etc/alloy/config.alloy --storage.path=/var/lib/alloy/data --server.http.listen-addr=0.0.0.0:12345
    ports: ["12345:12345"]
    volumes:
      - ./config.alloy:/etc/alloy/config.alloy:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
  grafana:
    image: grafana/grafana:13.2.2
    ports: ["3000:3000"]
    volumes:
      - ./datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:ro
volumes:
  loki-data:
```

次の内容を `datasources.yaml` として保存します。

```
apiVersion: 1
datasources:
  - name: Loki
    type: loki
    access: proxy
    url: http://loki:3100
    isDefault: true
```

Lokiイメージは `/etc/loki/local-config.yaml` を読む設定で起動し、UID 10001で動きます。名前付きボリュームを `/loki` にマウントすれば、書き込み権限でつまずくことはありません。`docker compose up -d` のあと `http://localhost:3100/ready` が `ready` を返せば、Lokiは起動済みです。GrafanaはURL `http://localhost:3000` で開き（初期ユーザーはadmin／admin）、Exploreで `{env="dev"}` を実行するとコンテナのログが並びます。

データソースを画面から登録する場合は、Connections → Data sources → Add data source でLokiを選び、URLに `http://loki:3100` を入れて「Save & test」を押します。Kubernetesでは上記のHelmチャート（`grafana-community/loki`）を使い、Alloyは各ノードにDaemonSetとして置く構成が標準です。アプリからOTLPで送る経路は[Grafana OpenTelemetry連携の構成｜OTLP受信から3シグナル統合まで](/tech/details/16566/)で扱っています。

## PromtailからAlloyへの移行手順

既存のPromtail設定は、Alloyの `convert` サブコマンドで1回で変換できます。

```
alloy convert --source-format=promtail --output=config.alloy promtail.yaml
```

`/var/log/*.log` を読む最小構成のPromtail設定を変換すると、次のAlloy設定が出力されました（Alloy 1.20.0）。

```
loki.source.file "varlogs" {
	targets = [{
		__address__ = "localhost",
		__path__    = "/var/log/*.log",
		job         = "varlogs",
	}]
	forward_to = [loki.write.default.receiver]

	file_match {
		enabled = true
	}
	legacy_positions_file = "/tmp/positions.yaml"
}

loki.write "default" {
	endpoint {
		url = "http://localhost:3100/loki/api/v1/push"
	}
	external_labels = {}
}
```

見落とせないのは `legacy_positions_file` です。Alloy側にまだpositionsファイルが無く、この項目が指す場所にPromtailの旧positionsファイルがあれば、その読み取り位置を引き継ぎます。旧ファイルを消したり別ホストへ移したりすると引き継ぎは効かないので、切り替えはPromtailを止めた同じホストで行います。この変換結果でAlloyを起動し、ローカルのLokiに3行のログが届くことを確認しました。届いたストリームには、Promtail設定には書いていない `filename` ラベルが自動で付いていました。ファイル数が多いホストではストリームがファイル単位に割れるので、filenameラベルが不要なら、収集後に `loki.relabel` の `labeldrop` ルールで削除します。

## LogQLの書き方：ストリームセレクタからメトリクスクエリまで

LogQLは、`{}` で囲むストリームセレクタと、`|` でつなぐパイプラインの2部構成です。以下はLoki 3.7.8に、JSON形式のアクセスログ200行を `/loki/api/v1/push` で投入し、logcliで実行した結果にもとづいています。

### ストリームセレクタとラインフィルタ

```
{service_name="shop-api", env="prod"} |= "error" != "healthcheck"
```

`|=` は含む、`!=` は含まない、`|~` と `!~` は正規表現での一致と不一致です。セレクタには、空文字列に一致しない条件が最低1つ必要です。`{}` や `{env=~".*"}` だけのクエリは、Lokiが「queries require at least one regexp or equality matcher that does not have an empty-compatible value」と返して拒否します。ラベルを問わず広く見たいときは、どのストリームにも付く `service_name` を使い、`{service_name=~".+"}` と書きます（ラベルを付けずに送ったログにも、Lokiが `service_name` を自動で付けるため）。

### json・logfmtパーサとline\_formatでの整形

```
{service_name="shop-api"} | json | status >= 500 | line_format "{{.method}} {{.path}} {{.latency_ms}}ms"
```

`| json` がJSONのキーを一時的なラベルに展開するので、`status >= 500` のように数値で比較できます。実行すると、各行は `GET /api/orders 621ms` の形で表示されました。`line_format` が変えるのは表示だけで、保存されたログは変わりません。パーサはほかに `logfmt`・`pattern`・`regexp`・`unpack` があり、`key=value` 形式のログには `| logfmt` を使います。

### count\_over\_timeとunwrapによる件数・レイテンシの集計

```
sum by (path) (count_over_time({service_name="shop-api"} | json | status >= 500 [10m]))

quantile_over_time(0.95, {service_name="shop-api"} | json | unwrap latency_ms | __error__="" [10m]) by (path)
```

1本目はパス別の5xx件数、2本目はパス別のレイテンシの95パーセンタイルです。`unwrap` はログ中の数値を値として取り出す演算子で、これを使うとログだけでレイテンシの推移を描けます。どちらもGrafanaのアラートルールのクエリに使えます。1本目に閾値条件を組み合わせれば、Prometheusにメトリクスが無いサービスでも「10分間の5xx件数が閾値を超えたら通知」を組めます。

### structured metadata（trace\_id）の検索で0件になる書き方

trace IDのように値が増え続ける属性は、ラベルではなくstructured metadataとして送ります。v13スキーマとTSDBが前提で、OTLPでの取り込みにもこの機能が要ります。検索するときは、セレクタの外でラベルフィルタとして書きます。

```
{service_name="shop-api"} | trace_id="2d54078cc55f8a3c4e31d58977c26374"
```

このクエリは該当の1行を返しました。一方、`{trace_id="..."}` とセレクタの中に書くと、エラーは出ずに結果が0件になります。structured metadataは索引に入らないためで、「ログが届いていない」と誤解しやすい挙動です。

## ラベル設計とカーディナリティの上限

ラベルの値の組み合わせが増えるとストリームが増え、索引が膨らむ一方で、チャンクは小さいまま書き出されます。公式のベストプラクティスは、ラベルを地域・クラスタ・アプリ・名前空間・環境のような固定的な値に限り、値の種類は数十程度に抑えることです。trace ID・注文ID・タイムスタンプは、ラベルにしてはいけない例として挙げられています。

上限は設定で決まっています。ラベル名を16個付けたストリームをpushすると、Loki 3.7.8は「has 16 label names; limit 15」を返して400で拒否しました（`max_label_names_per_series` の既定値15）。ラベルを付けずに送ると、Lokiが `service_name="unknown_service"` を自動で付けます。Alloyのファイル収集では `job` の値が `service_name` に入りました。

ラベルにするか迷ったときの基準は1つです。「そのラベルでセレクタを書く頻度が高く、値の種類が数十以内」ならラベルにし、それ以外は本文かstructured metadataに残して、`| json` やラベルフィルタで絞ります。`level` をラベルにすると、その値の種類に応じてストリームが分かれます。公式資料の例では最大5ストリームとなり、中小量のログではチャンクが細分化されます。公式ドキュメントも、`{app="loki"} != "level=debug"` のように本文フィルタで絞る書き方のほうが軽いと説明しています。

## 保持期間（retention）とデプロイモードの選び方

### compactorで保持期間を有効にする設定

Lokiの保持期間はcompactorが処理し、既定では削除が無効です。つまり、何も設定しなければログは消えずに溜まり続けます。有効にするには、`compactor.retention_enabled: true` と `limits_config.retention_period` を設定します。

このとき `delete_request_store` を書き忘れると、Loki 3.7.8は「compactor.delete-request-store should be configured when retention is enabled」を出して起動しません。前述のloki.yamlは、この点も含めて検証済みの形です。保持期間はストリーム単位でも指定でき、`retention_stream` で監査ログだけ長く残すといった使い分けができます。

### monolithic・SSD・microservicesの選択

| モード                  | 目安の取り込み量     | 2026年時点の扱い   |
| -------------------- | ------------ | ------------ |
| monolithic           | 1日あたり約20GBまで | 検証・小規模向け     |
| Simple Scalable（SSD） | 1日あたりTB近くまで  | 非推奨化中・4.0で削除 |
| microservices        | それ以上         | 本番の推奨        |

monolithicは全コンポーネントを1プロセスで動かすモードで、上のdocker compose構成もこれにあたります。SSDはread・write・backendの3系統に分けるモードで、Loki 4.0では動かなくなります。公式ドキュメントには「SSDがHelmチャートの既定」とまだ書かれていますが、grafana-communityのチャート18.13.7の `values.yaml` では `deploymentMode: Monolithic` が既定です。本番向けに入れるときは、この値を明示して選びます。本番の新規構築はmicroservicesにします。取り込みが1日20GBに届かない規模なら、monolithicを複数台並べ、オブジェクトストレージを共有して冗長化する構成でも足ります。

自前運用を避けるならGrafana Cloudという選択肢もあります。Freeプランのログは月50GBまでの取り込みで、保持期間は14日です。

## Grafana Lokiを採用しない方がよい場面

実機で確かめた拒否条件から、Lokiが合わない運用がはっきりします。

- **過去ログの一括投入**：8日前のタイムスタンプのログは「timestamp too old」で拒否されました（既定では7日より古いログを受け付けない）。既に書き込みがあるストリームでは、既定設定の場合、最新行より1時間を超えて古いログが「entry too far behind」で拒否されます。数か月分の過去ログを移行するなら、制限の緩和と投入順の設計が前提です。
- **任意語の横断検索が主用途**：本文に索引が無いので、全サービス・長期間を対象にした語句検索はチャンクをすべて展開することになります。セキュリティ調査やCS対応で毎日そうした検索をするなら、全文索引のあるElasticsearchやSIEMのほうが向きます。
- **ログを改ざん防止の証跡として保管する**：Lokiの保持期間は、期限を過ぎたログを削除する仕組みです。改ざんを防いだまま一定期間残す保管は担わないので、法定保存が必要なログはオブジェクトストレージ側の保護機能か、専用の保管先へ別に送ります。

一方、Grafanaでメトリクスを見ていて、ログも同じ画面で時間帯とラベルを合わせて見たいチームには、Grafanaから検索できるLokiを推奨します。ログ基盤全体の選び方は[ログ集約とは？収集・転送・保存・可視化の仕組みとエージェント選定・導入判断を実装目線で解説【2026年版】](/tech/details/15711/)で比較しています。

## Grafana Lokiに関するよくある質問

### Grafana Lokiの読み方は？

「ロキ」と読みます。同じGrafana Labsの製品に、トレース基盤のTempoとメトリクス基盤のMimirがあり、Lokiはこれらと並ぶログ担当の製品です。

### Grafana Lokiは無料で使えますか？

OSS版はAGPL-3.0で、社内で使う分には無料です。改変版をネットワーク経由で利用させる場合、AGPL第13条に従い、その利用者へ対応するソースを無償で取得する機会を提供する必要があります。マネージド版のGrafana Cloudにも、ログの取り込みが月50GBまで・保持期間14日のFreeプランがあります。

### LokiとPrometheusの違いは何ですか？

Prometheusは数値の時系列（メトリクス）、Lokiはログ行を保存します。ラベルの考え方とセレクタの書き方は共通なので、同じラベルを付けておけばGrafana上でメトリクスから同じ時間帯のログへ移れます。

### LogQLとは何ですか？

Lokiの検索言語です。`{service_name="api"}` のようなストリームセレクタで対象を絞り、`|= "error"` や `| json` などのパイプラインで絞り込みや整形をします。`count_over_time` で件数を集計し、レイテンシは `unwrap` で数値を取り出して `quantile_over_time` などで集計します。

### Promtailはまだ使えますか？

2026年3月2日にEOLとなり、更新もサポートもありません。動作はしますが、脆弱性の修正も届かないので、`alloy convert --source-format=promtail` で設定を変換し、Grafana Alloyへ移行してください。

## 関連記事

- [Grafana OpenTelemetry連携の構成｜OTLP受信から3シグナル統合まで](/tech/details/16566/)
- [Grafana Tempoとは？分散トレーシングの仕組み・TraceQL・導入判断を実装者向けに解説](/tech/details/15584/)
- [Prometheusで監視を構築する手順｜exporter設計・PromQL・保持期間の見積り](/tech/details/17516/)
- [Elasticsearchのログ収集｜ELKスタックの収集経路とインデックス分割・保持期間の設計](/tech/details/17017/)
- [ログ集約とは？収集・転送・保存・可視化の仕組みとエージェント選定・導入判断を実装目線で解説【2026年版】](/tech/details/15711/)

---

出典: [Grafana Lokiとは？仕組み・Alloyでの導入手順とLogQLの書き方【v3.7】](<https://www.issoh.co.jp/tech/details/9570/>)（株式会社一創）
