なぜLogstashやFluentdの使用をやめるべきなのか?
マイクロサービスを運用しているなら、Logstashが数行のログを転送するためだけに1GBもの RAMを消費することに頭を悩ませたことがあるはずです。以前はELK(Elasticsearch – Logstash – Kibana)スタックが標準でした。しかし、JVM上で動作するLogstashは非常に重いです。Fluentdはそれよりはマシですが、Rubyベースであるため、スループットが急増した際にボトルネックになりやすいという欠点があります。
私自身、以前苦い経験をしました。4GB RAMのVPSで4つのマイクロサービスがスムーズに動いていたのですが、Logstashを導入した途端に「フリーズ」してしまったのです。ログを送信するためにインストールしただけで、RAM使用率が即座に90%に跳ね上がり、システムがラグり始めました。そこで出会ったのが Vector でした。
VectorはRustで書かれており、毎秒数万件のイベントを処理できる能力を持ちながら、RAM消費量はわずか20〜30MB程度です。これはLogstashの10〜20分の1以下です。Docker Compose v2でVectorに切り替えて以来、ログエージェントのためだけにRAMをアップグレードする必要がなくなり、VPSの維持コストを大幅に削減できました。
Dockerログを「集約」するためのVectorのデプロイ
実際の運用モデルをセットアップしてみましょう. Vectorをコンテナとして実行し、Docker Socketからログを「リッスン」してコンソールに出力します。このプロセスはすべて、最新の標準であるDocker Compose v2に基づいています。
ステップ1:設定ファイルの初期化
Vectorはすべて vector.yaml ファイルを通じて制御されます。以下のコマンドでプロジェクトディレクトリと設定ファイルを作成しましょう。
mkdir vector-docker-logs && cd vector-docker-logs
touch vector.yaml
以下は、Vectorがデータの収集を開始するための最小限の設定です。
# vector.yaml
sources:
docker_logs:
type: "docker_logs"
sinks:
out:
type: "console"
inputs:
- "docker_logs"
encoding:
codec: "json"
ステップ2:Docker Composeの設定
docker-compose.yml ファイルでVectorと、サンプルログを生成するためのNginxアプリケーションを定義します。セキュリティとサイズを最適化するために、distroless イメージを使用することに注目してください。
# docker-compose.yml
services:
vector:
image: timberio/vector:0.34.1-distroless-static
container_name: vector
volumes:
- ./vector.yaml:/etc/vector/vector.yaml:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "8686:8686"
app-nginx:
image: nginx:latest
container_name: demo-nginx
ports:
- "8080:80"
実体験からのアドバイス: /var/run/docker.sock のマウントを忘れないでください。これがないと、VectorはDockerデーモンと通信できず、他のコンテナからデータを取得できないため、完全に「盲目」状態になってしまいます。
VRLによるプロフェッショナルなログ処理
Dockerからの生ログには、不要な情報が多く含まれていることがよくあります。Vectorの真の力は VRL (Vector Remap Language) にあり、これを使ってリアルタイムでデータのフィルタリングや変換を行うことができます。
データのフィルタリングと再フォーマット
例えば、コンテナ名に「demo」という文字が含まれるログだけを保持し、環境ラベルを追加したいとします。vector.yaml を以下のように更新します。
sources:
docker_logs:
type: "docker_logs"
transforms:
# demo-nginxコンテナからのログのみ取得
filter_nginx:
type: "filter"
inputs:
- "docker_logs"
condition: |
includes(string!(.container_name), "demo-nginx")
# 識別情報を追加
parse_logs:
type: "remap"
inputs:
- "filter_nginx"
source: |
.env = "production"
.processed_at = now()
.message = upcase(string!(.message))
sinks:
stdout:
type: "console"
inputs:
- "parse_logs"
encoding:
codec: "json"
VRLは直接コンパイルされるため、非常に高速です。メッセージを大文字に変換(upcase)したり、タイムスタンプを追加したりする処理はわずか数マイクロ秒で完了し、パイプラインに遅延が生じることはありません。
LokiまたはElasticsearchへのログ転送
ログがクリーンになったら、Grafana Lokiのような集中管理システムに送信できます。
sinks:
loki_sink:
type: "loki"
inputs:
- "parse_logs"
endpoint: "http://loki:3100"
labels:
container_name: "{{ container_name }}"
service: "my-app"
実際のパフォーマンスの確認
docker compose up -d コマンドでシステムを起動します。その後、localhost:8080 にアクセスしてNginxのトラフィックを生成してみてください。
Vectorがどのように処理しているかを確認するには、docker logs -f vector コマンドを使用します。設定した env や processed_at フィールドが含まれたJSON形式のログが即座に表示されるはずです。
大きなメリットは、Vectorの内部ダッシュボードです。設定ファイルに以下のコードを追加してください。
api:
enabled: true
address: "0.0.0.0:8686"
vector top を実行すると、スループットのグラフが表示されます。毎秒5,000〜10,000行のログを処理していても、一般的なCPUであればVectorのCPU使用率は通常5%未満に収まります。
最後に
Vectorへの移行は、Dockerインフラを最適化するための最良の決断の一つです。軽量であるだけでなく、VRL言語のおかげで非常に柔軟です。LogstashのためのJava/JVMのメンテナンスに疲れているなら、今すぐVectorを試してみてください。皆さんの導入が成功することを願っています。もしVRLの構文エラーなどで困ったら、コメント欄で教えてください。サポートします!

