Rsyslog - высокопроизводительный обработчик логов. Может использоваться в качестве агента на уровне сервера и агента журналирования на уровне пода.
Содержание
Изначально проектировался как syslog процесс. За время жизни эволюционировал в универсальный инструмент с расширяемым модульным дизайном. Использует язык ruby для конфигурирования.
Архитектура Rsyslog состоит из 3-х основных модулей: ввода, обработки и вывода. Модули реализуются в виде внешних подключаемых зависимостей - плагинов.
Позволяют получать сообщения из различных источников. К основным можно отнести:
journal
- журнал операционной системы; klog
- журнал ядра операционной системы; file
- чтение файла из файловой системы. Позволяют преобразовывать входящие сообщения. К основным можно отнести:
mmkubernetes
- позволяет дополнять входящие сообщения метаданными о поде;mmjsonparse
- позволяет модифицировать входящие json сообщения;mmfields
- позволяет выделять поля из входящих сообщений и использовать их для записи в другой формат;Позволяют отправлять сообщения в различные системы хранения. К основным можно отнести:
file
- записывать сообщения в файл;pgsql
- сохранять сообщения в PostgreSQL;elasticsearch
- сохранять сообщения в Elasticsearch;mongodb
- сохранять сообщения в MongoDB.Существует несколько подходов к cluster-level журналированию в kubernetes. Rsyslog можно применять в любом, но для упрощения примера будет использован подход журналирования на уровне сервера.
В зависимости от версии kubernetes могут быть использованы разные драйверы записи логов docker контейнера. Определить какой драйвер использован можно с помощью команды docker info:
~ % docker info --format '{{.LoggingDriver}}'
journald
Если используется драйвер journald
требуется включить перенаправление логов в unix socket в файле/etc/systemd/journald.conf
:
[Journal]
ForwardToSyslog=yes
После чего перезапустить сервис systemd-journald
:
~ % systemctl restart systemd-journald
За основу взят образ rsyslog-docker. Для получения метаинформации о поде из api-server дополнительно требуется плагин mm-kubernetes, поэтому его необходимо дополнительно установить в базовый образ:
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update \
&& apt-get -y upgrade \
&& apt-get -y install software-properties-common curl \
&& add-apt-repository -y ppa:adiscon/v8-stable \
&& apt-get -y update \
&& apt-get -y install libfastjson4 \
rsyslog \
rsyslog-mmkubernetes \
rsyslog-elasticsearch \
rsyslog-imptcp \
rsyslog-relp \
rsyslog-mmjsonparse \
rsyslog-mmutf8fix \
rsyslog-omstdout \
&& apt-get clean \
&& rm -r /etc/rsyslog.conf
ADD rsyslog.conf /etc/rsyslog.conf
#VOLUME /rsyslog-bin
RUN mkdir /rsyslog-bin \
&& cp /usr/sbin/rsyslogd /usr/lib/rsyslog/* /rsyslog-bin
EXPOSE 10514
WORKDIR /rsyslog-bin
CMD ["/rsyslog-bin/rsyslogd", "-n", "-f/etc/rsyslog.conf", "-M."]
И подготовить файл конфигурации rsyslog.conf
с настроенным шаблоном записи:
module(load="imuxsock" SysSock.Annotate="on" SysSock.ParseTrusted="on")
# Модуль mmkubernetes использует адрес https://kubernetes.default.svc.cluster.local/.
# Параметр KubernetesURL позволяет его изменить
module(load="mmkubernetes"
tls.cacert="/run/secrets/kubernetes.io/serviceaccount/ca.crt"
tokenfile="/run/secrets/kubernetes.io/serviceaccount/token"
# По умолчанию лейблы и аннотации не добавляются к сообщениям
annotation_match=["."])
module(load="omstdout")
# Для сбора логов используется unix socket /run/systemd/journal/syslog.
# Эта директория должна быть смонтирована из хостовой операционной системы
input(type="imuxsock" Socket="/run/systemd/journal/syslog" CreatePath="on")
# Запрос информации о поде у api-server
action(type="mmkubernetes")
# Объявление шаблона для записи сообщений
template(name="k8s-msg" type="list" option.jsonf="on") {
property(outname="priority" name="PRI" format="jsonf")
property(outname="@timestamp" name="TIMESTAMP" dateFormat="rfc3339" date.inUTC="on" format="jsonf")
property(outname="namespace" name="!kubernetes!namespace_name" format="jsonf")
property(outname="pod_name" name="!kubernetes!pod_name" format="jsonf")
property(outname="pod_id" name="!kubernetes!pod_id" format="jsonf")
property(outname="container_name" name="!kubernetes!container_name" format="jsonf")
property(outname="container_id" name="!kubernetes!container_id" format="jsonf")
property(name="msg" droplastlf="on" format="jsonf")
}
# Запись обработанных сообщений в файл
action(type="omfile" file="/var/log/rsyslog/k8s.log" template="k8s-msg")
Для лучшего понимания шаблонов обратитесь к статье "Использование шаблонов в Rsyslog"
Сборка docker образа выполняется с помощью команды docker build
:
~ % docker build -f Dockerfile influunt/rsyslog:8.36.0-3.7
Образ можно опубликовать в docker hub, или экспортировать для дальнейшего распространения по узлам:
~ % docker save influunt/rsyslog:8.36.0-3.7 > rsyslog-8.36.0-3.7.tar
~ % docker load < rsyslog-8.36.0-3.7.tar
Для журналирования на уровне сервера лучше всего подходит daemon set. При добавлении новых узлов в кластер kubernetes сам позаботится о запуске rsyslog.
Манифест основан на ранее собранном образе influunt/rsyslog:8.36.0-3.7
и монтирует хост директорию /run/systemd/journal
для интеграции rsyslog с systemd-journald через unix socket файл /run/systemd/journal/syslog
:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: rsyslog
namespace: kube-system
labels:
k8s-app: rsyslog
spec:
selector:
matchLabels:
k8s-app: rsyslog
template:
metadata:
labels:
k8s-app: rsyslog
spec:
priorityClassName: system-node-critical
containers:
- name: rsyslog
image: influunt/rsyslog:8.36.0-3.7
securityContext:
privileged: true
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: journal-run
mountPath: /run/systemd/journal/
volumes:
- name: journal-run
hostPath:
path: /run/systemd/journal/
Установка и применение изменений производится с помощью команды kubectl apply
:
~ % kubectl apply -f rsyslog-ds.yaml
и после этого убедиться в успехе установки:
~ % kubectl -n kube-system get ds rsyslog
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
rsyslog 1 1 1 1 1 <none> 27s
~ % kubectl -n kube-system get pods -lk8s-app=rsyslog
NAME READY STATUS RESTARTS AGE
rsyslog-qjt5d 1/1 Running 0 30s
~ % kubectl -n kube-system exec -ti rsyslog-qjt5d -- tail -f /var/log/rsyslog/cee.log
{"priority":"14", "@timestamp":"2021-02-18T19:04:39.057120+00:00", "namespace":"kube-system", "pod_name":"ingress-nginx-b55d9556b-g54s8", "pod_id":"b55d9556b-g54s8", "container_name":"rsyslog", "container_id":"0394f7d4a7e9b369c31dfd788c1a098eee289e726ae1afce63dcbb080c562d68", "msg":" 10.10.0.1 - - [18\/Feb\/2021:19:04:39 +0000] \"GET \/ HTTP\/1.1\" 200 6 \"\" \"kube-probe\/1.20\""}
...
Тема логирования с помощью rsyslog обширна и не может быть раскрыта в рамках одной статьи. Разнообразие плагинов вывода позволяет использовать различные системы хранения. Для построения отказоустойчивой схемы можно передавать журналы через персистентную очередь Kafka или RabbitMQ.
Недостаток rsyslog в схеме cluster level журналирования - неустойчивость к отказам api server. Метаинформация, запрошенная у api server, кэшируется на все время жизни пода. Она не перезапрашивается в случае ошибки при ее запросе или её обновлении.