diff --git a/charts/feature-node-logs/.helmignore b/charts/feature-node-logs/.helmignore new file mode 100644 index 0000000000..2b29eaf564 --- /dev/null +++ b/charts/feature-node-logs/.helmignore @@ -0,0 +1,6 @@ +docs +schema-mods +tests +Makefile +README.md +README.md.gotmpl diff --git a/charts/feature-node-logs/Chart.lock b/charts/feature-node-logs/Chart.lock new file mode 100644 index 0000000000..cc833191e5 --- /dev/null +++ b/charts/feature-node-logs/Chart.lock @@ -0,0 +1,3 @@ +dependencies: [] +digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726 +generated: "2024-08-28T15:09:37.347011-05:00" diff --git a/charts/feature-node-logs/Chart.yaml b/charts/feature-node-logs/Chart.yaml new file mode 100644 index 0000000000..555cbb0732 --- /dev/null +++ b/charts/feature-node-logs/Chart.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v2 +name: k8s-monitoring-feature-node-logs +description: Kubernetes Observability feature for gathering Cluster Node logs. +type: application +sources: + - https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-node-logs +version: 1.0.0 +appVersion: 1.0.0 +maintainers: + - email: pete.wall@grafana.com + name: petewall +dependencies: [] diff --git a/charts/feature-node-logs/Makefile b/charts/feature-node-logs/Makefile new file mode 100644 index 0000000000..9314711797 --- /dev/null +++ b/charts/feature-node-logs/Makefile @@ -0,0 +1,38 @@ +HAS_HELM_DOCS := $(shell command -v helm-docs;) +HAS_HELM_UNITTEST := $(shell helm plugin list | grep unittest 2> /dev/null) +UPDATECLI_FILES := $(shell yq -e '.dependencies[] | select(.repository == "http*") | ".updatecli-" + .name + ".yaml"' Chart.yaml 2>/dev/null | sort | uniq) + +.SECONDEXPANSION: +README.md: values.yaml Chart.yaml $$(wildcard README.md.gotmpl) +ifdef HAS_HELM_DOCS + helm-docs +else + docker run --rm --volume "$(shell pwd):/helm-docs" -u $(shell id -u) jnorwood/helm-docs:latest +endif + +Chart.lock: Chart.yaml + helm dependency update . + @touch Chart.lock # Ensure the timestamp is updated + +values.schema.json: values.yaml $$(wildcard schema-mods/*) + ../../scripts/schema-gen.sh . + +.updatecli-%.yaml: Chart.yaml + ../../scripts/charts-to-updatecli.sh Chart.yaml + +.PHONY: clean +clean: + rm -f README.md values.schema.json $(UPDATECLI_FILES) + +.PHONY: build +build: README.md Chart.lock values.schema.json $(UPDATECLI_FILES) + +.PHONY: test +test: build + helm lint . + ct lint --lint-conf ../../.configs/lintconf.yaml --helm-dependency-extra-args=--skip-refresh --charts . +ifdef HAS_HELM_UNITTEST + helm unittest . +else + docker run --rm --volume $(shell pwd):/apps helmunittest/helm-unittest . +endif diff --git a/charts/feature-node-logs/README.md b/charts/feature-node-logs/README.md new file mode 100644 index 0000000000..42fa96ee98 --- /dev/null +++ b/charts/feature-node-logs/README.md @@ -0,0 +1,56 @@ + + +# k8s-monitoring-feature-node-logs + +![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0](https://img.shields.io/badge/AppVersion-1.0.0-informational?style=flat-square) +Kubernetes Observability feature for gathering Cluster Node logs. + +The Node Logs feature enables the collection of logs from Kubernetes Cluster Nodes. + +## Testing + +This chart contains unit tests to verify the generated configuration. A hidden value, `deployAsConfigMap`, will render +the generated configuration into a ConfigMap object. This ConfigMap is not used during regular operation, but it is +useful for showing the outcome of a given values file. + +The unit tests use this to create an object with the configuration that can be asserted against. To run the tests, use +`helm test`. + +Actual integration testing in a live environment should be done in the main [k8s-monitoring](../k8s-monitoring) chart. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| petewall | | | + + +## Source Code + +* + + + +## Values + +### General settings + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Full name override | +| nameOverride | string | `""` | Name override | + +### Journal Logs + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| journal.extraDiscoveryRules | string | `""` | Rule blocks to be added used with the loki.source.journal component for journal logs. These relabeling rules are applied pre-scrape against the targets from service discovery. Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) **Note:** Many field names from journald start with an `_`, such as `_systemd_unit`. The final internal label name would be `__journal__systemd_unit`, with two underscores between `__journal` and `systemd_unit`. | +| journal.extraLogProcessingBlocks | string | `""` | Stage blocks to be added to the loki.process component for journal logs. ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) This value is templated so that you can refer to other values from this file. | +| journal.formatAsJson | bool | `false` | Whether to forward the original journal entry as JSON. | +| journal.jobLabel | string | `"integrations/kubernetes/journal"` | The value for the job label for journal logs. | +| journal.maxAge | string | `"8h"` | The path to the journal logs on the worker node. | +| journal.path | string | `"/var/log/journal"` | The path to the journal logs on the worker node. | +| journal.units | list | `[]` | The list of systemd units to keep scraped logs from. If empty, all units are scraped. | diff --git a/charts/feature-node-logs/README.md.gotmpl b/charts/feature-node-logs/README.md.gotmpl new file mode 100644 index 0000000000..e06cd0e8cc --- /dev/null +++ b/charts/feature-node-logs/README.md.gotmpl @@ -0,0 +1,32 @@ + + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.badgesSection" . }} +{{ template "chart.description" . }} +{{ template "chart.homepageLine" . }} + +The Node Logs feature enables the collection of logs from Kubernetes Cluster Nodes. + +## Testing + +This chart contains unit tests to verify the generated configuration. A hidden value, `deployAsConfigMap`, will render +the generated configuration into a ConfigMap object. This ConfigMap is not used during regular operation, but it is +useful for showing the outcome of a given values file. + +The unit tests use this to create an object with the configuration that can be asserted against. To run the tests, use +`helm test`. + +Actual integration testing in a live environment should be done in the main [k8s-monitoring](../k8s-monitoring) chart. + +{{ template "chart.maintainersSection" . }} + + +{{ template "chart.sourcesSection" . }} + + +{{ template "chart.requirementsSection" . }} +{{ template "chart.valuesSection" . }} diff --git a/charts/feature-node-logs/templates/_collector_validation.tpl b/charts/feature-node-logs/templates/_collector_validation.tpl new file mode 100644 index 0000000000..84bb246885 --- /dev/null +++ b/charts/feature-node-logs/templates/_collector_validation.tpl @@ -0,0 +1,13 @@ +{{/* Validates that the Alloy instance is appropriate for the given Node Logs settings */}} +{{/* Inputs: Values (Node Logs values), Collector (Alloy values), CollectorName (string) */}} +{{- define "feature.nodeLogs.collector.validate" -}} +{{- if not (eq .Collector.controller.type "daemonset") }} + {{- fail (printf "Node Logs feature requires Alloy to be a DaemonSet.\nPlease set:\n%s:\n controller:\n type: daemonset" .CollectorName) }} +{{- end -}} +{{- if and (hasPrefix "/var/log" .Values.journal.path) (not .Collector.alloy.mounts.varlog) }} + {{- fail (printf "Node Logs feature requires Alloy to mount /var/log.\nPlease set:\n%s:\n alloy:\n mounts:\n varlog: true" .CollectorName) }} +{{- end -}} +{{- if .Collector.alloy.clustering.enabled }} + {{- fail (printf "Node Logs feature requires Alloy to not be in clustering mode.\nPlease set:\n%s:\n alloy:\n clustering:\n enabled: true" .CollectorName) }} +{{- end -}} +{{- end -}} diff --git a/charts/feature-node-logs/templates/_helpers.tpl b/charts/feature-node-logs/templates/_helpers.tpl new file mode 100644 index 0000000000..5837853737 --- /dev/null +++ b/charts/feature-node-logs/templates/_helpers.tpl @@ -0,0 +1,17 @@ +{{/* +Create a default fully qualified name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "feature.nodeLogs.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride | lower }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" | lower }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" | lower }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/feature-node-logs/templates/_module.alloy.tpl b/charts/feature-node-logs/templates/_module.alloy.tpl new file mode 100644 index 0000000000..fe780316c6 --- /dev/null +++ b/charts/feature-node-logs/templates/_module.alloy.tpl @@ -0,0 +1,49 @@ +{{- define "feature.nodeLogs.module" }} +declare "node_logs" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.relabel "journal" { + {{- if len .Values.journal.units }} + rule { + action = "keep" + source_labels = ["__journal__systemd_unit"] + regex = "{{ join "|" .Values.journal.units }}" + } + {{- end }} + rule { + action = "replace" + source_labels = ["__journal__systemd_unit"] + replacement = "$1" + target_label = "unit" + } + {{- if .Values.journal.extraDiscoveryRules }} + {{ .Values.journal.extraDiscoveryRules | indent 2 }} + {{- end }} + + forward_to = [] // No forward_to is used in this component, the defined rules are used in the loki.source.journal component + } + + loki.source.journal "worker" { + path = {{ .Values.journal.path | quote }} + format_as_json = {{ .Values.journal.formatAsJson }} + max_age = {{ .Values.journal.maxAge | quote }} + relabel_rules = loki.relabel.journal.rules + labels = { + job = {{ .Values.journal.jobLabel | quote }}, + instance = env("HOSTNAME"), + } + forward_to = [loki.process.journal_logs.receiver] + } + + loki.process "journal_logs" { + {{- if .Values.journal.extraLogProcessingBlocks }} + {{ tpl .Values.journal.extraLogProcessingBlocks . | indent 2 }} + {{ end }} + forward_to = argument.logs_destinations.value + } +} +{{- end -}} + +{{- define "feature.nodeLogs.alloyModules" }}{{- end }} diff --git a/charts/feature-node-logs/templates/_notes.tpl b/charts/feature-node-logs/templates/_notes.tpl new file mode 100644 index 0000000000..ecdf628ebc --- /dev/null +++ b/charts/feature-node-logs/templates/_notes.tpl @@ -0,0 +1,11 @@ +{{- define "feature.nodeLogs.notes.deployments" }}{{- end }} + +{{- define "feature.nodeLogs.notes.task" }} +Gather logs from Kubernetes Nodes +{{- end }} + +{{- define "feature.nodeLogs.notes.actions" }}{{- end }} + +{{- define "feature.nodeLogs.summary" -}} +version: {{ .Chart.Version }} +{{- end }} diff --git a/charts/feature-node-logs/templates/configmap.yaml b/charts/feature-node-logs/templates/configmap.yaml new file mode 100644 index 0000000000..581522e515 --- /dev/null +++ b/charts/feature-node-logs/templates/configmap.yaml @@ -0,0 +1,11 @@ +{{- if .Values.deployAsConfigMap }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "feature.nodeLogs.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + module.alloy: |- + {{- include "feature.nodeLogs.module" . | indent 4 }} +{{- end }} diff --git a/charts/feature-node-logs/tests/__snapshot__/.gitkeep b/charts/feature-node-logs/tests/__snapshot__/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/charts/feature-node-logs/tests/default_test.yaml b/charts/feature-node-logs/tests/default_test.yaml new file mode 100644 index 0000000000..d43dead03d --- /dev/null +++ b/charts/feature-node-logs/tests/default_test.yaml @@ -0,0 +1,46 @@ +# yamllint disable rule:document-start rule:line-length rule:trailing-spaces +suite: Test default values +templates: + - configmap.yaml +tests: + - it: should render the default configuration + set: + deployAsConfigMap: true + asserts: + - isKind: + of: ConfigMap + - equal: + path: data["module.alloy"] + value: |- + declare "node_logs" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.relabel "journal" { + rule { + action = "replace" + source_labels = ["__journal__systemd_unit"] + replacement = "$1" + target_label = "unit" + } + + forward_to = [] // No forward_to is used in this component, the defined rules are used in the loki.source.journal component + } + + loki.source.journal "worker" { + path = "/var/log/journal" + format_as_json = false + max_age = "8h" + relabel_rules = loki.relabel.journal.rules + labels = { + job = "integrations/kubernetes/journal", + instance = env("HOSTNAME"), + } + forward_to = [loki.process.journal_logs.receiver] + } + + loki.process "journal_logs" { + forward_to = argument.logs_destinations.value + } + } diff --git a/charts/feature-node-logs/values.schema.json b/charts/feature-node-logs/values.schema.json new file mode 100644 index 0000000000..770bd6d9a6 --- /dev/null +++ b/charts/feature-node-logs/values.schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "deployAsConfigMap": { + "type": "boolean" + }, + "fullnameOverride": { + "type": "string" + }, + "journal": { + "type": "object", + "properties": { + "extraDiscoveryRules": { + "type": "string" + }, + "extraLogProcessingBlocks": { + "type": "string" + }, + "formatAsJson": { + "type": "boolean" + }, + "jobLabel": { + "type": "string" + }, + "maxAge": { + "type": "string" + }, + "path": { + "type": "string" + }, + "units": { + "type": "array" + } + } + }, + "nameOverride": { + "type": "string" + } + } +} diff --git a/charts/feature-node-logs/values.yaml b/charts/feature-node-logs/values.yaml new file mode 100644 index 0000000000..6229ee2bc3 --- /dev/null +++ b/charts/feature-node-logs/values.yaml @@ -0,0 +1,50 @@ +--- +# -- Name override +# @section -- General settings +nameOverride: "" + +# -- Full name override +# @section -- General settings +fullnameOverride: "" + +journal: + # -- The path to the journal logs on the worker node. + # @section -- Journal Logs + path: "/var/log/journal" + + # -- The path to the journal logs on the worker node. + # @section -- Journal Logs + maxAge: "8h" + + # -- The value for the job label for journal logs. + # @section -- Journal Logs + jobLabel: "integrations/kubernetes/journal" + + # -- Whether to forward the original journal entry as JSON. + # @section -- Journal Logs + formatAsJson: false + + # -- The list of systemd units to keep scraped logs from. If empty, all units are scraped. + # @section -- Journal Logs + units: [] + # - kubelet.service + # - docker.service + # - containerd.service + + # -- Rule blocks to be added used with the loki.source.journal component for journal logs. + # These relabeling rules are applied pre-scrape against the targets from service discovery. + # Before the scrape, any remaining target labels that start with `__` (i.e. `__meta_kubernetes*`) are dropped. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) + # **Note:** Many field names from journald start with an `_`, such as `_systemd_unit`. The final internal label name would + # be `__journal__systemd_unit`, with two underscores between `__journal` and `systemd_unit`. + # @section -- Journal Logs + extraDiscoveryRules: "" + + # -- Stage blocks to be added to the loki.process component for journal logs. + # ([docs](https://grafana.com/docs/alloy/latest/reference/components/loki/loki.process/#blocks)) + # This value is templated so that you can refer to other values from this file. + # @section -- Journal Logs + extraLogProcessingBlocks: "" + +# @ignore +deployAsConfigMap: false diff --git a/charts/k8s-monitoring-v1/values.yaml b/charts/k8s-monitoring-v1/values.yaml index 892a7c3d98..505cf7b54b 100644 --- a/charts/k8s-monitoring-v1/values.yaml +++ b/charts/k8s-monitoring-v1/values.yaml @@ -1799,7 +1799,7 @@ logs: # ([docs](https://grafana.com/docs/alloy/latest/reference/components/discovery/discovery.relabel/#rule-block)) # **Note:** Many field names from journald start with an `_`, such as `_systemd_unit`. The final internal label name would # be `__journal__systemd_unit`, with two underscores between `__journal` and `systemd_unit`. - # @section -- Logs Scrape: Pod Logs + # @section -- Logs Scrape: Journal extraRelabelingRules: "" # Settings related to logs ingested via receivers diff --git a/charts/k8s-monitoring/.updatecli-alloy.yaml b/charts/k8s-monitoring/.updatecli-alloy.yaml index b94001f48e..13d287388c 100644 --- a/charts/k8s-monitoring/.updatecli-alloy.yaml +++ b/charts/k8s-monitoring/.updatecli-alloy.yaml @@ -16,7 +16,7 @@ conditions: kind: yaml spec: file: charts/k8s-monitoring/Chart.yaml - key: $.dependencies[9].name + key: $.dependencies[10].name value: alloy disablesourceinput: true targets: @@ -25,7 +25,7 @@ targets: kind: helmchart spec: file: Chart.yaml - key: $.dependencies[9].version + key: $.dependencies[10].version name: charts/k8s-monitoring versionincrement: none sourceid: alloy @@ -34,7 +34,7 @@ targets: kind: helmchart spec: file: Chart.yaml - key: $.dependencies[10].version + key: $.dependencies[11].version name: charts/k8s-monitoring versionincrement: none sourceid: alloy @@ -43,7 +43,7 @@ targets: kind: helmchart spec: file: Chart.yaml - key: $.dependencies[11].version + key: $.dependencies[12].version name: charts/k8s-monitoring versionincrement: none sourceid: alloy @@ -52,7 +52,7 @@ targets: kind: helmchart spec: file: Chart.yaml - key: $.dependencies[12].version + key: $.dependencies[13].version name: charts/k8s-monitoring versionincrement: none sourceid: alloy @@ -61,7 +61,7 @@ targets: kind: helmchart spec: file: Chart.yaml - key: $.dependencies[13].version + key: $.dependencies[14].version name: charts/k8s-monitoring versionincrement: none sourceid: alloy diff --git a/charts/k8s-monitoring/Chart.lock b/charts/k8s-monitoring/Chart.lock index 611a87c842..ef7bec2a29 100644 --- a/charts/k8s-monitoring/Chart.lock +++ b/charts/k8s-monitoring/Chart.lock @@ -17,6 +17,9 @@ dependencies: - name: k8s-monitoring-feature-integrations repository: file://../feature-integrations version: 1.0.0 +- name: k8s-monitoring-feature-node-logs + repository: file://../feature-node-logs + version: 1.0.0 - name: k8s-monitoring-feature-pod-logs repository: file://../feature-pod-logs version: 1.0.0 @@ -41,5 +44,5 @@ dependencies: - name: alloy repository: https://grafana.github.io/helm-charts version: 0.10.0 -digest: sha256:c42e09be38582ced6f973de7fd7d2f5d96c1e926e187936e0ee1d7ae295c9e0f -generated: "2024-11-21T18:59:30.945426-06:00" +digest: sha256:5805f8a2eb47cc7ed65d2f8b94d07a3bf474143d179bf781be69c5f7ce1a4d00 +generated: "2024-11-26T09:28:35.078464-06:00" diff --git a/charts/k8s-monitoring/Chart.yaml b/charts/k8s-monitoring/Chart.yaml index abcfb27d70..088fd85b8d 100644 --- a/charts/k8s-monitoring/Chart.yaml +++ b/charts/k8s-monitoring/Chart.yaml @@ -41,6 +41,11 @@ dependencies: name: k8s-monitoring-feature-integrations repository: file://../feature-integrations version: 1.0.0 + - alias: nodeLogs + name: k8s-monitoring-feature-node-logs + repository: file://../feature-node-logs + version: 1.0.0 + condition: nodeLogs.enabled - alias: podLogs name: k8s-monitoring-feature-pod-logs repository: file://../feature-pod-logs diff --git a/charts/k8s-monitoring/README.md b/charts/k8s-monitoring/README.md index 133ee2d493..f44217d74b 100644 --- a/charts/k8s-monitoring/README.md +++ b/charts/k8s-monitoring/README.md @@ -129,6 +129,7 @@ podLogs: | file://../feature-cluster-events | clusterEvents(k8s-monitoring-feature-cluster-events) | 1.0.0 | | file://../feature-cluster-metrics | clusterMetrics(k8s-monitoring-feature-cluster-metrics) | 1.0.0 | | file://../feature-integrations | integrations(k8s-monitoring-feature-integrations) | 1.0.0 | +| file://../feature-node-logs | nodeLogs(k8s-monitoring-feature-node-logs) | 1.0.0 | | file://../feature-pod-logs | podLogs(k8s-monitoring-feature-pod-logs) | 1.0.0 | | file://../feature-profiling | profiling(k8s-monitoring-feature-profiling) | 1.0.0 | | file://../feature-prometheus-operator-objects | prometheusOperatorObjects(k8s-monitoring-feature-prometheus-operator-objects) | 1.0.0 | @@ -336,6 +337,14 @@ podLogs: | integrations | object | No integrations enabled | Service Integrations enables gathering telemetry data for common services and applications deployed to Kubernetes. To see the valid options, please see the [Service Integrations documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-integrations). | | integrations.destinations | list | `[]` | The destinations where integration metrics will be sent. If empty, all metrics-capable destinations will be used. | +### Features - Node Logs + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| nodeLogs | object | Disabled | Node logs. Requires a destination that supports logs. To see the valid options, please see the [Node Logs feature documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-node-logs). | +| nodeLogs.destinations | list | `[]` | The destinations where logs will be sent. If empty, all logs-capable destinations will be used. | +| nodeLogs.enabled | bool | `false` | Enable gathering Kubernetes Cluster Node logs. | + ### Features - Pod Logs | Key | Type | Default | Description | diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-annotation-autodiscovery-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-annotation-autodiscovery-1.0.0.tgz index 1727226a86..a77d3d5165 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-annotation-autodiscovery-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-annotation-autodiscovery-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-application-observability-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-application-observability-1.0.0.tgz index fc5d77929b..3a48be5360 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-application-observability-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-application-observability-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-auto-instrumentation-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-auto-instrumentation-1.0.0.tgz index ba11bb416c..23d345758a 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-auto-instrumentation-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-auto-instrumentation-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-events-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-events-1.0.0.tgz index 4c74f52161..548ce1fe74 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-events-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-events-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-metrics-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-metrics-1.0.0.tgz index f14011287a..5ce5f1f887 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-metrics-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-cluster-metrics-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-integrations-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-integrations-1.0.0.tgz index b4ce7d7216..d019b3de3e 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-integrations-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-integrations-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-node-logs-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-node-logs-1.0.0.tgz new file mode 100644 index 0000000000..898946e929 Binary files /dev/null and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-node-logs-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-pod-logs-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-pod-logs-1.0.0.tgz index 613030615a..3356d37d45 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-pod-logs-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-pod-logs-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-profiling-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-profiling-1.0.0.tgz index 3f68b58c30..c1aa1991a5 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-profiling-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-profiling-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/charts/k8s-monitoring-feature-prometheus-operator-objects-1.0.0.tgz b/charts/k8s-monitoring/charts/k8s-monitoring-feature-prometheus-operator-objects-1.0.0.tgz index 8ec88c85dc..f679d7e120 100644 Binary files a/charts/k8s-monitoring/charts/k8s-monitoring-feature-prometheus-operator-objects-1.0.0.tgz and b/charts/k8s-monitoring/charts/k8s-monitoring-feature-prometheus-operator-objects-1.0.0.tgz differ diff --git a/charts/k8s-monitoring/docs/Features.md b/charts/k8s-monitoring/docs/Features.md index 468923bda3..5322f092b6 100644 --- a/charts/k8s-monitoring/docs/Features.md +++ b/charts/k8s-monitoring/docs/Features.md @@ -7,6 +7,7 @@ These are the current features supported in this Helm chart: - [Application Observability](#application-observability) - [Annotation Autodiscovery](#annotation-autodiscovery) - [Prometheus Operator Objects](#prometheus-operator-objects) +- [Node Logs](#node-logs) - [Pod Logs](#pod-logs) - [Service Integrations](#service-integrations) - [Profiling](#profiling) @@ -42,6 +43,12 @@ Collects metrics from Pods and Services that use a specific annotation. Collects metrics from Prometheus Operator objects, like PodMonitors and ServiceMonitors. +## Node Logs + +[Documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-node-logs) + +Collects logs from Kubernetes Cluster Nodes. + ## Pod Logs [Documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-pod-logs) diff --git a/charts/k8s-monitoring/docs/examples/features/node-logs/default/README.md b/charts/k8s-monitoring/docs/examples/features/node-logs/default/README.md new file mode 100644 index 0000000000..c6f7ecea57 --- /dev/null +++ b/charts/k8s-monitoring/docs/examples/features/node-logs/default/README.md @@ -0,0 +1,24 @@ + +# Example: features/node-logs/default/values.yaml + +## Values + +```yaml +--- +cluster: + name: node-logs-cluster + +destinations: + - name: loki + type: loki + url: http://loki.loki.svc:3100/api/push + +nodeLogs: + enabled: true + +alloy-logs: + enabled: true +``` diff --git a/charts/k8s-monitoring/docs/examples/features/node-logs/default/alloy-logs.alloy b/charts/k8s-monitoring/docs/examples/features/node-logs/default/alloy-logs.alloy new file mode 100644 index 0000000000..19bc87fd9d --- /dev/null +++ b/charts/k8s-monitoring/docs/examples/features/node-logs/default/alloy-logs.alloy @@ -0,0 +1,56 @@ +// Destination: loki (loki) +otelcol.exporter.loki "loki" { + forward_to = [loki.write.loki.receiver] +} + +loki.write "loki" { + endpoint { + url = "http://loki.loki.svc:3100/api/push" + tls_config { + insecure_skip_verify = false + } + } + external_labels = { + cluster = "node-logs-cluster", + "k8s_cluster_name" = "node-logs-cluster", + } +} + +// Feature: Node Logs +declare "node_logs" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.relabel "journal" { + rule { + action = "replace" + source_labels = ["__journal__systemd_unit"] + replacement = "$1" + target_label = "unit" + } + + forward_to = [] // No forward_to is used in this component, the defined rules are used in the loki.source.journal component + } + + loki.source.journal "worker" { + path = "/var/log/journal" + format_as_json = false + max_age = "8h" + relabel_rules = loki.relabel.journal.rules + labels = { + job = "integrations/kubernetes/journal", + instance = env("HOSTNAME"), + } + forward_to = [loki.process.journal_logs.receiver] + } + + loki.process "journal_logs" { + forward_to = argument.logs_destinations.value + } +} +node_logs "feature" { + logs_destinations = [ + loki.write.loki.receiver, + ] +} diff --git a/charts/k8s-monitoring/docs/examples/features/node-logs/default/output.yaml b/charts/k8s-monitoring/docs/examples/features/node-logs/default/output.yaml new file mode 100644 index 0000000000..d3f842b41c --- /dev/null +++ b/charts/k8s-monitoring/docs/examples/features/node-logs/default/output.yaml @@ -0,0 +1,343 @@ +--- +# Source: k8s-monitoring/charts/alloy-logs/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ko-alloy-logs + namespace: default + labels: + helm.sh/chart: alloy-logs-0.10.0 + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + + app.kubernetes.io/version: "v1.5.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +--- +# Source: k8s-monitoring/templates/alloy-config.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: ko-alloy-logs + namespace: default +data: + config.alloy: |- + // Destination: loki (loki) + otelcol.exporter.loki "loki" { + forward_to = [loki.write.loki.receiver] + } + + loki.write "loki" { + endpoint { + url = "http://loki.loki.svc:3100/api/push" + tls_config { + insecure_skip_verify = false + } + } + external_labels = { + cluster = "node-logs-cluster", + "k8s_cluster_name" = "node-logs-cluster", + } + } + + // Feature: Node Logs + declare "node_logs" { + argument "logs_destinations" { + comment = "Must be a list of log destinations where collected logs should be forwarded to" + } + + loki.relabel "journal" { + rule { + action = "replace" + source_labels = ["__journal__systemd_unit"] + replacement = "$1" + target_label = "unit" + } + + forward_to = [] // No forward_to is used in this component, the defined rules are used in the loki.source.journal component + } + + loki.source.journal "worker" { + path = "/var/log/journal" + format_as_json = false + max_age = "8h" + relabel_rules = loki.relabel.journal.rules + labels = { + job = "integrations/kubernetes/journal", + instance = env("HOSTNAME"), + } + forward_to = [loki.process.journal_logs.receiver] + } + + loki.process "journal_logs" { + forward_to = argument.logs_destinations.value + } + } + node_logs "feature" { + logs_destinations = [ + loki.write.loki.receiver, + ] + } +--- +# Source: k8s-monitoring/charts/alloy-logs/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: ko-alloy-logs + labels: + helm.sh/chart: alloy-logs-0.10.0 + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + + app.kubernetes.io/version: "v1.5.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +rules: + # Rules which allow discovery.kubernetes to function. + - apiGroups: + - "" + - "discovery.k8s.io" + - "networking.k8s.io" + resources: + - endpoints + - endpointslices + - ingresses + - nodes + - nodes/proxy + - nodes/metrics + - pods + - services + verbs: + - get + - list + - watch + # Rules which allow loki.source.kubernetes and loki.source.podlogs to work. + - apiGroups: + - "" + resources: + - pods + - pods/log + - namespaces + verbs: + - get + - list + - watch + - apiGroups: + - "monitoring.grafana.com" + resources: + - podlogs + verbs: + - get + - list + - watch + # Rules which allow mimir.rules.kubernetes to work. + - apiGroups: ["monitoring.coreos.com"] + resources: + - prometheusrules + verbs: + - get + - list + - watch + - nonResourceURLs: + - /metrics + verbs: + - get + # Rules for prometheus.kubernetes.* + - apiGroups: ["monitoring.coreos.com"] + resources: + - podmonitors + - servicemonitors + - probes + verbs: + - get + - list + - watch + # Rules which allow eventhandler to work. + - apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch + # needed for remote.kubernetes.* + - apiGroups: [""] + resources: + - "configmaps" + - "secrets" + verbs: + - get + - list + - watch + # needed for otelcol.processor.k8sattributes + - apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- +# Source: k8s-monitoring/charts/alloy-logs/templates/rbac.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ko-alloy-logs + labels: + helm.sh/chart: alloy-logs-0.10.0 + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + + app.kubernetes.io/version: "v1.5.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: rbac +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ko-alloy-logs +subjects: + - kind: ServiceAccount + name: ko-alloy-logs + namespace: default +--- +# Source: k8s-monitoring/charts/alloy-logs/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: ko-alloy-logs + labels: + helm.sh/chart: alloy-logs-0.10.0 + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + + app.kubernetes.io/version: "v1.5.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy + app.kubernetes.io/component: networking +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + internalTrafficPolicy: Cluster + ports: + - name: http-metrics + port: 12345 + targetPort: 12345 + protocol: "TCP" +--- +# Source: k8s-monitoring/charts/alloy-logs/templates/controllers/daemonset.yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: ko-alloy-logs + labels: + helm.sh/chart: alloy-logs-0.10.0 + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + + app.kubernetes.io/version: "v1.5.0" + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: alloy +spec: + minReadySeconds: 10 + selector: + matchLabels: + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: alloy + labels: + app.kubernetes.io/name: alloy-logs + app.kubernetes.io/instance: ko + spec: + serviceAccountName: ko-alloy-logs + containers: + - name: alloy + image: docker.io/grafana/alloy:v1.5.0 + imagePullPolicy: IfNotPresent + args: + - run + - /etc/alloy/config.alloy + - --storage.path=/tmp/alloy + - --server.http.listen-addr=0.0.0.0:12345 + - --server.http.ui-path-prefix=/ + - --stability.level=generally-available + env: + - name: ALLOY_DEPLOY_MODE + value: "helm" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - containerPort: 12345 + name: http-metrics + readinessProbe: + httpGet: + path: /-/ready + port: 12345 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 1 + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - FSETID + - KILL + - SETGID + - SETUID + - SETPCAP + - NET_BIND_SERVICE + - NET_RAW + - SYS_CHROOT + - MKNOD + - AUDIT_WRITE + - SETFCAP + drop: + - ALL + seccompProfile: + type: RuntimeDefault + volumeMounts: + - name: config + mountPath: /etc/alloy + - name: varlog + mountPath: /var/log + readOnly: true + - name: dockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + - name: config-reloader + image: ghcr.io/jimmidyson/configmap-reload:v0.12.0 + args: + - --volume-dir=/etc/alloy + - --webhook-url=http://localhost:12345/-/reload + volumeMounts: + - name: config + mountPath: /etc/alloy + resources: + requests: + cpu: 1m + memory: 5Mi + dnsPolicy: ClusterFirst + nodeSelector: + kubernetes.io/os: linux + volumes: + - name: config + configMap: + name: ko-alloy-logs + - name: varlog + hostPath: + path: /var/log + - name: dockercontainers + hostPath: + path: /var/lib/docker/containers diff --git a/charts/k8s-monitoring/docs/examples/features/node-logs/default/values.yaml b/charts/k8s-monitoring/docs/examples/features/node-logs/default/values.yaml new file mode 100644 index 0000000000..bf1980748b --- /dev/null +++ b/charts/k8s-monitoring/docs/examples/features/node-logs/default/values.yaml @@ -0,0 +1,14 @@ +--- +cluster: + name: node-logs-cluster + +destinations: + - name: loki + type: loki + url: http://loki.loki.svc:3100/api/push + +nodeLogs: + enabled: true + +alloy-logs: + enabled: true diff --git a/charts/k8s-monitoring/docs/examples/features/pod-logs/default/alloy-singleton.alloy b/charts/k8s-monitoring/docs/examples/features/pod-logs/default/alloy-singleton.alloy deleted file mode 100644 index 7b27b94311..0000000000 --- a/charts/k8s-monitoring/docs/examples/features/pod-logs/default/alloy-singleton.alloy +++ /dev/null @@ -1,32 +0,0 @@ -// Destination: loki (loki) -otelcol.exporter.loki "loki" { - forward_to = [loki.write.loki.receiver] -} - -loki.write "loki" { - endpoint { - url = "http://loki.loki.svc:3100/api/push" - } - external_labels = { - cluster = "pod-logs-cluster", - "k8s_cluster_name" = "pod-logs-cluster", - } -} - -// Feature: Cluster Events -declare "cluster_events" { - argument "logs_destinations" { - comment = "Must be a list of log destinations where collected logs should be forwarded to" - } - - loki.source.kubernetes_events "cluster_events" { - job_name = "integrations/kubernetes/eventhandler" - log_format = "logfmt" - forward_to = argument.logs_destinations.value - } -} -cluster_events "feature" { - logs_destinations = [ - loki.write.loki.receiver, - ] -} diff --git a/charts/k8s-monitoring/templates/features/_feature_helpers.tpl b/charts/k8s-monitoring/templates/features/_feature_helpers.tpl index d8f0e7c2fa..faee7a0ec8 100644 --- a/charts/k8s-monitoring/templates/features/_feature_helpers.tpl +++ b/charts/k8s-monitoring/templates/features/_feature_helpers.tpl @@ -4,6 +4,7 @@ - autoInstrumentation - clusterMetrics - clusterEvents +- nodeLogs - podLogs - profiling - prometheusOperatorObjects diff --git a/charts/k8s-monitoring/templates/features/_feature_node_logs.tpl b/charts/k8s-monitoring/templates/features/_feature_node_logs.tpl new file mode 100644 index 0000000000..9cc9541569 --- /dev/null +++ b/charts/k8s-monitoring/templates/features/_feature_node_logs.tpl @@ -0,0 +1,40 @@ +{{- define "features.nodeLogs.enabled" }}{{ .Values.nodeLogs.enabled }}{{- end }} + +{{- define "features.nodeLogs.collectors" }} +{{- if .Values.nodeLogs.enabled -}} +- {{ .Values.nodeLogs.collector }} +{{- end }} +{{- end }} + +{{- define "features.nodeLogs.include" }} +{{- if .Values.nodeLogs.enabled -}} +{{- $destinations := include "features.nodeLogs.destinations" . | fromYamlArray }} + +// Feature: Node Logs +{{- include "feature.nodeLogs.module" (dict "Values" .Values.nodeLogs "Files" $.Subcharts.nodeLogs.Files) }} +node_logs "feature" { + logs_destinations = [ + {{ include "destinations.alloy.targets" (dict "destinations" $.Values.destinations "names" $destinations "type" "logs" "ecosystem" "loki") | indent 4 | trim }} + ] +} +{{- end -}} +{{- end -}} + +{{- define "features.nodeLogs.destinations" }} +{{- if .Values.nodeLogs.enabled -}} +{{- include "destinations.get" (dict "destinations" $.Values.destinations "type" "logs" "ecosystem" "loki" "filter" $.Values.nodeLogs.destinations) -}} +{{- end -}} +{{- end -}} + +{{- define "features.nodeLogs.validate" }} +{{- if .Values.nodeLogs.enabled -}} +{{- $featureName := "Kubernetes Node logs" }} +{{- $destinations := include "features.nodeLogs.destinations" . | fromYamlArray }} +{{- include "destinations.validate_destination_list" (dict "destinations" $destinations "type" "logs" "ecosystem" "loki" "feature" $featureName) }} + +{{- range $collector := include "features.nodeLogs.collectors" . | fromYamlArray }} + {{- include "collectors.require_collector" (dict "Values" $.Values "name" $collector "feature" $featureName) }} + {{- include "feature.nodeLogs.collector.validate" (dict "Values" $.Values.nodeLogs "Collector" (index $.Values $collector) "CollectorName" $collector) }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/k8s-monitoring/templates/features/_feature_pod_logs.tpl b/charts/k8s-monitoring/templates/features/_feature_pod_logs.tpl index cdef7193e7..d083ce2762 100644 --- a/charts/k8s-monitoring/templates/features/_feature_pod_logs.tpl +++ b/charts/k8s-monitoring/templates/features/_feature_pod_logs.tpl @@ -34,10 +34,10 @@ pod_logs "feature" { {{- $featureName := "Kubernetes Pod logs" }} {{- $destinations := include "features.podLogs.destinations" . | fromYamlArray }} {{- include "destinations.validate_destination_list" (dict "destinations" $destinations "type" "logs" "ecosystem" "loki" "feature" $featureName) }} -{{- include "collectors.require_collector" (dict "Values" $.Values "name" "alloy-logs" "feature" $featureName) }} {{- range $collector := include "features.podLogs.collectors" . | fromYamlArray }} {{- include "collectors.require_collector" (dict "Values" $.Values "name" $collector "feature" $featureName) }} + {{- include "feature.podLogs.collector.validate" (dict "Values" $.Values.nodeLogs "Collector" (index $.Values $collector) "CollectorName" $collector) }} {{- end -}} {{- end -}} {{- end -}} diff --git a/charts/k8s-monitoring/values.schema.json b/charts/k8s-monitoring/values.schema.json index 37d6982f8c..c5816cb4f5 100644 --- a/charts/k8s-monitoring/values.schema.json +++ b/charts/k8s-monitoring/values.schema.json @@ -968,6 +968,20 @@ } } }, + "nodeLogs": { + "type": "object", + "properties": { + "collector": { + "type": "string" + }, + "destinations": { + "type": "array" + }, + "enabled": { + "type": "boolean" + } + } + }, "podLogs": { "type": "object", "properties": { diff --git a/charts/k8s-monitoring/values.yaml b/charts/k8s-monitoring/values.yaml index eb83b42dc1..957059f7dd 100644 --- a/charts/k8s-monitoring/values.yaml +++ b/charts/k8s-monitoring/values.yaml @@ -81,6 +81,22 @@ clusterEvents: # @ignored collector: alloy-singleton +# -- Node logs. +# Requires a destination that supports logs. +# To see the valid options, please see the [Node Logs feature documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-node-logs). +# @default -- Disabled +# @section -- Features - Node Logs +nodeLogs: + # -- Enable gathering Kubernetes Cluster Node logs. + # @section -- Features - Node Logs + enabled: false + + # -- The destinations where logs will be sent. If empty, all logs-capable destinations will be used. + # @section -- Features - Node Logs + destinations: [] + + collector: alloy-logs + # -- Pod logs. # Requires a destination that supports logs. # To see the valid options, please see the [Pod Logs feature documentation](https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-pod-logs).