本文同步发布于 糖菓・部落
サーバーが増えるにつれて、各サーバー上で実行されるコンテナがますます混雑し、ログを収集することが猫の悩みの種になっています。普段は管理を便利にするために docker を使用しており、k8s が理解できないためにクラスターを構築していないので、ログの収集は少し気まずいことになっています。docker や docker-compose に付属の log コマンドを使用してクエリを実行する場合、元のサーバーに接続し、サービスディレクトリに入る必要があり、長いコマンドを入力し、成功した後には大量の出力の中から必要な部分を探さなければならず、うっかり見つけた内容が新しいログに上書きされてしまうこともあり、実に優雅ではありません。そこで、実行ログを迅速かつ便利に収集し、必要に応じてクエリや整理を行うことができるソリューションを探し始めました。ちょうど最近、Grafana と Loki を研究していて、公式が開発した docker ログプラグインを見つけたので、使用した設定ファイルやコマンドを記録するためにもう一つの記事を書くことにしました。必要な友人たちが同様の問題を迅速に解決できるようにするためです。
使用時は、使用状況に応じて関連する設定ファイルを調整し、サンプル設定による干渉を避けてください。
Grafana + Loki の準備#
統合起動ファイルの準備#
Loki は実際にログを収集するサーバーと理解でき、Grafana はサーバーからデータをクエリするフロントエンドと理解できます。両者は独立しているが相互に関連しており、同じローカルネットワーク環境にデプロイすることも、分けてパブリックネットワークを介して接続することもできます。ここでは純粋にログ収集の特化したシナリオを使用しているため、直接docker-compose
で関連付けて起動しました。
また、このサーバーはログ収集専用であり、他のサービスと 443 ポートを共有する必要がないため、Caddy の設定も一緒に書きました。
docker-compose.yml
ファイルは以下の通りです:
version: '3.4'
services:
loki:
image: grafana/loki
container_name: grafana-loki
command: -config.file=/etc/loki/local-config.yml
networks:
- internal_network
volumes:
- ./config/loki.yml:/etc/loki/local-config.yml
- ./data/loki:/tmp/loki
grafana:
depends_on:
- grafana-db
- loki
image: grafana/grafana
container_name: grafana
networks:
- internal_network
- external_network
volumes:
- ./config/grafana.ini:/etc/grafana/grafana.ini
restart: unless-stopped
grafana-db:
image: postgres:15-alpine
restart: always
container_name: grafana-db
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
POSTGRES_USER: grafana
POSTGRES_PASSWORD: password
POSTGRES_DB: grafana
POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
networks:
- internal_network
caddy:
image: caddy
restart: always
ports:
- "443:443"
networks:
- internal_network
- external_network
volumes:
- ./config/Caddyfile:/etc/caddy/Caddyfile
- ./ssl:/ssl:ro
- ./data/caddy/data:/data
- ./data/caddy/config:/config
networks:
internal_network:
internal: true
external_network:
公開される唯一のポートは Caddy の 443 ポートであり、CDN で強制 HTTPS を有効にして、80 ポートへのリクエストが発生しないようにします。
各サービスの設定の準備#
設定ファイルを config ディレクトリに統一して配置し、管理を容易にします。
Grafana#
grafana の設定ファイルgrafana.ini
は以下の通りです:
[database]
type = postgres
host = grafana-db:5432
name = grafana
user = grafana
password = password
Loki#
loki の設定ファイルloki.yml
は以下の通りです:
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9095
common:
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
analytics:
reporting_enabled: false
# 参见 https://grafana.com/docs/loki/latest/configuration/
# 可以开启 S3 存储,暂时没必要就不管了
alertmanager_url
が何に設定されるべきか分からず、ログ収集サービスとしてアラートの必要性を考慮していないため、サンプル値をそのまま保持しています。
auth_enabled
という設定項目に注意が必要です。このフィールドの意味は、異なる組織が同じ loki サービスを共有するために異なる領域リクエストヘッダーを設定することです。これを有効にすると、HTTP 呼び出しでX-Scope-OrgID
を使用してリクエストを発信する組織を区別する必要があります。データを提出する際やデータを取得する際には、これを持参する必要があります。しかし、ここでは単独使用であり、データ共有に関する問題はないため、このオプションは無効にしました。
loki 自体は HTTP 認証検証を持っていないため、認証リクエストヘッダーをフロントエンドのリバースプロキシプログラムの設定に記載することをお勧めします。例えば、ここでは Caddy の設定ファイルに配置し、パブリックトラフィックからのリクエストに対してのみ認証検証を要求し、Grafana が内部ネットワーク接続を使用する場合は検証を必要としません。
Caddy#
ここでは CDN プロバイダーのソースサーバー証明書を使用しており、Caddy に申請させる必要がないため、設定ファイルは以下の通りです:
example.com {
tls /ssl/example.com/cert.pem /ssl/example.com/key.pem
reverse_proxy grafana:3000
}
loki.example.com {
tls /ssl/example.com/cert.pem /ssl/example.com/key.pem
reverse_proxy loki:3100
basicauth * {
user $2a$14$QZIF1JLM9lFPjAl6PQzBDeANmB4Ssufc0qUnP9nI7QYnv.QevEzyi
}
}
loki-grpc.example.com {
tls /ssl/example.com/cert.pem /ssl/example.com/key.pem
reverse_proxy loki:9095
basicauth * {
user $2a$14$QZIF1JLM9lFPjAl6PQzBDeANmB4Ssufc0qUnP9nI7QYnv.QevEzyi
}
}
認証部分には BasicAuth を使用しており、ユーザー名とパスワードの方式です。パスワードは明文で保存されず、caddy のhash-password
機能によって事前に計算され、安全性を高めるようにしています。
/srv # caddy hash-password
Enter password:
Confirm password:
$2a$14$QZIF1JLM9lFPjAl6PQzBDeANmB4Ssufc0qUnP9nI7QYnv.QevEzyi
/srv #
設定が完了したら、対応する SSL 証明書を指定された場所に配置し、証明書ファイルがないためのエラーを回避します。
すべての設定が完了したら、docker-compose up -d
コマンドを使用して起動できるはずです。
Loki データディレクトリの権限管理#
コンテナ内の Loki は root ユーザーとして起動されないため、Docker が設定した root 権限により Loki のアクセスが拒否されます。以下のようなコマンドを手動で実行して、Loki のデータディレクトリの権限をコンテナが使用できるように開放する必要があります:
chown -R 10001:10001 ./data/loki/
変更が完了したら、Loki コンテナを再起動してください。
Grafana のデータソースとして Loki を関連付ける#
デプロイされた Grafana に入り、デフォルトのユーザー名とパスワードadmin
でログインし、パスワードを変更した後、データソースを追加し始めることができます。
上記の docker-compose 設定に基づいている場合、Loki を選択し、HTTP の URL にhttp://loki:3100
を入力するだけで、保存してテストできます。この時点で Loki にはログがないため、ラベルが見つからないというエラーメッセージが表示されますが、心配しないでください。後でログが出現すれば大丈夫です。
サーバーの準備#
docker 環境を使用しているため、具体的なコマンドはここでは繰り返しません。直接 loki ログプラグインのインストールから始めます。
ここでは、Docker Driver Clientが提供するチュートリアルを参考にしています。関連する内容は更新される可能性があるため注意してください。
loki-docker-driver プラグインのインストール#
データを loki に送信するためには、Docker のログを詳細なタグ情報を持つデータに変換し、Loki 互換のインターフェースを使用して上記のサーバーに送信するためのプラグインが必要です。このコマンドを使用してこのプラグインをインストールできます:
docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions
インストールが完了したら、docker plugin ls
を使用して Docker にインストールされたプラグインを確認できます。
もし後でアップグレードが必要な場合は、元のリンクに記載されているコマンドを参考にしてアップグレードできます:
docker plugin disable loki --force
docker plugin upgrade loki grafana/loki-docker-driver:latest --grant-all-permissions
docker plugin enable loki
systemctl restart docker
その後、プラグインの具体的な設定を行うことができます。私はホストマシン上のすべての docker ログを収集する必要があり、異なる組織を区別する必要がないため、/etc/docker/daemon.json
ファイルを設定し、以下の内容を書き込みます:
{
"log-driver": "loki",
"log-opts": {
"loki-url": "https://user:[email protected]/loki/api/v1/push"
}
}
設定が完了したら、docker プロセスを再起動して変更を有効にします。
この時点では、すべてのコンテナにリアルタイムで適用されるわけではなく、すでに作成されたコンテナのログシステムは固定されているため、新しく作成されたコンテナにのみ有効です。ログ収集が非常に急務である場合は、docker-compose up -d --force-recreate
を使用してすべてのコンテナを再構築することができます。
Grafana でのクエリ#
設定が完了し、新しく作成されたコンテナが稼働してログを生成し始めると、Grafana でクエリできるようになるはずです。単独使用であり、詳細な可視化の必要がないため、Dashboard を設定せず、直接 Explore 機能に入ってインタラクティブなクエリを行います。
ログが出現したら、ラベルを使用してソースをフィルタリングできます。このプラグインは、host
compose_project
compose_service
container_name
source
filename
の 6 つのフィルタリングラベルを提供します。その中で:
host
はログを発信したホストマシンのホスト名を指します。compose_project
compose_service
またはcontainer_name
はコンテナを特定するために使用できます。source
はログのソースが一般的な出力stdout
かエラーログstderr
かを示します。filename
はログの元のファイルを指します(通常は重要ではありません)。
これらのラベルを Grafana の時間制御と組み合わせて使用することで、特定のコンテナの実行ログを迅速にクエリできます。もはやログが散在して多すぎるという悩みはありません!