Skip to content

Commit

Permalink
Initial version (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-vovk authored Aug 17, 2024
1 parent 2201774 commit 4a42f3a
Show file tree
Hide file tree
Showing 13 changed files with 1,975 additions and 1 deletion.
34 changes: 34 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Release Charts

on:
push:
# branches:
# - main

jobs:
release:
# depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions
# see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"
- name: Install Helm
uses: azure/setup-helm@v4
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

- name: Run chart-releaser
uses: helm/[email protected]
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
test-helm-template
52 changes: 51 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
# kube-logs-sender-datadog
# Kubernetes ➡️ Datadog logs sender

Helm chart to set up sending logs from a Kubernetes cluster to Datadog. [Vector](https://vector.dev) is used under the
hood.

This is an example of how to use Vector to send logs to Datadog author couldn't find when
he was trying to set it up.
It's also the author's exercise to learn writing Helm charts.

It is based on Axiom's [instruction](https://axiom.co/docs/send-data/kubernetes) on setting up Vector.

## Features

* Lightweight and fast.
* Supports excluding logs from log collection by service name and log level.

## Installation
1. Create kubernetes secret with Datadog API key:
```shell
kubectl create secret generic datadog-api-key --from-literal=DD_API_KEY=<YOUR_DATADOG_API_KEY>
```
2. Add the Helm repository:
```shell
helm repo add kube-logs-datadog-sender https://raw.githubusercontent.com/igor-vovk/kube-logs-datadog-sender/main/helm
```
3. Install the chart:
```shell
helm install kube-logs-datadog-sender kube-logs-datadog-sender/kube-logs-datadog-sender
```


## Architecture

![Architecture](./docs/architecture-diagram.svg)

Sender-Aggregator pattern is used to send logs to Datadog:

* Senders are deployed on each node in the cluster. They collect logs from the node, process and filter them, and then
send logs to the aggregator.
* Aggregator collects logs from all senders and then sends them to Datadog.

## Points of Improvement

* Consider having thin senders and doing parsing and filtering in the aggregator instance.

## Referral Links

They help me to pay for the Datadog, so I can see my logs.

* [Hetzner Cloud](https://hetzner.cloud/?ref=iAnthJAtoQ8d) – best cloud provider with the cheapest prices in the EU
* [Bybit](https://www.bybit.nl/invite?ref=EVWANAG) – best crypto exchange
23 changes: 23 additions & 0 deletions charts/kube-logs-datadog-sender/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
7 changes: 7 additions & 0 deletions charts/kube-logs-datadog-sender/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v2
name: kube-logs-datadog-sender
description: Sends logs to Datadog

type: application
version: 0.1.0
appVersion: 0.1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---

apiVersion: v1
kind: ConfigMap

metadata:
name: vector-logs-aggregator-config
namespace: kube-system

data:
vector.yaml: |
api:
enabled: true
address: 0.0.0.0:8686
sources:
vector:
type: vector
address: 0.0.0.0:8685
transforms:
final_transform:
type: remap
inputs: [ vector ]
source: |
. = .
sinks:
datadog:
type: datadog_logs
inputs: [ final_transform ]
site: datadoghq.eu
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---

apiVersion: apps/v1
kind: Deployment

metadata:
name: vector-logs-aggregator
namespace: kube-system

spec:
selector:
matchLabels:
name: vector-logs-aggregator
template:
metadata:
labels:
name: vector-logs-aggregator
spec:
serviceAccountName: vector
containers:
- name: vector-logs-aggregator
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
args: [ "--config-dir", "/etc/vector/" ]
ports:
- containerPort: 8686
- containerPort: 8685
envFrom:
- secretRef:
name: {{ .Values.datadogSecretName | default "datadog-creds" }}
volumeMounts:
- mountPath: /etc/vector
name: config
livenessProbe:
httpGet:
path: /health
port: 8686
initialDelaySeconds: 3
periodSeconds: 3
resources:
requests:
memory: "100Mi"
cpu: "100m"
securityContext:
runAsUser: 0
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumes:
- name: config
configMap:
name: vector-logs-aggregator-config
restartPolicy: Always
terminationGracePeriodSeconds: 30

---

apiVersion: v1
kind: Service

metadata:
name: vector-logs-aggregator

spec:
selector:
name: vector-logs-aggregator
ports:
- name: source
port: 8685
targetPort: 8685
88 changes: 88 additions & 0 deletions charts/kube-logs-datadog-sender/templates/sender-configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---

apiVersion: v1
kind: ConfigMap

metadata:
name: vector-logs-sender-config
namespace: kube-system

data:
vector.yaml: |
api:
enabled: true
address: 0.0.0.0:8686
sources:
logs:
type: kubernetes_logs
self_node_name: ${VECTOR_SELF_NODE_NAME}
transforms:
sample_logs:
type: sample
inputs: [ logs ]
rate: 500
parse_json:
type: remap
inputs: [ logs ]
source: |
. = merge!(., parse_json(.message) ?? parse_key_value(.message) ?? {})
.@timestamp = del(.timestamp)
if exists(.msg) {
.message = del(.msg)
}
if exists(.logger_name) {
.logger_name_full = .logger_name
.logger_name = replace!(.logger_name, r'(?P<fl>\w)\w+\.', "$$fl.") # Convert `com.example.Foo` to `c.e.Foo`
}
.service = .kubernetes.container_name
.hostname = .kubernetes.pod_name
del(.file)
del(.kubernetes)
del(.@version)
del(.level_value)
del(.source_type)
del(.stream)
exclude_log_levels:
type: filter
inputs: [ parse_json ]
condition: |
!includes(
[
{{- range .Values.sender.exclude.logLevels }}
"{{ . }}",
{{- end }}
],
.level
)
exclude_services:
type: filter
inputs: [ exclude_log_levels ]
condition: |
!includes(
[
{{- range .Values.sender.exclude.services }}
"{{ . }}",
{{- end }}
],
.service
)
# Placeholder transform to always refer to the last transform in the sinks section
final_transform:
type: remap
inputs: [ exclude_services ]
source: |
. = .
sinks:
vector_aggregator:
type: vector
inputs: [ final_transform ]
address: vector-logs-aggregator.kube-system.svc.cluster.local:8685
#console:
# type: console
# inputs: [ final_transform ]
# encoding:
# codec: json
80 changes: 80 additions & 0 deletions charts/kube-logs-datadog-sender/templates/sender-daemonset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---

apiVersion: apps/v1
kind: DaemonSet

metadata:
name: vector-logs-sender
namespace: kube-system

spec:
selector:
matchLabels:
name: vector-logs-sender
template:
metadata:
labels:
name: vector-logs-sender
spec:
serviceAccountName: vector
containers:
- name: vector-logs-sender
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
args: [ "--config-dir", "/etc/vector/", "--require-healthy", "true" ]
ports:
- containerPort: 8686
env:
- name: VECTOR_SELF_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- mountPath: /etc/vector
name: config
- name: data-dir
mountPath: /var/lib/vector
- name: var-log
mountPath: /var/log
readOnly: true
- name: var-lib
mountPath: /var/lib
readOnly: true
livenessProbe:
httpGet:
path: /health
port: 8686
initialDelaySeconds: 3
periodSeconds: 3
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "500Mi"
securityContext:
runAsUser: 0
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumes:
- name: config
configMap:
name: vector-logs-sender-config
- name: data-dir
hostPath:
path: /var/lib/vector
type: DirectoryOrCreate
- name: var-log
hostPath:
path: /var/log
- name: var-lib
hostPath:
path: /var/lib
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: { }
terminationGracePeriodSeconds: 30
updateStrategy:
rollingUpdate:
maxUnavailable: 1
type: RollingUpdate
Loading

0 comments on commit 4a42f3a

Please sign in to comment.