Семь привычек Linux-инженера, которые спасают прод. linux.. linux. linux bash scripts.. linux. linux bash scripts. linux games.. linux. linux bash scripts. linux games. linux kernel.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех. линукс.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех. линукс. линукс в россии.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех. линукс. линукс в россии. линукс для каждого.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех. линукс. линукс в россии. линукс для каждого. линуксоиды.. linux. linux bash scripts. linux games. linux kernel. Блог компании К2Тех. линукс. линукс в россии. линукс для каждого. линуксоиды. Настройка Linux.

Всем привет! Меня зовут Анна Васильева, я технический менеджер в K2 Cloud и люблю запускать утилиты с максимально возможным уровнем verbose.

Есть фраза, после которой расследование сбоя обычно становится интереснее: «Я ничего не менял». Через несколько часов выясняется, что изменения всё-таки были. Инженер распаковал архив, добавил сетевой интерфейс, обновил библиотеку или перенёс виртуальную машину на другой хост. Действие казалось безобидным, а его последствия проявились в неожиданном месте.

На митапе «Инженеры перебрали / кейсы по Linux» мы взяли семь реальных случаев и разобрали их вместе с экспертами:

  • Андреем Кулаевым, руководителем инженеров разработки в K2 Cloud. Андрей уже больше менеджер, чем инженер, но все еще читает man`ы перед тем как спросить у ИИ.

  • Владимиром Сергеевым, руководителем практики объединённых коммуникаций и программного обеспечения для совместной работы в K2Тех. В проекте ценит проявление естественного интеллекта инженеров больше, чем искусственного.

  • Михаилом Якушиным, системным архитектором Orion soft, который собирает ядро из исходников since 1998, застал системы без udev и yum.

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

Полное обсуждение кейсов и демонстрации можно посмотреть по [ссылке на запись].

1. Не распаковывайте архивы в рабочем каталоге

Начнем с ситуации, в которой инженер действительно не менял ни настройки в конфиге SSH, ни права доступа вручную.

Пользователь вошёл на Linux-сервер под своей учётной записью, загрузил архив с проектом и распаковал его прямо в домашнем каталоге. После этого он завершил сеанс. При следующей попытке подключения сервер перестал принимать его SSH-ключ.

Сама машина продолжала работать. Другой пользователь смог войти на неё и посмотреть журналы. Значит, искать проблему нужно было не в сети и не в службе SSH целиком, а в конкретной директории.

Первая версия выглядела очевидно: архив мог содержать каталог .ssh или файл authorized_keys, который при распаковке заменил исходный список ключей. Вторая версия — закончилось свободное место. Третья — изменились владелец файлов или контексты SELinux.

Журнал SSH дал более точную подсказку:

Authentication refused: bad ownership or modes for directory /home/user01

Сервер отказывался использовать ключи из-за небезопасных прав на домашний каталог. У исправно работающего пользователя директория имела права 700:

drwx------ user02 user02 /home/user02

У пользователя, потерявшего доступ, права изменились на 775:

drwxrwxr-x user01 user01 /home/user01

Теперь каталог мог изменять владелец и любой участник его группы. SSH считает такую конфигурацию небезопасной: другой пользователь теоретически способен подменить содержимое .ssh и изменить правила авторизации.

Доступ восстановился после возврата исходных прав:

Семь привычек Linux-инженера, которые спасают прод - 1

Оставался главный вопрос: каким образом распаковка проекта изменила права на домашнюю директорию?

Коллега создавал архив, находясь в своём домашнем каталоге. Он нашёл готовую команду и передал tar текущую директорию целиком:

tar -czf project.tar.gz.

Точка в конце команды означает текущий каталог. Поэтому в архив попали проект, скрытые файлы и отдельная запись ./, описывающая сам каталог. Архиватор воспринимает ./ как конкретный объект архивации и применяет к  текущей папке те метаданные и права, которые были сохранены в архиве.

Посмотреть её можно до распаковки:

Семь привычек Linux-инженера, которые спасают прод - 2

В начале списка будет строка примерно такого вида:

drwxrwxr-x user02/user02 0 ... ./

Исходный домашний каталог имел права 775. Когда другой пользователь распаковал архив у себя, tar применил метаданные ./ к текущей директории. Права /home/user01 изменились с 700 на 775, после чего SSH перестал принимать ключи.

Безопаснее архивировать конкретную директорию:

tar -czf project.tar.gz. project/

Незнакомые архивы лучше извлекать во временное место:

tmp_dir=$(mktemp -d)
tar -xzf project.tar.gz -C "$tmp_dir"

Так можно проверить структуру, владельцев и права файлов до переноса в рабочий каталог.

Главный совет — всегда проверяйте архивы перед распаковкой с помощью опции v и старайтесь избегать распаковки в домашние директории пользователей.

2. Не выбирайте виновника по одному графику

Следующий случай начинался как обычная жалоба на медленное хранилище. Резервные копии между двумя дата-центрами передавались со скоростью около 1 Гбит/с. На графике получалось почти идеальная полка: производительность доходила до определённого значения и дальше не росла.

Такая картина часто указывает на жёсткое ограничение. Под подозрение попали система хранения, сеть между площадками и межсетевые экраны, через которые проходил трафик.

Исходный сервер был подключён двумя интерфейсами по 25 Гбит/с. Между дата-центрами работал канал на 5 Гбит/с. Явного гигабитного участка в схеме не было, но форма графика продолжала напоминать сетевой лимит.

Команда начала проверять путь данных по частям. Сначала запустили отдельный сетевой тест между площадками. Канал стабильно выдавал все 5 Гбит/с. Тест шёл достаточно долго, поэтому результат нельзя было объяснить коротким всплеском или кэшированием. Сеть справлялась. Ограничение находилось выше по стеку.

Резервная копия сначала сохранялась в локальный репозиторий, а затем синхронизировалась со второй площадкой через rsync поверх SSH. Шифрование создавало заметную вычислительную нагрузку и в этом сценарии упиралось в производительность одного ядра. Сжатие и дедупликация на дисковых пулах добавляли собственные расходы на обработку данных. Измерения показали, что сервер не успевал обработать поток быстрее примерно 1 Гбит/с, хотя сеть и дисковая подсистема ещё располагали запасом производительности.

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

При такой диагностике весь путь стоит разложить на отдельные этапы:

  1. источник данных

  2. локальный репозиторий

  3. обработка

  4. шифрование

  5. сеть

  6. удалённый репозиторий

Сеть проверяется отдельным продолжительным тестом. Диски — нагрузкой с подходящим размером блока, количеством потоков и глубиной очереди. При проверке нагрузки на CPU стоит обратить внимание, равномерная у нас нагрузка по всем ядрам или же есть явный перекос в сторону одного загруженного ядра.

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

В итоге от ручной синхронизации через rsync отказались. Её заменили штатным механизмом системы резервного копирования. Он сначала проверял целостность копии, затем передавал её в несколько потоков.

Многопоточная обработка позволила лучше использовать доступный канал. Проверка целостности перед отправкой снизила риск перенести на вторую площадку уже повреждённые данные.

Главный совет: ровная полка на графике указывает на наличие предела, но не на конкретный компонент. Ищите ограничение по всей цепочке и проверяйте каждый слой отдельно.

3. Не отключайте защиту, когда она мешает запуску

Инженер настроил новый виртуальный хост Apache на нестандартном порту 8081. После изменения конфигурации веб-сервер перестал запускаться.

На стандартном порту 80 всё работало. Конфигурационные файлы существовали, права были корректными, порт не занимало другое приложение.

Если бы порт уже использовался, Apache сообщил бы:

Address already in use

Проверить такую версию можно командой:

ss -lntp | grep ':8081'

Внешний межсетевой экран тоже не мог помешать самому запуску Apache. Он способен заблокировать подключения извне, но локальный процесс всё равно открыл бы порт. Ошибка указывала на запрет операции внутри системы. Причиной оказался SELinux.

Apache работает в отдельном домене безопасности. SELinux разрешает этому домену открывать только порты, отмеченные подходящим типом. Стандартный порт 80 уже относится к http_port_t. Порт 8081 в разрешённый набор не входил, поэтому система блокировала попытку процесса веб-сервера занять этот порт.

В такой ситуации часто используют самое быстрое «исправление»: отключают SELinux и перезапускают приложение. Сервис начинает работать, задача считается закрытой, а временная настройка остаётся на сервере на несколько лет.

Для диагностики SELinux действительно можно перевести в permissive mode:

Семь привычек Linux-инженера, которые спасают прод - 3

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

Оставлять SELinux в таком состоянии не нужно. После проверки принудительный режим возвращается:

Семь привычек Linux-инженера, которые спасают прод - 4

Дальше следует выяснить, какое правило требуется приложению. Список портов, разрешённых веб-службам, можно посмотреть так:

Семь привычек Linux-инженера, которые спасают прод - 5

Порт 8081 добавляется к типу http_port_t:

semanage port -a -t http_port_t -p tcp 8081

Если он уже зарегистрирован в политике с другим типом, правило нужно изменить:

semanage port -m -t http_port_t -p tcp 8081

После этого Apache сможет использовать новый порт, а остальные ограничения SELinux продолжат действовать.

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

Главный совет: используйте отключение в целях диагностики, определите в audit логе, по какой причине была заблокирована попытка доступа, затем исправьте контекст на валидный для данного процесса. Вопрос, кстати, касается не только SElinux. Этот подход валиден при настройке файерволов и других систем обеспечения информационной безопасности.

4. Сначала добейтесь стабильного воспроизведения

Этот кейс — от Orion soft и связан с платформой виртуализации zVirt. Заказчик обновлял платформу виртуализации. Вместе с другими компонентами Linux, KVM и ядро переходили с версии 4.18 на 6.1.

Первые тестовые и второстепенные сервисы работали нормально. Проблема появилась после переноса крупной производственной системы: её производительность резко снизилась. Виртуальные машины возвращали на старые хосты — скорость восстанавливалась. Снова переносили на обновлённые — деградация повторялась. Связь с новой платформой выглядела очевидной.

На другой площадке то же обновление не вызывало проблем. Там использовались более новые процессоры. На проблемных хостах стояли Intel Cascade Lake.

Инженеры проверили версии микрокода, модели процессоров, драйверы, работу планировщика и взаимодействие ядра с оборудованием. Стандартные стресс-тесты показывали нормальную производительность. Процессор выдерживал нагрузку, память работала, явных ошибок в системе не было.

Синтетический тест оказался слишком простым. В проблемной ВМ работало около 400 контейнеров. Они создавали множество переключений контекста и операций с памятью. Обычная нагрузка на процессор такое поведение не воспроизводила.

Для расследования построили отдельный стенд с идентичным оборудованием и похожим количеством контейнеров. Партнёры помогли воспроизвести профиль производственной системы. На подготовку и поиск причины ушло около двух–трёх недель.

После появления стабильного теста проблему можно было исследовать последовательно. Инженеры временно отключили программные механизмы защиты процессора — деградация исчезла. Затем защиты начали включать по одной. Производительность снова падала после активации определённого механизма.

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

Разница в отдельной метрике могла выглядеть незначительно. Например, доля времени, которую занимала работа планировщика, увеличивалась с условного 1 до 2%. Для одной операции это почти ничего. Для сотен контейнеров — уже серьезная потеря.

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

Самая ценная часть кейса связана не с конкретным параметром ядра, а с методом расследования:

  1. Воспроизвести настоящий профиль нагрузки.

  2. Сделать результат стабильным.

  3. Менять по одному параметру.

  4. После каждого изменения проводить одинаковый тест.

  5. Подтверждать выводы измерениями.

При плавающем сбое непонятно, помогло ли изменение или система случайно отработала быстрее. Стабильное воспроизведение превращает поиск причины в управляемый эксперимент.

Главный совет: не начинайте исправлять ошибку, пока не научились уверенно её вызывать. Без этого любую удачную попытку легко принять за решение.

5. Не считайте имя устройства постоянным

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

Инженер добавил ещё один интерфейс и перезагрузил ВМ. После запуска часть соединений перестала работать. Внутри гостевой системы MAC-адреса словно поменялись местами: настройки, предназначенные для одного интерфейса, применялись к другому.

В облачной консоли адаптеры отображались в привычном порядке. Внутри Linux порядок оказался другим.

Имена сетевых интерфейсов могут зависеть от MAC-адреса, PCI-слота, физического пути до устройства, порядка обнаружения или правил udev. Конкретный механизм определяется дистрибутивом, версией системы и настройками.

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

Упрощённо исходная схема выглядела так:

PCI 01 — сетевой интерфейс 1
PCI 02 — сетевой интерфейс 2
PCI 03 — сетевой интерфейс 3
PCI 04 — сетевой интерфейс 4
PCI 05 — сетевой интерфейс 5
PCI 06 — дисковый контроллер

После изменения конфигурации:

PCI 01 — сетевой интерфейс 1
PCI 02 — сетевой интерфейс 2
PCI 03 — сетевой интерфейс 3
PCI 04 — дисковый контроллер
PCI 05 — сетевой интерфейс 4
PCI 06 — сетевой интерфейс 5

Если гостевая система связывает имя с PCI-путём, привычное обозначение после перезагрузки может указывать уже на другой адаптер.

Для межсетевого экрана такое расхождение особенно опасно. Конкретно в этой инсталляции настройка зон на МСЭ была привязана к именам сетевых интерфейсов, из-за чего политики перестали отрабатывать. Так же упал data-HA линк, из-за чего перестал отрабатывать файловер для active-passive инсталляции.

Безопасного способа изменить порядок устройств в работающей закрытой системе инженеры не нашли. Пришлось согласовать технологическое окно, выключить ВМ, удалить интерфейсы и подключить их заново в нужной последовательности.

После запуска проверили соответствие по всей цепочке:

интерфейс в облачной консоли → MAC-адрес → PCI-слот → имя внутри Linux → IP-адрес → назначение сети

интерфейс в облачной консоли → MAC-адрес → PCI-слот → имя внутри Linux → IP-адрес → назначение сети

Полагаться исключительно на имена eth0, eth1 или ens5 рискованно. Они могут измениться после обновления, клонирования, замены оборудования или перестройки виртуальной шины.

Похожая проблема встречается с дисками. Устройство /dev/sdb после перезагрузки может стать /dev/sdc.

Для монтирования надёжнее применять UUID, метки файловых систем, пути /dev/disk/by-id/ или WWID.

Для монтирования надёжнее применять UUID, метки файловых систем, пути /dev/disk/by-id/ или WWID.

Главный совет: имя устройства — не константа, а результат неких вычислений. Учитывайте это при создании настроек/политик etc

6. Сравнивайте состояние, а не конфигурационные файлы

Два сервера-балансировщика работали с HAProxy и keepalived. Между ними перемещался виртуальный IP-адрес. Версии системы совпадали, службы были настроены одинаково, конфигурационные файлы не отличались.

HAProxy при этом запускался только на одном сервере. На втором он завершался с ошибкой привязки к адресу.

Разница скрывалась не в конфигурации, а в текущем состоянии узлов. HAProxy должен был слушать конкретный виртуальный адрес и порт:

192.0.2.10:8084

На активном сервере виртуальный IP уже присутствовал. Ядро разрешало открыть сокет, и HAProxy запускался.

На резервном узле адреса ещё не было. Перед привязкой ядро проверяло, назначен ли указанный IP одному из локальных интерфейсов, и возвращало ошибку:

Cannot assign requested address

Одинаковая конфигурация приводила к разному результату, поскольку один сервер владел адресом, а второй — нет.

Для быстрого переключения требовалось заранее запустить HAProxy на обоих узлах. Тогда после переноса виртуального IP резервный сервер сразу начал бы принимать соединения.

Linux позволяет приложению привязаться к адресу, который пока отсутствует на локальных интерфейсах. За это отвечает параметр:

net.ipv4.ip_nonlocal_bind = 1

Временно включить его можно командой:

sysctl -w net.ipv4.ip_nonlocal_bind=1

Для постоянной настройки значение добавляется в конфигурацию sysctl, после чего параметры применяются:

Семь привычек Linux-инженера, которые спасают прод - 8

Эта настройка не создаёт IP-адрес и не переносит трафик. Она разрешает приложению заранее открыть сокет и ждать, пока keepalived назначит виртуальный адрес нужному узлу.

Параметр действует на все процессы в соответствующем сетевом пространстве имён, поэтому его влияние нужно проверить на остальных службах. Для IPv6 используется отдельная настройка:

Семь привычек Linux-инженера, которые спасают прод - 9

Другим решением могло стать прослушивание всех локальных адресов, например *:8084. Такой вариант не подходил проекту: HAProxy должен был обслуживать конкретный виртуальный IP, не затрагивая остальные адреса сервера.

После включения ip_nonlocal_bind оба экземпляра HAProxy работали постоянно. При переносе адреса резервный узел принимал соединения без ручного перезапуска службы.

Главный совет: если два одинаково настроенных сервера ведут себя по-разному, проверьте, проверяйте состояние сетевых интерфейсов, текущие параметры ядра и т.д.

7. Не обновляйте весь кластер одним нажатием

Последний кейс прислал зритель Дмитрий Говоров. На трёх прокси-серверах работал производственный проект. Вход на машины был разрешён только по SSH-ключам, пароли для учётных записей не устанавливались.

Под нагрузкой сервисы начали сбоить. В журналах Nginx появлялись ошибки, связанные с сертификатами. Команда предположила, что проблема вызвана старой версией OpenSSL, и запустила обновление через Ansible сразу на всех трёх серверах.

После установки пакетов SSH перестал принимать ключи на каждой машине. Удалённо подключиться к инфраструктуре было невозможно. Инженерам пришлось использовать консоль, задавать пароли и завершать прерванное обновление вручную.

Точную причину отказа без журналов и списка изменившихся пакетов установить нельзя. Вместе с OpenSSL могли обновиться OpenSSH, зависимости и системные криптографические политики. Используемый алгоритм подписи или формат ключа мог оказаться запрещённым новой конфигурацией.

Проверять в такой ситуации нужно тип ключа, алгоритмы подписи, настройки sshd_config, криптографа.

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

Проверить нужно:

  • доступ по SSH существующими ключами;

  • успешный запуск Nginx;

  • загрузку конфигурации и сертификатов;

  • прохождение тестового запроса;

  • работу под ожидаемой нагрузкой;

  • возврат сервера в балансировку.

Открытый порт ещё не означает, что приложение готово принимать трафик. Процесс может запуститься, открыть сокет и возвращать ошибки на каждый запрос. Полезнее обращаться к служебной точке проверки состояния, которая подтверждает выполнение минимальной рабочей операции.

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

Для критической инфраструктуры нужен независимый аварийный канал: консоль облачной платформы, BMC, iDRAC, iLO или другой механизм, который не зависит от обновляемого SSH. Единственный способ входа не должен становиться единственным способом восстановления.

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

Безопасная схема выглядит иначе: сначала тестовый узел или копия сервера, затем один производственный узел, проверка и только после неё переход к следующей машине. Рабочая часть кластера всё это время продолжает обслуживать трафик.

Главный совет: обновляйте инфраструктуру так, чтобы после любой неудачи у вас оставались исправный сервер, доступ к системе и возможность остановить процесс.

Вместо вывода: ищите правила

Эти семь историй начинаются по-разному. SSH перестаёт принимать ключи после распаковки архива. Скорость передачи упирается в гигабит при 25-гигабитном сетевом канале. Приложение не запускается на нестандартном порту. Одинаковые балансировщики ведут себя неодинаково. Новый интерфейс ломает политики и маршруты на межсетевом экране.

Но система нигде не действовала случайно. tar восстановил сохранённые права. SSH отказался доверять небезопасному домашнему каталогу. SELinux заблокировал доступ из-за невалидного контекста. Гостевая ОС обнаружила устройства в новом порядке. Ядро запретило привязку к отсутствующему IP. Ansible выполнил команду сразу на всех указанных серверах.

Проблема появлялась в момент, когда представление инженера о системе расходилось с её реальным устройством.

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

Полную встречу с версиями участников, другими историями и подробными демонстрациями смотрите по [ссылке на запись].

Автор: AnnVasileva

Источник