Splunk Universal Forwarder у докері як збирач системних логів

Splunk Universal Forwarder у докері як збирач системних логів

Splunk одна із кількох найбільш відомих комерційних товарів для збирання й аналізу логів. Навіть зараз, коли продажі у Росії більше не виробляються, це не привід не писати інструкції/how-to щодо цього продукту.

Завдання: збирати системні логи з docker нод у Splunk не змінюючи конфігурацію хост-машини

Почати хотілося б з офіційного підходу, який виглядає дивним при використанні докеру.
Посилання на Docker hub
Що ж ми маємо:

1. Пулімо образ

$ docker pull splunk/universalforwarder:latest

2. Стартуємо контейнер із потрібними параметрами

$ docker run -d  -p 9997:9997 -e 'SPLUNK_START_ARGS=--accept-license' -e 'SPLUNK_PASSWORD=<password>' splunk/universalforwarder:latest

3. Заходимо у контейнер

docker exec -it <container-id> /bin/bash

Далі нас просять пройти за відомою адресою до документації.

І конфігурувати контейнер після його запуску:


./splunk add forward-server <host name or ip address>:<listening port>
./splunk add monitor /var/log
./splunk restart

Зачекайте. Що?

Але на цьому сюрпризи не закінчуються. Якщо ви запустите контейнер з офіційного образу в інтерактивному режимі, побачите наступне:

Трохи розчарування


$ docker run -it -p 9997:9997 -e 'SPLUNK_START_ARGS=--accept-license' -e 'SPLUNK_PASSWORD=password' splunk/universalforwarder:latest

PLAY [Run default Splunk provisioning] *******************************************************************************************************************************************************************************************************
Tuesday 09 April 2019  13:40:38 +0000 (0:00:00.096)       0:00:00.096 *********

TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [localhost]
Tuesday 09 April 2019  13:40:39 +0000 (0:00:01.520)       0:00:01.616 *********

TASK [Get actual hostname] *******************************************************************************************************************************************************************************************************************
changed: [localhost]
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.599)       0:00:02.215 *********
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.054)       0:00:02.270 *********

TASK [set_fact] ******************************************************************************************************************************************************************************************************************************
ok: [localhost]
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.075)       0:00:02.346 *********
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.067)       0:00:02.413 *********
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.060)       0:00:02.473 *********
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.051)       0:00:02.525 *********
Tuesday 09 April 2019  13:40:40 +0000 (0:00:00.056)       0:00:02.582 *********
Tuesday 09 April 2019  13:40:41 +0000 (0:00:00.216)       0:00:02.798 *********
included: /opt/ansible/roles/splunk_common/tasks/change_splunk_directory_owner.yml for localhost
Tuesday 09 April 2019  13:40:41 +0000 (0:00:00.087)       0:00:02.886 *********

TASK [splunk_common : Update Splunk directory owner] *****************************************************************************************************************************************************************************************
ok: [localhost]
Tuesday 09 April 2019  13:40:41 +0000 (0:00:00.324)       0:00:03.210 *********
included: /opt/ansible/roles/splunk_common/tasks/get_facts.yml for localhost
Tuesday 09 April 2019  13:40:41 +0000 (0:00:00.094)       0:00:03.305 *********

ну и так далее...

Чудово. В образі навіть немає артефакту. Тобто щоразу при запуску витрачатиметься час, щоб викачати архів із бінарниками, розпакувати та налаштувати.
А як же docker-way і таке інше?

Ні дякую. Ми підемо іншим шляхом. Що, якщо всі ці операції ми виконаємо на етапі збирання? Тоді поїхали!

Щоб довго не тягнути, покажу одразу підсумковий образ:

Докер-файл

# Тут у кого какие предпочтения
FROM centos:7

# Задаём переменные, чтобы каждый раз при старте не указывать их
ENV SPLUNK_HOME /splunkforwarder
ENV SPLUNK_ROLE splunk_heavy_forwarder
ENV SPLUNK_PASSWORD changeme
ENV SPLUNK_START_ARGS --accept-license

# Ставим пакеты
# wget - чтобы скачать артефакты
# expect - понадобится для первоначального запуска Splunk на этапе сборки
# jq - используется в скриптах, которые собирают статистику докера
RUN yum install -y epel-release 
    && yum install -y wget expect jq

# Качаем, распаковываем, удаляем
RUN wget -O splunkforwarder-7.2.4-8a94541dcfac-Linux-x86_64.tgz 'https://www.splunk.com/bin/splunk/DownloadActivityServlet?architecture=x86_64&platform=linux&version=7.2.4&product=universalforwarder&filename=splunkforwarder-7.2.4-8a94541dcfac-Linux-x86_64.tgz&wget=true' 
    && wget -O docker-18.09.3.tgz 'https://download.docker.com/linux/static/stable/x86_64/docker-18.09.3.tgz' 
    && tar -xvf splunkforwarder-7.2.4-8a94541dcfac-Linux-x86_64.tgz 
    && tar -xvf docker-18.09.3.tgz  
    && rm -f splunkforwarder-7.2.4-8a94541dcfac-Linux-x86_64.tgz 
    && rm -f docker-18.09.3.tgz

# С shell скриптами всё понятно, а вот inputs.conf, splunkclouduf.spl и first_start.sh нуждаются в пояснении. Об этом расскажу после source тэга.
COPY [ "inputs.conf", "docker-stats/props.conf", "/splunkforwarder/etc/system/local/" ]
COPY [ "docker-stats/docker_events.sh", "docker-stats/docker_inspect.sh", "docker-stats/docker_stats.sh", "docker-stats/docker_top.sh", "/splunkforwarder/bin/scripts/" ]
COPY splunkclouduf.spl /splunkclouduf.spl
COPY first_start.sh /splunkforwarder/bin/

#  Даём права на исполнение, добавляем пользователя и выполняем первоначальную настройку
RUN chmod +x /splunkforwarder/bin/scripts/*.sh 
    && groupadd -r splunk 
    && useradd -r -m -g splunk splunk 
    && echo "%sudo ALL=NOPASSWD:ALL" >> /etc/sudoers 
    && chown -R splunk:splunk $SPLUNK_HOME 
    && /splunkforwarder/bin/first_start.sh 
    && /splunkforwarder/bin/splunk install app /splunkclouduf.spl -auth admin:changeme 
    && /splunkforwarder/bin/splunk restart

# Копируем инит скрипты
COPY [ "init/entrypoint.sh", "init/checkstate.sh", "/sbin/" ]

# По желанию. Кому нужно локально иметь конфиги/логи, кому нет.
VOLUME [ "/splunkforwarder/etc", "/splunkforwarder/var" ]

HEALTHCHECK --interval=30s --timeout=30s --start-period=3m --retries=5 CMD /sbin/checkstate.sh || exit 1

ENTRYPOINT [ "/sbin/entrypoint.sh" ]
CMD [ "start-service" ]

І так, що ж міститься в

first_start.sh

#!/usr/bin/expect -f
set timeout -1
spawn /splunkforwarder/bin/splunk start --accept-license
expect "Please enter an administrator username: "
send -- "adminr"
expect "Please enter a new password: "
send -- "changemer"
expect "Please confirm new password: "
send -- "changemer"
expect eof

При першому старті, Splunk просить задати йому логін/пароль, АЛЕ ці дані використовуються лише виконання адміністративних команд цієї конкретної інсталяції, тобто, всередині контейнера. У нашому випадку ми просто хочемо запустити контейнер, щоб все працювало і логи лилися річкою. Звичайно, це хардкод, але я не знайшов інших способів.

Далі за сценарієм виконується

/splunkforwarder/bin/splunk install app /splunkclouduf.spl -auth admin:changeme

splunkclouduf.spl — Це файл креди для Splunk Universal Forwarder, які можна завантажити із веб-інтерфейсу.

Куди натискати щоб скачатиSplunk Universal Forwarder у докері як збирач системних логів

Splunk Universal Forwarder у докері як збирач системних логів
Це звичайний архів, який можна розпакувати. Усередині – сертифікати та пароль для підключення до нашого SplunkCloud та outputs.conf зі списком наших вхідних інстансів. Цей файл буде актуальним до тих пір, поки ви не встановите інсталяцію Splunk або не додайте input нод, якщо інсталяція on-premise. Тому нічого страшного немає в тому, щоб додати його до контейнера.

І останнє – restart. Так, для застосування змін потрібно його рестартанути.

В наш inputs.conf додаємо логи, які ми хочемо відправляти до Splunk. Необов'язково додавати цей файл образ, якщо ви, наприклад, розкидаєте конфіги через puppet. Головне лише в тому, щоб Forwarder бачив конфіги, при старті демона, інакше буде потрібно ./splunk restart.

А що це за docker stats скрипти? На гітхабі є старе рішення від outcoldman, скрипти взято звідти та доопрацьовано для роботи з актуальними версіями Docker (ce-17.*) та Splunk (7.*).

З отриманими даними можна будувати такі

дешборди: (пара картинок)Splunk Universal Forwarder у докері як збирач системних логів

Splunk Universal Forwarder у докері як збирач системних логів
Вихідний код дешей лежить у ріпі, вказаній наприкінці статті. Зверніть увагу, що там є 2 select поля: 1 — вибір індексу (шукаються по масці), вибір хоста/контейнера. Маску індексу швидше за все вам доведеться оновити, залежно від імен, які ви використовуєте.

На завершення хочу звернути увагу на функцію start () в

entrypoint.sh

start() {
    trap teardown EXIT
	if [ -z $SPLUNK_INDEX ]; then
	echo "'SPLUNK_INDEX' env variable is empty or not defined. Should be 'dev' or 'prd'." >&2
	exit 1
	else
	sed -e "s/@index@/$SPLUNK_INDEX/" -i ${SPLUNK_HOME}/etc/system/local/inputs.conf
	fi
	sed -e "s/@hostname@/$(cat /etc/hostname)/" -i ${SPLUNK_HOME}/etc/system/local/inputs.conf
    sh -c "echo 'starting' > /tmp/splunk-container.state"
	${SPLUNK_HOME}/bin/splunk start
    watch_for_failure
}

У моєму випадку, для кожного оточення та кожної окремої сутності, будь то додаток у контейнері або хост-машина, ми використовуємо окремий індекс. Так не страждатиме швидкість пошуку при значному накопиченні даних. Для іменування індексів використовується просте правило: _. Тому, щоб контейнер був універсальним, ми перед запуском безпосередньо демона замінюємо sed-й wildcard на ім'я оточення. Змінна з ім'ям оточення передається через змінні оточення. Звучить кумедно.

Також варто відзначити момент, що з якоїсь причини Splunk не впливає наявність docker параметра ім'я хоста. Він все одно буде упорото надсилати логи з id свого контейнера в полі host. Як рішення можна монтувати / etc / hostname з хост-машини і при старті робити заміну, аналогічну до імен індексів.

Приклад docker-compose.yml

version: '2'
services:
  splunk-forwarder:
    image: "${IMAGE_REPO}/docker-stats-splunk-forwarder:${IMAGE_VERSION}"
    environment:
      SPLUNK_INDEX: ${ENVIRONMENT}
    volumes:
    - /etc/hostname:/etc/hostname:ro
    - /var/log:/var/log
    - /var/run/docker.sock:/var/run/docker.sock:ro

Підсумок

Так, можливо, рішення не ідеальне і точно не універсальне для всіх, так як є багато «хардкод». Але на основі нього кожен може зібрати свій образ і покласти його у свій приватний артифактор, якщо, так вже трапилося, вам необхідний Splunk Forwarder саме в докері.

Посилання:

Рішення із статті
Рішення від outcoldman надихнуло перевикористовувати частину функціоналу
Оф. документація з налаштування Universal Forwarder

Джерело: habr.com

Додати коментар або відгук