Skip to content

[Kubernetes] Reroute container logs based on pod annotations #7118

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4637d62
Add ingest pipeline for rerouting
zmoog Jul 24, 2023
5f7a3fa
Add pipeline failure handler
zmoog Jul 24, 2023
0fe640c
Set service.name and service.version
zmoog Jul 24, 2023
b483709
Draft rerouting docs
zmoog Jul 24, 2023
d8ed5e2
Update packages/kubernetes/data_stream/container_logs/elasticsearch/i…
zmoog Jul 25, 2023
80918ea
Use the Set processor more efficiently
zmoog Jul 25, 2023
7fe8dea
Use ECS for service.name and service.version
zmoog Jul 26, 2023
3559f9f
Switch to routing rules
zmoog Jul 26, 2023
dddb795
Add basic testing for service.name and service.version
zmoog Jul 26, 2023
3bb1e49
Expand the rerouting docs
zmoog Aug 17, 2023
3f9c79a
Mention container-logs routing in the README
zmoog Aug 22, 2023
47cee10
Cleanup
zmoog Aug 22, 2023
b187956
Update test case adding a dataset label
zmoog Aug 30, 2023
7be0729
Docs: add a namespace customization example
zmoog Aug 30, 2023
4b52f34
Drop static fallbacks
zmoog Sep 4, 2023
f026f36
Update docs
zmoog Sep 4, 2023
daf53c2
Update changelog
zmoog Sep 5, 2023
d21d06c
Update packages/kubernetes/data_stream/container_logs/routing_rules.yml
zmoog Sep 6, 2023
9eddeec
Update packages/kubernetes/_dev/build/docs/container-logs.md
zmoog Sep 6, 2023
7385b12
Switch from labels to annotations
zmoog Sep 7, 2023
6f01d4f
Replace some leftover labels with annotations
zmoog Sep 7, 2023
825e7ac
Update packages/kubernetes/_dev/build/docs/container-logs.md
zmoog Sep 7, 2023
81e13ac
Indent processors list to improve compatibility
zmoog Sep 7, 2023
b7d3de0
Update rendered docs
zmoog Sep 7, 2023
4b2d776
Explain WHY we added processors for annotations
zmoog Sep 8, 2023
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
8 changes: 8 additions & 0 deletions packages/kubernetes/_dev/build/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ the masters won't be visible. In these cases it won't be possible to use `schedu
The container-logs dataset requires access to the log files in each Kubernetes node where the container logs are stored.
This defaults to `/var/log/containers/*${kubernetes.container.id}.log`.

#### Routing

The container-logs data stream allows routing logs to a different *dataset* or *namespace* using pod annotations.

For example, suppose you are running Nginx on your Kubernetes cluster, and you want to drive the Nginx container logs into a dedicated dataset or namespace. By annotating the pod with `elastic.co/namespace: nginx`, the integration will send all the container logs to the `nginx` namespace.

To learn more about routing container-logs, see https://docs.elastic.co/integrations/kubernetes/container-logs.

### audit-logs

The audit-logs dataset requires access to the log files on each Kubernetes node where the audit logs are stored.
Expand Down
78 changes: 78 additions & 0 deletions packages/kubernetes/_dev/build/docs/container-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,81 @@ It requires access to the log files in each Kubernetes node where the container
This defaults to `/var/log/containers/*${kubernetes.container.id}.log`.

By default only {{ url "filebeat-input-filestream-parsers" "container parser" }} is enabled. Additional log parsers can be added as an advanced options configuration.


## Rerouting based on pod annotations

You can customize the routing of container logs events and sending them to different datasets and namespaces using pods' annotations.

Routing customization can happen at:

- pod definition time, e.g., using a deployment.
- pod runtime, annotating pods using `kubectl`.


### Set routing at pod definition time

Here is an example of an Nginx deployment where we set both `elastic.co/dataset` and `elastic.co/namespace` annotations to route the container logs to specific datasets and namespace, respectively.

```yaml
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
annotations:
elastic.co/dataset: kubernetes.container_logs.nginx
elastic.co/namespace: nginx
labels:
app: nginx
app.kubernetes.io/name: myservice
app.kubernetes.io/version: v0.1.2
app.kubernetes.io/instance: myservice-abcxzy
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
```


### Set routing at runtime

Suppose you want to change the container logs routing on a running container. In that case, you can annotate the pod using `kubectl`, and the integration will apply it immediately sending all the following documents to the new destination:

Here is an example where we route the container logs for a pod running the Elastic Agent to the `kubernetes.container_logs.agents` dataset:

```shell
kubectl annotate pods elastic-agent-managed-daemonset-6p22g elastic.co/dataset=kubernetes.container_logs.agents
```

Here's a similar example to change the namespace on a pod running Nginx:

```shell
kubectl annotate pods elastic-agent-managed-daemonset-6p22g elastic.co/namespace=nginx
```

You can restore the standard routing by removing the annotations:

```shell
kubectl annotate pods elastic-agent-managed-daemonset-6p22g elastic.co/dataset-
kubectl annotate pods elastic-agent-managed-daemonset-6p22g elastic.co/namespace-
```

### Annotations Reference

Here are the annotations available to customize routing:


| Label | Description |
| ---------------------- | -------------------------------------------------------- |
| `elastic.co/dataset` | Defines the target data stream's dataset for this pod. |
| `elastic.co/namespace` | Defines the target data stream's namespace for this pod. |
5 changes: 5 additions & 0 deletions packages/kubernetes/changelog.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# newer versions go on top
- version: "1.45.0"
changes:
- description: Reroute container logs based on pod annotations.
type: enhancement
link: https://github.com/elastic/integrations/pull/7118
- version: "1.44.0"
changes:
- description: Introducing kubernetes.deployment.status.* metrics
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fields:
data_stream:
dataset: kubernetes.container_logs
namespace: default
kubernetes:
annotations:
elastic_co/dataset: kubernetes.container_logs.nginx
elastic_co/namespace: nginx
labels:
app_kubernetes_io/version: "v0.1.0"
app_kubernetes_io/name: "myservice"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
2023/07/25 15:24:11 [notice] 1#1: start worker process 33
2023/07/25 15:24:11 [notice] 1#1: start worker process 34
2023/07/25 15:24:11 [notice] 1#1: start worker process 35
2023/07/25 15:24:11 [notice] 1#1: using the "epoll" event method
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"expected": [
{
"data_stream": {
"dataset": "kubernetes.container_logs.nginx",
"namespace": "nginx",
"type": "logs"
},
"kubernetes": {
"annotations": {
"elastic_co/dataset": "kubernetes.container_logs.nginx",
"elastic_co/namespace": "nginx"
},
"labels": {
"app_kubernetes_io/name": "myservice",
"app_kubernetes_io/version": "v0.1.0"
}
},
"message": "2023/07/25 15:24:11 [notice] 1#1: start worker process 33",
"service": {
"name": "myservice",
"version": "v0.1.0"
}
},
{
"data_stream": {
"dataset": "kubernetes.container_logs.nginx",
"namespace": "nginx",
"type": "logs"
},
"kubernetes": {
"annotations": {
"elastic_co/dataset": "kubernetes.container_logs.nginx",
"elastic_co/namespace": "nginx"
},
"labels": {
"app_kubernetes_io/name": "myservice",
"app_kubernetes_io/version": "v0.1.0"
}
},
"message": "2023/07/25 15:24:11 [notice] 1#1: start worker process 34",
"service": {
"name": "myservice",
"version": "v0.1.0"
}
},
{
"data_stream": {
"dataset": "kubernetes.container_logs.nginx",
"namespace": "nginx",
"type": "logs"
},
"kubernetes": {
"annotations": {
"elastic_co/dataset": "kubernetes.container_logs.nginx",
"elastic_co/namespace": "nginx"
},
"labels": {
"app_kubernetes_io/name": "myservice",
"app_kubernetes_io/version": "v0.1.0"
}
},
"message": "2023/07/25 15:24:11 [notice] 1#1: start worker process 35",
"service": {
"name": "myservice",
"version": "v0.1.0"
}
},
{
"data_stream": {
"dataset": "kubernetes.container_logs.nginx",
"namespace": "nginx",
"type": "logs"
},
"kubernetes": {
"annotations": {
"elastic_co/dataset": "kubernetes.container_logs.nginx",
"elastic_co/namespace": "nginx"
},
"labels": {
"app_kubernetes_io/name": "myservice",
"app_kubernetes_io/version": "v0.1.0"
}
},
"message": "2023/07/25 15:24:11 [notice] 1#1: using the \"epoll\" event method",
"service": {
"name": "myservice",
"version": "v0.1.0"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,43 @@ parsers:
format: {{ containerParserFormat }}
{{ additionalParsersConfig }}

{{#if processors}}
processors:
{{!
Why do we need to add the following processors?
-----------------------------------------------

The kubernetes provider supports[^1] pods annotations, making it possible to add
them to the event using the `include_annotations` configuration option.

However, adding annotations to the event is disabled by default, and it is
not possible to enable it on Fleet-managed agents.

The following processors are a workaround to add the annotations to the event
without using the `include_annotations` configuration option.


[^1]: https://github.com/elastic/elastic-agent/blob/37ec2bb7ee1d2cc6c0fccf2f0cd0a44eb3d61efd/internal/pkg/composable/providers/kubernetes/pod.go#L311-L315
}}
- add_fields:
target: kubernetes
fields:
annotations.elastic_co/dataset: ${kubernetes.annotations.elastic.co/dataset|""}
annotations.elastic_co/namespace: ${kubernetes.annotations.elastic.co/namespace|""}
- drop_fields:
fields:
- kubernetes.annotations.elastic_co/dataset
when:
equals:
kubernetes.annotations.elastic_co/dataset: ""
ignore_missing: true
- drop_fields:
fields:
- kubernetes.annotations.elastic_co/namespace
when:
equals:
kubernetes.annotations.elastic_co/namespace: ""
ignore_missing: true
{{#if processors}}
{{processors}}
{{/if}}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
description: Pipeline for Kubernetes container logs
processors:
- set:
field: service.name
copy_from: kubernetes.labels.app_kubernetes_io/name
ignore_empty_value: true
- set:
field: service.name
copy_from: kubernetes.container.name
override: false
ignore_empty_value: true
- set:
field: service.version
copy_from: kubernetes.labels.app_kubernetes_io/version
ignore_empty_value: true
on_failure:
- set:
field: event.kind
value: pipeline_error
- append:
field: error.message
value: '{{{ _ingest.on_failure_message }}}'
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@
name: orchestrator.cluster.name
- external: ecs
name: orchestrator.cluster.url
- external: ecs
name: service.name
- external: ecs
name: service.version
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
title: "Kubernetes container logs"
type: logs
dataset: kubernetes.container_logs
streams:
- input: filestream
title: Collect Kubernetes container logs
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Route container logs events to the correct dataset and namespace
# based on pod annotations.
- source_dataset: kubernetes.container_logs
rules:
- target_dataset:
- "{{kubernetes.annotations.elastic_co/dataset}}"
- "{{data_stream.dataset}}"
namespace:
- "{{kubernetes.annotations.elastic_co/namespace}}"
- "{{data_stream.namespace}}"
if: "ctx.kubernetes?.annotations != null"
8 changes: 8 additions & 0 deletions packages/kubernetes/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ the masters won't be visible. In these cases it won't be possible to use `schedu
The container-logs dataset requires access to the log files in each Kubernetes node where the container logs are stored.
This defaults to `/var/log/containers/*${kubernetes.container.id}.log`.

#### Routing

The container-logs data stream allows routing logs to a different *dataset* or *namespace* using pod annotations.

For example, suppose you are running Nginx on your Kubernetes cluster, and you want to drive the Nginx container logs into a dedicated dataset or namespace. By annotating the pod with `elastic.co/namespace: nginx`, the integration will send all the container logs to the `nginx` namespace.

To learn more about routing container-logs, see https://docs.elastic.co/integrations/kubernetes/container-logs.

### audit-logs

The audit-logs dataset requires access to the log files on each Kubernetes node where the audit logs are stored.
Expand Down
Loading