Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Node Logs feature, which currently only handles journal logs #953

Merged
merged 6 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ ignore:
- node_modules
- charts/k8s-monitoring/vendir.lock.yml
- charts/k8s-monitoring/docs/examples/**/output.yaml
- charts/k8s-monitoring/tests/integration/**/output.yaml
- charts/k8s-monitoring/tests/platform/**/output.yaml
- charts/k8s-monitoring-v1/docs/examples/**/output.yaml
- charts/**/templates

Expand Down
6 changes: 6 additions & 0 deletions charts/feature-node-logs/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
docs
schema-mods
tests
Makefile
README.md
README.md.gotmpl
3 changes: 3 additions & 0 deletions charts/feature-node-logs/Chart.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies: []
digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
generated: "2024-08-28T15:09:37.347011-05:00"
13 changes: 13 additions & 0 deletions charts/feature-node-logs/Chart.yaml
Original file line number Diff line number Diff line change
@@ -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: []
38 changes: 38 additions & 0 deletions charts/feature-node-logs/Makefile
Original file line number Diff line number Diff line change
@@ -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
56 changes: 56 additions & 0 deletions charts/feature-node-logs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!--
(NOTE: Do not edit README.md directly. It is a generated file!)
( To make changes, please modify README.md.gotmpl and run `helm-docs`)
-->

# 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 | <pete.wall@grafana.com> | |
<!-- markdownlint-disable no-bare-urls -->
<!-- markdownlint-disable list-marker-space -->
## Source Code

* <https://github.com/grafana/k8s-monitoring-helm/tree/main/charts/feature-node-logs>
<!-- markdownlint-enable list-marker-space -->
<!-- markdownlint-enable no-bare-urls -->

## 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. |
32 changes: 32 additions & 0 deletions charts/feature-node-logs/README.md.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--
(NOTE: Do not edit README.md directly. It is a generated file!)
( To make changes, please modify README.md.gotmpl and run `helm-docs`)
-->

{{ 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" . }}
<!-- markdownlint-disable no-bare-urls -->
<!-- markdownlint-disable list-marker-space -->
{{ template "chart.sourcesSection" . }}
<!-- markdownlint-enable list-marker-space -->
<!-- markdownlint-enable no-bare-urls -->
{{ template "chart.requirementsSection" . }}
{{ template "chart.valuesSection" . }}
13 changes: 13 additions & 0 deletions charts/feature-node-logs/templates/_collector_validation.tpl
Original file line number Diff line number Diff line change
@@ -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 -}}
17 changes: 17 additions & 0 deletions charts/feature-node-logs/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -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 }}
49 changes: 49 additions & 0 deletions charts/feature-node-logs/templates/_module.alloy.tpl
Original file line number Diff line number Diff line change
@@ -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"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know if the hostname here would generally match the k8s node name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it matches the Node name where the Alloy pod lives.

}
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 }}
11 changes: 11 additions & 0 deletions charts/feature-node-logs/templates/_notes.tpl
Original file line number Diff line number Diff line change
@@ -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 }}
11 changes: 11 additions & 0 deletions charts/feature-node-logs/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -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 }}
Empty file.
46 changes: 46 additions & 0 deletions charts/feature-node-logs/tests/default_test.yaml
Original file line number Diff line number Diff line change
@@ -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
}
}
41 changes: 41 additions & 0 deletions charts/feature-node-logs/values.schema.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
Loading