Nya Candy

Nya Candy

aka. Nya Crypto FSD(Fish Stack Developer) working at @rss3 with friends, Cɾყρƚσ Adventurer. candinya.eth
misskey

私は独自のログ収集技術を持っています

cover

本文同步发布于 糖菓・部落

サーバーが増えるにつれて、各サーバー上で実行されるコンテナがますます混雑し、ログを収集することが猫の悩みの種になっています。普段は管理を便利にするために 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 の時間制御と組み合わせて使用することで、特定のコンテナの実行ログを迅速にクエリできます。もはやログが散在して多すぎるという悩みはありません!

筛选出来的日志

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。