Skip to content
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
k8s/
test/
Makefile
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test/test.sh -text eol=lf
start.sh -text eol=lf

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.k3d*
.helm-setup
9 changes: 6 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
FROM centos:7
FROM alpine:3.13.5
ENV RSYSLOG_PORT=514 RSYSLOG_PROTOCOL=udp

RUN curl -s -L -o /etc/yum.repos.d/rsyslog.repo http://rpms.adiscon.com/v8-stable/rsyslog.repo
RUN yum -y install rsyslog gettext && yum clean all
RUN apk add --no-cache rsyslog gettext

COPY rsyslog.conf.template /etc/rsyslog.conf.template
COPY start.sh /start.sh

# So we can make the root file system read-only
RUN ln -sf /var/lib/rsyslog/rsyslog.conf /etc/rsyslog.conf

RUN chmod +x /start.sh

CMD /start.sh
87 changes: 87 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
IMAGE=localhost:5000/syslog-agent
DEFAULT_METRICS=kube-state-metrics
LOCAL_PORT=8081

## make build -- build the image
build: .k3d-image

.k3d-image: Dockerfile start.sh rsyslog.conf.template
docker build -t $(IMAGE) .
@touch $@

## make push -- push the image to the local k3d registry
push: .k3d-registry .k3d-image
docker push $(IMAGE)

## make test -- install all components and run a simple test by cURLing the NGINX container and looking for the access record
test: build up k8s ready
bash test/test.sh

## run a Snyk scan on the image
scan:
docker scan $(IMAGE)

## make k8s or make deploy -- install the components into the cluster
k8s deploy: push .k3d
kubectl apply -f k8s -f test

## make up -- create and configure the testing cluster
k3d-up k3d cluster cluster-up up: .k3d

## make down -- delete the testing cluster
k3d-down cluster-down down:
k3d cluster delete syslog
k3d registry delete local
rm -f .k3d-*

## make ready -- wait for all components to be ready
ready:
@echo -n "Waiting for pod count..."
@while [ "$$(kubectl get pods -A | wc -l)" -lt 4 ] ; do sleep 2; echo -n .; done || true
@echo "DONE"
@echo -n "Waiting for pods ready..."
@while kubectl get pods -A | grep -q -E 'Pending|ContainerCreating'; do sleep 2; echo -n . ; done || true
@echo "READY"

.k3d: .k3d-cluster .k3d-kube-state-metrics

.k3d-cluster: .k3d-registry
k3d cluster create syslog -p "$(LOCAL_PORT):80@loadbalancer" --registry-use local
# @echo "Waiting for cluster to initialize"
# @while [ -n "kubectl get -n kube-system pods | grep ContainerCreating" ]; do echo -n "."; sleep 3; done
# @echo DONE
touch $@

.k3d-registry:
k3d registry create local -p 5000
touch $@


# Install the selected metrics server package
metrics: .k3d-$(DEFAULT_METRICS)

.k3d-kube-state-metrics: .helm-setup
helm install -n kube-system metrics prometheus-community/kube-state-metrics
touch $@

.k3d-prometheus:
helm install -n kube-system prometheus prometheus-community/kube-prometheus-stack
touch $@ .k3d-kube-state-metrics

# Run a local helm setup
helm: .helm-setup

.helm-setup:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
touch $@

clean:
-make -f $(lastword $(MAKEFILE_LIST)) down >/dev/null 2>/dev/null
rm -f .helm-setup

real-clean: clean
docker image rm $(IMAGE)

help:
awk '/^##/{print}' $(lastword $(MAKEFILE_LIST))
30 changes: 23 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
# Kubernetes Container Log Syslog Forwarder

This container is designed to run as a DaemonSet and forwards pod logs to a syslog
listener for all pods running on a node. Log forwarding is implemented with
[RSYSLOG](http://www.rsyslog.com/) and uses [omfwd](http://www.rsyslog.com/doc/v8-stable/configuration/modules/omfwd.html) module.
This container is designed to run as a DaemonSet and forwards pod logs to a syslog listener for all
pods running on a node. Log forwarding is implemented with
[RSYSLOG](http://www.rsyslog.com/) and
uses [omfwd](http://www.rsyslog.com/doc/v8-stable/configuration/modules/omfwd.html) module.

## Configuration Options

Configuration can be done with environment variables:

* **RSYSLOG_TARGET** - Remote syslog listener
* **RSYSLOG_PORT** - Remote syslog listener port
* **RSYSLOG_PROTOCOL** - Remote syslog listener protocol (udp/tcp)

## Example DaemonSet
DaemonSet example requires a privileged SCC if using k8s v1.5+ or OpenShift and
probably needs rsyslog already installed in order to use /var/lib/rsyslog on the
host as the place for the file state directory
## DaemonSet

A working example of a deployment daemonset can be found in the [k8s](./k8s) directory, along with
an example ConfigMap. You will need to adjust the configmap to suit your system.

## Hacking

The `Makefile` included here is set up to assist development *and* testing of the system,
using [`k3d`](https://k3d.io/). It will fully set up a test cluster, install all necessary
components, and run a simple test.

Use `make test` to perform all of these

**NOTE:** there is currently an occasional timing issue where the test will fail right after the
cluster is up. If this happens, wait 30 seconds and attempt `make test` again.

Use `make help` to display information about available targets

39 changes: 39 additions & 0 deletions k8s/agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: syslog-agent
labels:
app: syslog-agent
spec:
selector:
matchLabels:
app: syslog-agent
template:
metadata:
labels:
app: syslog-agent
spec:
containers:
- name: syslog-agent
image: k3d-local:5000/syslog-agent
envFrom:
- configMapRef:
name: syslog-agent-config
volumeMounts:
- mountPath: /var/log
name: logs
readOnly: true
- mountPath: /var/lib/rsyslog
name: work
securityContext:
readOnlyRootFilesystem: true
volumes:
- name: logs
hostPath:
path: /var/log
- name: work
emptyDir: {}




8 changes: 8 additions & 0 deletions k8s/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: syslog-agent-config
data:
RSYSLOG_PORT: "514"
RSYSLOG_PROTOCOL: UDP
RSYSLOG_TARGET: rsyslog
8 changes: 3 additions & 5 deletions start.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#!/bin/bash
#!/bin/sh

rm -f /etc/rsyslog.conf
envsubst < /etc/rsyslog.conf.template > /var/lib/rsyslog/rsyslog.conf

envsubst < /etc/rsyslog.conf.template > /etc/rsyslog.conf

exec /sbin/rsyslogd -n
exec /usr/sbin/rsyslogd -n
59 changes: 59 additions & 0 deletions test/nginx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
resources: {}
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- name: 80-80
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP
---
# apiVersion: networking.k8s.io/v1beta1 # for k3s < v1.19
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
59 changes: 59 additions & 0 deletions test/rsyslog.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
apiVersion: v1
kind: Service
metadata:
name: rsyslog
labels:
app: rsyslog
spec:
selector:
app: rsyslog
ports:
- protocol: UDP
port: 514
targetPort: 514
name: syslog-udp
- protocol: TCP
port: 514
targetPort: 514
name: syslog-tcp
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: rsyslog
name: rsyslog
spec:
replicas: 1
selector:
matchLabels:
app: rsyslog
template:
metadata:
labels:
app: rsyslog
spec:
containers:
- image: voxxit/rsyslog
name: rsyslog
ports:
- containerPort: 514
protocol: UDP
name: syslog-udp
- containerPort: 514
protocol: TCP
name: syslog-tcp
env:
- name: TZ
value: America/New_York
livenessProbe:
tcpSocket:
port: 514
readinessProbe:
exec:
command:
- test
- -s
- /var/log/messages

15 changes: 15 additions & 0 deletions test/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# purpose: test the k8s cluster to see if a log message gets through

DATE=$(date +%y%m%d%H%M%S)
curl -s "http://localhost:8081/testing/${DATE}" > /dev/null

pod=$(kubectl get pods -l app=rsyslog | awk '!/NAME/{print $1}')
if kubectl exec "$pod" -- grep -q "testing/${DATE}" /var/log/messages
then
echo "PASS"
else
echo "FAIL"
exit 1
fi