Доступ к сообщениям журнала ядра при переходе ядра Linux в режим паники

Часто встречающаяся ситуация: виртуальный или аппаратный сервер завис и не отвечает. Заходите на него с помощью инструмента удаленного управления IPMI или консоли VNC, видите только черный экран и ничего кроме. Скорее всего, ядро Linux вошло в режим паники (Kernel Panic), который вызван сбоем одного из модулей ядра, ошибкой в самом ядре, критической аппаратной ошибкой.

Вы перезагружаете сервер, ищите журналы на предмет релевантных сообщений, а в ответ пустота — ничего криминального нет. На самом деле, сообщения сопровождающую возникшую ошибку были, но они не дошли до файла журнала. Связано это с тем, что, когда ядро Linux сталкивается с критической ситуацией, особенно, если она связана с файловой системой, то ему не удается использовать модули файловых систем, чтобы записать данные в файл журнала. Как результат, записи, сопровождающие ошибку теряются.

В лучшем случае, вы сможете увидеть сообщение об ошибке на экране монитора и сделать снимок экрана, но часто вы не видите даже этого.

В этой статье мы познакомимся с методом, который позволяет решить проблему журналирования сообщений ядра при возникновении ситуации паники ядра Linux.

Для решения этой задачи мы воспользуемся специальным модулем ядра Netconsole, который позволяет отправить предсмертные сообщения ядра на удаленный сервер syslog.

Метод не очень широко известен, но чрезвычайно полезен для полноценной диагностики серверов Linux, когда их ядро сталкивается с ситуациями, последствием которых является переход в режим паники с остановкой всех сервисов.

Все примеры в данной статье будут приводиться для серверов, работающих под управлением Ubuntu Linux, однако, для других дистрибутивов настройка практически полностью повторяется.

В рамках инструкции будем использовать два сервера:

  • panic с ip: 10.0.0.2;
  • monitor с ip: 10.0.0.1.

На сервере panic мы настроим netconsole и будем имитировать ситуацию паники ядра. На сервере monitor мы настроим rsyslogd для поддержки удаленного журналирования по протоколу udp. Начнем с настройки узла monitor.

Настройка Rsyslog на узле monitor

Мы ограничимся минимальной настройкой, решающей задачу. В случае, если журналирование используется для многих серверов, рекомендуется настроить организацию журналов по имени сервера. Для того, чтобы сервис Rsyslog мог принимать сообщения от удаленных серверов, в файле /etc/rsyslog.conf необходимо раскомментировать строки, отвечающие за активацию модуля, обрабатывающего внешние события, приходящие по протоколу UDP:

module(load="imudp")
input(type="imudp" port="514")

Сохраните файл и перезапустите rsyslogd:

$ sudo service rsyslog restart

убедимся, что rsyslog слушает порт 514 по протоколу UDP:

$ sudo netstat -nlp | grep 514
udp   0      0 0.0.0.0:10514           0.0.0.0:*         4446/rsyslogd
udp6  0      0 :::10514                     :::*         4446/rsyslogd   

Настройка практически завершена, однако, так как при использовании удаленного журналирования отсутствуют встроенные механизмы верификации источника данных, подходящие при использовании netconsole, мы будем использовать iptables для ограничения трафика от неизвестных источников.

Настройка Iptables на узле monitor

Разрешим доступ к rsyslogd только с хоста 10.0.0.2 с порта 10002, откуда будут отправляться сообщения при возникновении критической ситуации ядра.

Установим пакет iptables-persistent.

$ sudo apt update && sudo apt install iptables-persistent netfilter-persistent

Если вы предпочитаете для настройки использовать UFW, можете использовать этот инструмент. Мы подразумеваем, что используются настройки iptables, по умолчанию пропускающие весь трафик, поэтому будем использовать запрещающие правила.

$ sudo iptables -A INPUT -p udp --destination-port 514 -s 176.120.28.219 --source-port 10000 -j ACCEPT
$ sudo iptables -A INPUT -p udp --destination-port 514 -j DROP
$ sudo ip6tables -A INPUT -p udp --destination-port 514 -j DROP

Добавим сохранение правил в iptables-persistent:

$ sudo netfilter-persistent save

Если вы используете приложения, которые добавляют свои правила, например, fail2ban или docker, удалите правила этих приложений из созданных файлов /etc/iptables/rules.v4, /etc/iptables/rules.v6. Например, для fail2ban необходимо удалить правила:

-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A f2b-sshd -j RETURN

Для проверки корректности настроек перезагрузите сервер monitor и после завершения загрузки проверьте наличие в iptables всех нужных правил с помощью команд iptables-save и ip6tables-save:

$ sudo iptables-save 
# Generated by iptables-save v1.6.0 on Tue Mar 26 02:15:33 2019
*filter
:INPUT ACCEPT [822:79695]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [517:55062]
-A INPUT -s 176.120.28.219/32 -p udp -m udp --sport 10000 --dport 514 -j ACCEPT
-A INPUT -p udp -m udp --dport 514 -j DROP
COMMIT
# Completed on Tue Mar 26 02:15:33 2019

$ sudo ip6tables-save 
# Generated by ip6tables-save v1.6.0 on Tue Mar 26 02:15:37 2019
*filter
:INPUT ACCEPT [75:6880]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [82:7304]
-A INPUT -p udp -m udp --dport 514 -j DROP
COMMIT
# Completed on Tue Mar 26 02:15:37 2019

На этом настройку хоста monitor считаем законченной. Перейдем к настройке хоста panic.

Настройка модуля netconsole на узле panic

В документации ядра Linux к модулю netconsole можно увидеть, что модуль принимает следующие настройки:

netconsole=[+][src-port]@[src-ip]/[<dev>],[tgt-port]@<tgt-ip>/[tgt-macaddr]

разберем каждую из них:

  • + — netconsole будет использовать “extended” режим, при котором передаются метаданные, помимо самих сообщений, а также не-ASCII символы;
  • src-port — порт на локальном сервере с которого будут отправляться сообщения, по умолчанию 6665;
  • src-ip — ip4 или ip6 адрес, принадлежащий серверу, с которого будут отправляться сообщения;
  • dev — имя локального сетевого устройства, в которое будут отправляться сообщения;
  • tgt-port — порт сервера syslog или другого приложения, принимающего сообщения, по умолчанию 6666;
  • tgt-ip — ip4, ip6 адрес сервера, который будет принимать сообщения;
  • tgt-macaddr — mac-адрес сервера, который принимает сообщения.

как можно видеть, параметры, кроме tgt-ip опциональны, но мы зададим их все для большей ясности.

Модуль netconsole может работать в двух режимах — статической конфигурации и динамической конфигурации, когда вы можете добавлять дополнительные цели отправки сообщений через /sys. У нас такой задачи нет, поэтому мы будем использовать статическую конфигурацию. За подробностями настройки netconsole в режиме динамической конфигурации обратитесь к документации модуля.

Настройка модуля заключается в правке двух файлов — /etc/modules и /etc/modprobe.d/netconsole.conf (замените MAC AA:BB:CC:DD:EE:FF на реальный MAC сервера monitor, которому соответствует IP 10.0.0.1):

$ sudo echo netconsole >> /etc/modules
$ sudo echo “options netconsole netconsole=10002@10.0.0.2/eth0,514@10.0.0.1/AA:BB:CC:DD:EE:FF” > /etc/modprobe.d/netconsole.conf

После выполнения этих операций загрузим модуль в память:

$ sudo dmesg -c
…
$ sudo modprobe neconsole
$ sudo dmesg
[ 1007.501492] netpoll: netconsole: local port 10002
[ 1007.501499] netpoll: netconsole: local IPv4 address 10.0.0.2
[ 1007.501501] netpoll: netconsole: interface 'eth0'
[ 1007.501502] netpoll: netconsole: remote port 514
[ 1007.501503] netpoll: netconsole: remote IPv4 address 10.0.0.1
[ 1007.501504] netpoll: netconsole: remote ethernet address AA:BB:CC:DD:EE:FF
[ 1007.501616] console [netcon0] enabled
[ 1007.501617] netconsole: network logging started

Если вывод похож на приведенный выше, значит модуль правильно настроен. Попробуйте перезагрузить сервер и найти сообщения netconsole после загрузки:

$ sudo dmesg | grep netconsole
[    8.423277] netpoll: netconsole: local port 10000
[    8.423288] netpoll: netconsole: local IPv4 address 176.120.28.219
[    8.423293] netpoll: netconsole: interface 'eth0'
[    8.423294] netpoll: netconsole: remote port 514
[    8.423295] netpoll: netconsole: remote IPv4 address 176.120.29.214
[    8.423296] netpoll: netconsole: remote ethernet address 1e:00:4d:00:02:d3
[    8.423302] netpoll: netconsole: device eth0 not up yet, forcing it
[    8.423670] netpoll: netconsole: carrier detect appears untrustworthy, waiting 4 seconds
[   12.427644] netconsole: network logging started

На этом настройка модуля завершена. Убедимся в том, что он работает. Для этого смоделируем событие паники ядра. Сначала запустим отслеживание событий syslog в режиме реального времени на сервере monitor:

$ sudo tail -f /var/log/syslog

Сначала убедимся, что сообщения поступают в syslog с помощью команды ‘w’ триггера sysrq:

$ sudo echo w > /proc/sysrq-trigger

В журнале вы должны увидеть строку, похожую на эту:

Mar 26 02:46:39 panic.host.name [  287.160555] sysrq: SysRq : 
Mar 26 02:46:39 Show Blocked State

Если вы ее видите, значит, сообщения доходят. Теперь посмотрим, что мы увидем в логах при возникновении паники на сервере panic с помощью другой команды триггера sysrq:

$ sudo echo c > /proc/sysrq-trigger

На этом месте сервер panic зависнет без возможности восстановления без перезагрузки, а в журнале syslog появится трассировка сообщений событий, приведших к панике.

### Большая часть начальных строк опущена для краткости ###
...
Mar 26 02:50:57 panic.host.name  
Mar 26 02:50:57 panic.host.name [  545.309199] RIP 
Mar 26 02:50:57 panic.host.name  [<ffffffff81517d26>] sysrq_handle_crash+0x16/0x20
Mar 26 02:50:57 panic.host.name [  545.309257]  RSP <ffff88003c777e48>
Mar 26 02:50:57 panic.host.name [  545.309298] CR2: 0000000000000000
Mar 26 02:50:57 panic.host.name [  545.309384] ---[ end trace 3cf5f65ed1a64f3b ]---
Mar 26 02:50:57 panic.host.name [  545.310812] Kernel panic - not syncing: Fatal exception
Mar 26 02:50:57 panic.host.name [  545.312336] Kernel Offset: disabled
Mar 26 02:50:57 panic.host.name [  545.313633] ---[ end Kernel panic - not syncing: Fatal exception

Если вы видите такой вывод, значит настройка успешна и при возникновении исключительных событий ядра, вы сможете видеть их в журнале syslog на удаленном сервере.

Заключение

В этом руководстве вы научились использовать модуль netconsole для удаленной отправки критических сообщений ядра с момента возникновения нештатной ситуации до перехода ядра в режим паники.

Данный способ может не подойти при возникновении ошибок в сетевых модулях ядра, связанных с сетевой картой, используемой для отправки сообщений. В этом случае, ошибки ядра могут находиться в журналах файловой системы, а еще возможно использовать терминал на последовательном порту (/dev/ttyS*). Приведенный метод успешно зарекомендовал себя в средах, где часто встречаются ошибки файловых систем — наиболее сложных компонентах операционных систем.