Vectorとは
現在参画している現場で、ログコレクターとしてVectorを利用しています。
本記事ではVectorの紹介と併せて、Kubernetes環境へデプロイできるようにHelmChart化してみたいと思います。
ログコレクターとは
ログコレクターは複数のソース (ファイル、system など) からログを収集します。
メタデータによるエントリの追加、解析、フィルタリングなどを含む、ログの変換操作を実行できます。
収集したログはSplunkなどのコンポーネントに送信されます。
Vectorとは
OSSのRust製データパイプライン(エージェント)で、可観測性データ(ログ・メトリクス)の収集・変換・送信を行います。
大きく「Sources」「Transforms」「Sinks」の3コンポーネントで構成されています。
様々なデータを収集することが可能で、送信先として指定可能な製品(Splunk、ElasticSerach、Grafana Loki ...)も幅広くサポートされています。
詳細は公式ドキュメントを参照してください。
Vectorの性能
Fluentd等の他エージェントに比べると、高速でメモリ効率が高く、要求の厳しいワークロードの処理に適しているようです。
パフォーマンス比較については、以下の記事が参考になります。
HelmChart
ディレクトリ構成は以下となります。
. |-- Chart.yaml |-- templates | |-- vector-config.yaml | |-- vector-daemonset.yaml | |-- vector-rbac.yaml | |-- vector-service-account.yaml | `-- vector-service.yaml `-- values.yaml
templates/vector-daemonset.yaml
VectorをDaemonSetで定義して、各ノードのコンテナログ(/var/log/pods)を参照できるようにします。
kube-config を参照する必要があるため、SecretにしてVolumeMountしています。
apiVersion: apps/v1 kind: DaemonSet metadata: name: "{{ .Release.Name }}-daemonset" spec: selector: matchLabels: app: "{{ .Release.Name }}-app" template: metadata: labels: app: "{{ .Release.Name }}-app" spec: serviceAccountName: "{{ .Release.Name }}-vector-sa" containers: - name: "{{ .Release.Name }}-app" image: "{{ .Values.vector.image.repository }}:{{ .Values.vector.image.tag }}" args: ["--config", "/etc/vector/vector.toml"] readinessProbe: httpGet: path: /health port: 8686 initialDelaySeconds: 60 periodSeconds: 60 livenessProbe: httpGet: path: /health port: 8686 initialDelaySeconds: 60 periodSeconds: 60 volumeMounts: - name: config-volume mountPath: /etc/vector readOnly: true - name: kube-config mountPath: /mnt/vector readOnly: true - name: pod-logs mountPath: /var/log/pods readOnly: true env: - name: TZ value: Asia/Tokyo - name: VECTOR_SELF_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: VECTOR_CONFIG_PATH value: /etc/vector/vector.toml ports: - containerPort: 8686 volumes: - name: config-volume configMap: name: "{{ .Release.Name }}-config" - name: kube-config secret: secretName: kube-config - name: pod-logs hostPath: path: /var/log/pods tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule"
kube-config
Secret化するkube-config
は、以下のような内容となります。
kubectl create secret generic kube-config --from-file=kube-config -n xxx
でVectorと同じnamespaceにデプロイしてください。
apiVersion: v1 clusters: - cluster: certificate-authority-data: xxxx server: https://kubernetes.default.svc:443 name: default contexts: - context: cluster: default user: default name: default current-context: default kind: Config preferences: {} users: - name: default user: xxxx client-key-data: xxxx
templates/vector-config.yaml
次にConfigMapです。
Vectorの設定ファイルをConfigMap化しています。
sources.kubernetes_logs.kube_config_file
にDaemonSetでマウントしたkube-config
のパスを指定する必要がありますtransforms.transform_logs
でログの変換やフィルタリングの設定をしていますsinks.loki
でログの送信先に Grafana Loki のURLを指定しています
apiVersion: v1 kind: ConfigMap metadata: name: "{{ .Release.Name }}-config" data: vector.toml: |- # Vector の設定ファイル [api] enabled = true address = "0.0.0.0:8686" [sources.kubernetes_logs] type = "kubernetes_logs" ignore_older_secs = 1800 max_read_bytes = 10485760 max_line_bytes = 1048576 read_from = "end" timezone = "Asia/Tokyo" kube_config_file = "/mnt/vector/kube-config" extra_namespace_label_selector = """ kubernetes.io/metadata.name!=default, kubernetes.io/metadata.name!=kube-system """ [transforms.transform_logs] type = "remap" inputs = [ "kubernetes_logs" ] source = """ .pod = .kubernetes.pod_name .namespace = .kubernetes.pod_namespace .container = .kubernetes.container_name del(.file) del(.kubernetes) del(.source_type) del(.stream) """ timezone = "Asia/Tokyo" [sinks.loki] type = "loki" inputs = ["transform_logs"] compression = "snappy" endpoint = "{{ .Values.loki.address }}" path = "/loki/api/v1/push" out_of_order_action = "drop" remove_timestamp = false [sinks.loki.encoding] codec = "json" timestamp_format = "rfc3339" [sinks.loki.labels] job = "k8s-logs" env = "{{ .Values.loki.env }}"
各設定項目の詳細は公式ドキュメントを参照してください。
- https://vector.dev/docs/reference/configuration/sources/kubernetes_logs/
- https://vector.dev/docs/reference/configuration/transforms/remap/
- https://vector.dev/docs/reference/configuration/sinks/loki/
その他のマニフェストについて特筆すべき点はないため、詳細は割愛します。
# Chart.yaml apiVersion: v2 name: vector-agent description: A Helm chart for Vector Agent version: 1.0.0
# values.yaml vector: image: repository: "docker.io/timberio/vector" tag: "0.29.1-alpine" service: type: ClusterIP loki: address: "http://loki-stack.logging.svc:3100" env: dev
# templates/vector-service.yaml apiVersion: v1 kind: Service metadata: name: "{{ .Release.Name }}-service" spec: selector: app: "{{ .Release.Name }}-app" ports: - name: http port: 8686 targetPort: 8686 type: "{{ .Values.vector.service.type }}"
# templates/vector-service-account.yaml apiVersion: v1 kind: ServiceAccount metadata: name: "{{ .Release.Name }}-vector-sa"
# templates/vector-rbac.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: "{{ .Release.Name }}-vector-clusterrole" rules: - apiGroups: [""] resources: ["pods", "pods/log", "nodes", "namespaces", "deployments", "statefulsets"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: "{{ .Release.Name }}-vector-rolebinding" subjects: - kind: ServiceAccount name: "{{ .Release.Name }}-vector-sa" namespace: {{ .Release.Namespace | quote }} roleRef: kind: ClusterRole name: "{{ .Release.Name }}-vector-clusterrole" apiGroup: rbac.authorization.k8s.io
上記のChartをhelmコマンドでデプロイしてみます。
$ helm version version.BuildInfo{Version:"v3.10.2", GitCommit:"50f003e5ee8704ec937a756c646870227d7c8b58", GitTreeState:"clean", GoVersion:"go1.18.8"} # dry run $ helm install vector-test ./vector-agent-helm-chart/ --dry-run --namespace test-ns --create-namespace NAME: vector-test LAST DEPLOYED: Fri May 12 16:08:49 2023 NAMESPACE: test-ns STATUS: pending-install REVISION: 1 TEST SUITE: None HOOKS: MANIFEST: --- # Source: vector-agent/templates/vector-service-account.yaml apiVersion: v1 kind: ServiceAccount metadata: name: "vector-test-vector-sa" ... $ helm install vector-test ./vector-agent-helm-chart/ --namespace test-ns --create-namespace NAME: vector-test LAST DEPLOYED: Fri May 12 16:10:48 2023 NAMESPACE: test-ns STATUS: deployed REVISION: 1 TEST SUITE: None
Vectorを使ってみて
2023年5月現在、複数行のログがそれぞれ別レコードとして扱われてしまうので、Grafanaで可視化した際に見づらいと感じました。
コンテナのログをJSONで出力するなどしないと、単一データとして扱われないようです。
改行の扱いについては、以下の記事も参考になります。
まとめ
Vectorの紹介とHelmChartにしてデプロイしてみました。
OpenShiftではFluentd が非推奨となり、代わりにVectorが採用されています。
また、Vectorには以下のような特徴があります。
- ログ・メトリクス収集が可能なエージェント(Fluentdとほぼ同等)
- 高性能(高速でメモリ効率が高い、CPU消費は多め)
- Splunk、ElasticSerachなど大体の製品に対応している
参考リンク
- https://github.com/vectordotdev/vector#performance
- https://medium.com/ibm-cloud/log-collectors-performance-benchmarking-8c5218a08fea
- https://docs.openshift.com/container-platform/4.12/logging/cluster-logging.html#collector-features
- https://access.redhat.com/ja/articles/7009795
- https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.11/html-single/logging/index#doc-wrapper
Gitレポジトリ。
公式のHelmChart。
コンテナイメージはtimberio/vector
という名前で、Dockerhubに公開されています。