この記事は 3-shake Advent Calendar 2023 22 日目の記事です!
はじめに
いきなりですがみなさんログコレクターツールは何を使っていますか?Fluentd, Logstash色々あると思います。私は最近Vectorというツールを知りました。本記事ではVectorについて他のログコレクターツールと比べた時の特色とコンセプト。実際に動かしてみたという内容でお送りしようと思います。
Vectorとは
- Datadogによって開発が進められているOSSのObservability Pipelines
- 効率的なメモリ/CPU消費と高いデータスループット
- ログ、メトリクス(ベータ)、トレース(coming soon)を1つのツールで管理できる
- エージェント、アグリゲーターとして動作
- オンザフライでのデータ変換
- Rust製
Vector Components
VectorにはSource, Transform, Sinksの3つのコンポーネントがあります。それぞれ
- Source:Vectorがどこからデータをプルするか、またプッシュされたデータをどの様に受信するかを定義します。例:syslog, stdin, docker_logs, s3など
- Transform:Vectorによって転送されるデータの変換を定義します。変換はfilterやreduceなどの基本的な操作が用意されていたり、あるいはVRL(Vector独自のDSL)やLuaなどのプログラミング言語を使うことで柔軟に対応することもできます。
- Sinks:データの送信先を定義します。データ転送の方法はダウンストリームによって異なります。
ログコレクタ実践
Manifests
vector-agent.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
- name: shared-data
mountPath: /var/log/nginx
- name: vector-agent
image: timberio/vector:0.34.0-debian
volumeMounts:
- name: vector-agent-config
mountPath: /etc/vector/
- name: shared-data
mountPath: /var/log/nginx
volumes:
- name: vector-agent-config
configMap:
name: vector-agent-config
- name: nginx-config
configMap:
name: nginx-config
- name: shared-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
vector-aggregator.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vector-aggregator
labels:
app: vector-aggregator
spec:
replicas: 1
selector:
matchLabels:
app: vector-aggregator
template:
metadata:
labels:
app: vector-aggregator
spec:
containers:
- name: vector-aggregator
image: timberio/vector:0.34.0-debian
volumeMounts:
- name: vector-aggregator-config
mountPath: /etc/vector/
volumes:
- name: vector-aggregator-config
configMap:
name: vector-aggregator-config
---
apiVersion: v1
kind: Service
metadata:
name: aggregator-service
spec:
selector:
app: vector-aggregator
ports:
- protocol: TCP
port: 6000
targetPort: 6000
nginx.confにはどのPodのログかわかりやすいように$hostnameを追加しておきます
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$hostname" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
vector-agent-config.yaml
sources:
nginx_logs:
type: file
include:
- "/var/log/nginx/*.log"
sinks:
vector:
type: vector
inputs:
- nginx_logs
address: "aggregator-service:6000"
vector-aggregator-config.yaml
sources:
vector:
type: vector
address: "0.0.0.0:6000"
sinks:
stdout:
type: console
inputs:
- vector
target: stdout
encoding:
codec: "text"
vectorのconfはシンプルなので、読めばなんとなく理解ができるレベルのものだと思います。
コンポーネントとそのタイプを指定、タイプ毎に必要なパラメーターを設定すればOKです。各コンポーネント間のデータの受け渡しはinputsに識別子を記述することでできます。
また、ここではyamlで書いていますが、その他にJSONやToml形式で記述することができます。
k create configmap vector-agent-config --from-file=vector.yaml=vector-agent-config.yaml
k create configmap vector-aggregator-config --from-file=vector.yaml=vector-aggregator-config.yaml
k create configmap nginx-config --from-file=nginx.conf
k apply -f vector-agent.yaml
k apply -f vector-aggregator.yaml
アグリゲーターのログを確認すると各Podのログが集約されて標準出力されていますね
k logs vector-aggregator-6489756b9c-wpbr2
10.244.0.5 - - [21/Dec/2023:16:59:48 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-z4s4x" "172.18.0.1"
10.244.0.5 - - [21/Dec/2023:16:59:49 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-kv4vq" "172.18.0.1"
10.244.0.5 - - [21/Dec/2023:16:59:50 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-z4s4x" "172.18.0.1"
10.244.0.5 - - [21/Dec/2023:16:59:51 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-8lnj5" "172.18.0.1"
10.244.0.5 - - [21/Dec/2023:16:59:52 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-kv4vq" "172.18.0.1"
10.244.0.5 - - [21/Dec/2023:16:59:53 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.85.0" "nginx-584856b57f-kv4vq" "172.18.0.1"
次はTransformを追加してnginxのlogをParse、VRLで理解できる形にした後、HTTPステータスコードを200でフィルターしJSONで出力する例です
sources:
vector:
type: vector
address: "0.0.0.0:6000"
transforms:
parse-nginx:
type: remap
inputs:
- vector
source: |
. |= parse_nginx_log!(.message,"combined")
filtered:
type: filter
inputs:
- parse-nginx
condition:
type: "vrl"
source: ".status == 200"
sinks:
stdout:
type: console
inputs:
- filtered
target: stdout
encoding:
codec: "json"
{"agent":"curl/7.85.0","client":"10.244.0.5","compression":"172.18.0.1","file":"/var/log/nginx/access.log","host":"nginx-584856b57f-sbt4c","message":"10.244.0.5 - - [21/Dec/2023:18:10:42 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.85.0\" \"172.18.0.1\"","referer":"-","request":"GET / HTTP/1.1","size":615,"source_type":"file","status":200,"timestamp":"2023-12-21T18:10:42Z"}
{"agent":"curl/7.85.0","client":"10.244.0.5","compression":"172.18.0.1","file":"/var/log/nginx/access.log","host":"nginx-584856b57f-v8dl6","message":"10.244.0.5 - - [21/Dec/2023:18:10:43 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.85.0\" \"172.18.0.1\"","referer":"-","request":"GET / HTTP/1.1","size":615,"source_type":"file","status":200,"timestamp":"2023-12-21T18:10:43Z"}
{"agent":"curl/7.85.0","client":"10.244.0.5","compression":"172.18.0.1","file":"/var/log/nginx/access.log","host":"nginx-584856b57f-v8dl6","message":"10.244.0.5 - - [21/Dec/2023:18:10:45 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.85.0\" \"172.18.0.1\"","referer":"-","request":"GET / HTTP/1.1","size":615,"source_type":"file","status":200,"timestamp":"2023-12-21T18:10:45Z"}
とまぁこんな感じで比較的簡単に、ログの収集、変換、出力が出来ました。VRLなどは弱化の学習コストがかかるかもしれないですが、LogQLなどのクエリ言語を触ったことがある方にはそれほど抵抗がないのではないでしょうか?また今回はローカルで手軽に触るためクラウドサービスは利用していませんが、いくつかサポートされているので、ぜひお試ししてみてください。
まとめ
Observability PiplineのVectorを紹介しました。今回はログコレクタについて記載させてもらいましたが、メトリクスやトレースも利用できる(予定)ので、ツール選定で迷っている方は候補として入れてみてはいかがでしょうか?
最後までご覧いただきありがとうございました!