Вопросы с собесов на Linux-администратора: 42 реальных

Коротко

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

Подборки вопросов: Linux · DevOps · SRE · DevSecOps · MLOps · AIOps

Блок 1. Загрузка и systemd

1. Что происходит от включения питания до приглашения login?

Прошивка (BIOS или UEFI) проходит POST и передаёт управление загрузчику — обычно GRUB. GRUB читает свой конфиг, находит ядро и initramfs, грузит их в память. Ядро инициализирует железо, монтирует временный корень из initramfs, где лежат модули для доступа к настоящему корню — драйверы дисков, LVM, mdadm, шифрование. Дальше switch_root на настоящий корень и запуск PID 1, то есть systemd. Systemd поднимает цели и юниты по зависимостям, доводит систему до multi-user.target или graphical.target, и getty выводит приглашение.

Обычно путаются на роли initramfs — говорят «это ядро». Стоит уметь объяснить, зачем он вообще нужен: без него ядро не сможет прочитать корень на LVM или на зашифрованном разделе.

Follow-up интервьюера: а что сломается, если пересобрать ядро без модуля контроллера дисков и не обновить initramfs? — kernel panic на этапе монтирования корня, машина уйдёт в цикл перезагрузок.

2. Чем Wants= отличается от Requires= в юните systemd?

Requires= — жёсткая зависимость: если указанный юнит не поднялся или упал, зависящий тоже останавливается. Wants= — мягкая: systemd попытается запустить зависимость, но её падение на наш юнит не влияет. Обе директивы задают только состав, а не порядок: порядок — это отдельно After= и Before=. Самая частая ошибка в реальных конфигах — написать Requires=postgresql.service и ждать, что сервис стартует после базы. Он стартует одновременно с ней, потому что After= забыли.

Смешивают состав и порядок. Правильный ответ обязательно содержит фразу «Requires не гарантирует очерёдность».

Follow-up интервьюера: а чем BindsTo= отличается от Requires=? — BindsTo жёстче: юнит останавливается и тогда, когда зависимость исчезает по внешней причине, например пропало устройство.

3. Сервис не стартует. Ваши действия по шагам?

Сначала systemctl status имя — код возврата, последние строки лога, PID. Дальше journalctl -u имя -n 100 --no-pager, а если нужен предыдущий запуск — -b -1. Потом проверяю сам юнит: systemctl cat имя покажет итоговый файл вместе с drop-in из /etc/systemd/system/имя.d/, про которые часто забывают. Если ошибка невнятная, запускаю бинарь руками от нужного пользователя с теми же переменными окружения: systemd-run --uid=... --pty или просто su. Классика — процесс не видит переменные, потому что systemd не читает профиль пользователя.

Забывают про drop-in каталоги и правят основной юнит в /lib, который потом перезатрёт пакетный менеджер. И не делают systemctl daemon-reload после правки.

Follow-up интервьюера: сервис пишет «Permission denied», а права на файл верные. Что ещё? — SELinux или AppArmor, ProtectSystem/ReadOnlyPaths в самом юните, либо неверный SupplementaryGroups.

4. Что такое target и чем он заменил runlevel?

Target — это группирующий юнит, точка синхронизации. Вместо жёсткой лестницы уровней 0–6 systemd описывает состояния графом зависимостей: multi-user.target примерно соответствует старому runlevel 3, graphical.target — пятому, и он в свою очередь требует multi-user. Плюс есть служебные цели вроде network-online.target и basic.target. Текущую цель по умолчанию смотрят через systemctl get-default, меняют через set-default. Главное отличие от runlevel — параллельный запуск: systemd поднимает всё, что не связано зависимостями, одновременно.

Говорят «target это то же самое, что runlevel». Отличие принципиальное: runlevel — последовательность, target — граф.

Follow-up интервьюера: чем network.target отличается от network-online.target? — первый означает «сетевая подсистема настроена», второй «адрес получен и сеть реально доступна»; сервисам, которым нужен коннект на старте, нужен второй.

5. Сервис падает, systemd перезапускает его по кругу. Что делать?

Сначала посмотреть, почему падает: journalctl -u имя и код выхода в статусе. Параллельно приструнить сам цикл — в юните есть StartLimitIntervalSec и StartLimitBurst: по умолчанию после пяти рестартов за десять секунд systemd переводит юнит в состояние failed и перестаёт его дёргать. Если нужно дать сервису шанс, добавляют RestartSec=, чтобы паузы между попытками росли. На проде важнее другое: бесконечный рестарт часто маскирует проблему в зависимостях — недоступную базу или неготовую сеть, — и лечится это условием готовности, а не увеличением числа попыток.

Отвечают только «поставить Restart=no». Хороший ответ разделяет: как остановить шторм сейчас и почему падает на самом деле.

Follow-up интервьюера: как systemd поймёт, что сервис действительно готов, а не просто запустился? — Type=notify и sd_notify из приложения, либо ExecStartPost с проверкой готовности.

6. Как ограничить сервису ресурсы средствами systemd?

Через cgroups, которыми systemd управляет напрямую. В юните задаются MemoryMax= (жёсткий потолок, при превышении процесс убивает OOM внутри cgroup), MemoryHigh= (мягкий порог, включается агрессивный reclaim), CPUQuota= в процентах от ядра, TasksMax= против форк-бомб, IOWeight= для дисковых приоритетов. Посмотреть фактическое потребление — systemd-cgtop. Прелесть в том, что лимит применяется ко всему дереву процессов сервиса, а не к одному PID, поэтому дочерние процессы не убегают из-под ограничения.

Путают MemoryMax и MemoryHigh и не знают, что лимит накрывает всё дерево процессов, а не только главный.

Follow-up интервьюера: что произойдёт при упоре в MemoryMax? — OOM внутри cgroup убьёт процесс сервиса, при этом остальная система не пострадает; в логе будет запись от ядра.

7. Чем journald отличается от syslog и как сделать логи персистентными?

journald хранит структурированный бинарный лог с полями: юнит, PID, приоритет, произвольные ключи от приложения. Отсюда фильтры вида journalctl -u nginx -p err --since "1 hour ago", которые в текстовом syslog делались бы через grep. По умолчанию во многих дистрибутивах журнал живёт в /run/log/journal, то есть в tmpfs, и после перезагрузки исчезает — именно поэтому «после ребута логов нет». Чтобы сохранять, создают /var/log/journal и ставят Storage=persistent в journald.conf, плюс ограничивают размер через SystemMaxUse=. Syslog при этом никуда не делся: journald умеет пересылать записи дальше, в rsyslog и в централизованный сбор.

Не знают про tmpfs и удивляются пропаже логов после перезагрузки. Второй провал — не ограничивают размер журнала, и он съедает /var.

Follow-up интервьюера: как вычистить журнал, не трогая файлы руками? — journalctl --vacuum-size=1G или --vacuum-time=7d.

Блок 2. Файловая система, права, диски

8. df показывает свободное место, но запись не идёт. Почему?

Три классические причины. Первая — кончились inode: df -i покажет 100% при свободных гигабайтах, типично для каталогов с миллионами мелких файлов, кешей и почтовых очередей. Вторая — место занято удалённым, но всё ещё открытым файлом: процесс держит дескриптор, ядро не освобождает блоки; ищется через lsof +L1. Третья — квоты или зарезервированные для root 5% блоков в ext4, из-за которых обычный пользователь упирается в потолок раньше, чем df покажет ноль.

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

Follow-up интервьюера: как освободить место, занятое удалённым открытым файлом, не перезапуская сервис? — обнулить содержимое через дескриптор в /proc/PID/fd, но честнее всё-таки перезапустить.

9. Что означают права rwx на каталоге?

Для каталога смысл другой, чем для файла. r — можно прочитать список имён, то есть сделать ls. x — можно войти внутрь и обратиться к файлу по имени, а также прочитать метаданные. w вместе с x — можно создавать, удалять и переименовывать записи. Отсюда контринтуитивные следствия: с правом x, но без r, вы прочитаете файл, зная его точное имя, но не увидите содержимое каталога. И наоборот, право на удаление файла определяется правами на каталог, а не на сам файл — поэтому чужой файл в каталоге, куда у вас есть запись, удалить можно.

Тот самый вопрос, где почти все говорят про файлы. Разбор именно каталога и фраза про удаление по правам каталога сразу отличают практика.

Follow-up интервьюера: а как запретить удаление чужих файлов в общем каталоге? — sticky bit, как на /tmp: удалять сможет только владелец файла.

10. Что такое setuid, setgid и sticky bit?

setuid на исполняемом файле означает, что процесс запустится с правами владельца файла, а не запустившего: так работает passwd, которому нужен доступ к /etc/shadow. setgid на файле — то же самое для группы, а на каталоге даёт другое поведение: все создаваемые внутри файлы наследуют группу каталога, что удобно для общих папок команды. Sticky bit на каталоге разрешает удалять файлы только их владельцу — классика /tmp. Найти все setuid-бинари: find / -perm -4000 -type f.

Не знают, что setgid на каталоге и на файле делают разные вещи. И не упоминают, что setuid — первое, что проверяют при разборе компрометации.

Follow-up интервьюера: почему setuid не работает на скриптах? — большинство ядер игнорируют этот бит у интерпретируемых файлов из-за гонки между проверкой прав и запуском интерпретатора.

11. Чем hard link отличается от symlink?

Жёсткая ссылка — это ещё одно имя для той же inode: у файла просто растёт счётчик ссылок, и данные исчезают только когда счётчик обнулился и никто не держит дескриптор. Она не может пересекать границу файловой системы и не указывает на каталоги. Символическая ссылка — отдельный маленький файл, внутри которого лежит путь; она спокойно живёт на другой файловой системе, может указывать на каталог и превращается в «битую», если цель переименовали. Практический вывод: бэкап, сделанный жёсткими ссылками, экономит место, но правка файла меняет его во всех «копиях».

Говорят «symlink это ярлык», но не могут объяснить, почему hard link не работает между разделами: у каждой файловой системы своя нумерация inode.

Follow-up интервьюера: что покажет ls -l для жёсткой ссылки? — ровно то же, что для оригинала: различить их можно только по номеру inode через ls -i.

12. Как расширить файловую систему на LVM, не уронив сервис?

Порядок снизу вверх. Добавляем диск или расширяем существующий, потом pvresize, чтобы LVM увидел новый размер физического тома. Дальше lvextend -L +50G /dev/vg/lv. И только затем растёт сама файловая система: resize2fs для ext4 или xfs_growfs для XFS — обе умеют делать это на смонтированном разделе, простой не нужен. Удобно сразу lvextend -r, который вызывает ресайз файловой системы за вас. Обратная операция — уменьшение — на XFS невозможна вообще, а на ext4 требует размонтирования и делается только с бэкапом.

Путают порядок и пытаются сначала растянуть файловую систему. И почти никто не помнит, что XFS не уменьшается — а это важное архитектурное ограничение.

Follow-up интервьюера: а если LV на диске, который уже расширили в гипервизоре, но система не видит новый размер? — перечитать шину: echo 1 > /sys/class/block/sdX/device/rescan.

13. Что делает опция монтирования noatime и зачем она нужна?

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

Ответ «ускоряет диск» без объяснения механизма. И не знают про relatime, считая, что выбор только между atime и noatime.

Follow-up интервьюера: где ещё стоит посмотреть опции монтирования при разборе производительности? — barrier/nobarrier и discard: последний включает онлайн-TRIM, который на некоторых SSD даёт заметные паузы.

14. Как найти, что именно занимает место на диске?

Сверху вниз. df -h — какая файловая система заполнена, df -i — не в inode ли дело. Дальше du -xh --max-depth=1 / и спуск по самому толстому каталогу; ключ -x обязателен, иначе du уйдёт в другие смонтированные файловые системы и в /proc. Для интерактивного разбора удобен ncdu. Отдельно проверяю два места, которые du покажет неправильно: удалённые открытые файлы через lsof +L1 и содержимое каталогов, поверх которых что-то смонтировано — они видны только после размонтирования или через bind-mount корня.

Забывают -x и потом удивляются, почему сумма du не сходится с df. Второй провал — не проверяют удалённые открытые файлы.

Follow-up интервьюера: du показал 40 ГБ, df говорит 80 ГБ занято. Где разница? — почти наверняка удалённые файлы, которые держит процесс, либо данные под точкой монтирования.

Блок 3. Процессы, память, производительность

15. Процесс висит в состоянии D. Что это значит и что с ним делать?

D — это uninterruptible sleep: процесс ушёл в системный вызов и ждёт ответа от ядра, чаще всего от блочного устройства или от сетевой файловой системы. Он не реагирует ни на какие сигналы, включая kill -9, потому что сигнал доставляется при выходе из системного вызова, а выхода не происходит. Лечится не убийством процесса, а устранением причины: подвисший NFS-сервер, отвалившийся LUN, умирающий диск. Смотрю dmesg на предмет ошибок ввода-вывода и таймаутов, cat /proc/PID/stack — где именно застряли, iostat -x 1 — не упёрлись ли в диск. Много процессов в D разом почти всегда означают проблему на уровне хранилища, а не на уровне приложения.

Пытаются добить его через kill -9 и делают вывод, что «система сломана». Правильный ответ начинается со слов «сигнал ему не дойдёт».

Follow-up интервьюера: а как процессы в D влияют на load average? — прямо: в Linux LA считает и D-состояния тоже, поэтому подвисшее хранилище даёт LA под сотню при нулевом CPU.

16. Load average 40 на 8 ядрах. Всё плохо?

Не обязательно. Load average в Linux — это среднее число задач в состояниях R (готов бежать или бежит) и D (ждёт ввода-вывода) за 1, 5 и 15 минут. Из-за D-состояний метрика перестаёт быть про процессор: LA 40 при нулевой загрузке CPU означает, что сорок задач ждут диск или сеть, и лечить надо хранилище. И наоборот: LA 8 на 8 ядрах при полной загрузке CPU — это ровно рабочая ситуация. Поэтому LA я всегда читаю в паре: top или vmstat 1 покажет распределение по us/sy/wa/id, и уже колонка wa отделяет процессорную нагрузку от дисковой.

Классика — сравнивают LA с числом ядер и на этом останавливаются. Ключевая деталь, которую ждут: в Linux в LA входит iowait, в отличие от классического Unix.

Follow-up интервьюера: три числа LA: 40, 12, 5. О чём это говорит? — нагрузка резко выросла только что; если бы порядок был обратный, пик уже прошёл и система разгружается.

17. Чем RSS отличается от VSZ и сколько памяти реально ест процесс?

VSZ — размер виртуального адресного пространства: всё, что процесс замапил, включая ещё не тронутые страницы, файлы через mmap и разделяемые библиотеки. Он может быть в разы больше физической памяти машины и сам по себе ни о чём не говорит. RSS — сколько страниц реально лежит в физической памяти прямо сейчас, но и он завышает: разделяемые библиотеки посчитаны целиком в каждом процессе, который их использует. Честная метрика — PSS из /proc/PID/smaps_rollup: общая память делится между процессами пропорционально. Для вопроса «сколько освободится, если убить процесс» смотрят USS.

Складывают RSS всех процессов, получают больше, чем есть памяти в машине, и не могут это объяснить.

Follow-up интервьюера: почему сумма RSS может превышать физическую память? — из-за многократного учёта разделяемых страниц; PSS такой проблемы не имеет.

18. Как работает OOM killer и как он выбирает жертву?

Когда ядро не может выделить страницу и не помогает вытеснение, оно вызывает OOM killer. Тот считает для каждого процесса oom_score, отталкиваясь в первую очередь от объёма занятой памяти, и корректирует его на oom_score_adj из /proc/PID/ — диапазон от −1000 (неприкосновенный) до +1000. Убивается процесс с максимальным счётом, то есть обычно самый жирный, и это чаще всего именно ваша база или бэкенд, а не виновник утечки. Следы всегда остаются в dmesg и в journal: строка Out of memory: Killed process с полной таблицей кандидатов. Отдельно есть cgroup-OOM: при упоре в MemoryMax= сервиса убивают внутри его cgroup, остальная система не страдает.

Не знают, что событие логируется в dmesg, и часами ищут, «почему процесс сам упал без ошибки». Второй провал — считают, что OOM killer срабатывает при исчерпании swap, а не физической памяти.

Follow-up интервьюера: как защитить от OOM конкретный процесс? — echo -1000 в /proc/PID/oom_score_adj либо OOMScoreAdjust= в юните systemd; но чаще правильнее ограничить обжору, а не защищать жертву.

19. free -m показывает 200 МБ свободно из 32 ГБ. Пора паниковать?

Нет, и это самый частый ложный алярм. Linux по определению занимает всю незанятую память под page cache — кеш прочитанных с диска данных, — потому что простаивающая память бесполезна. Эта память освобождается мгновенно, как только она понадобится приложению. Смотреть нужно не на колонку free, а на available: она учитывает то, что можно отдать без свопа. Настоящие признаки нехватки другие: рост si/so в vmstat 1, то есть активный своп, всплеск pgscan и pgsteal, срабатывания OOM в dmesg. И отдельно — не путать buffers/cache с утечкой в приложении.

Реагируют на free вместо available. Ещё встречается ритуальное drop_caches на проде — оно ничего не чинит, только выкидывает горячий кеш и делает хуже.

Follow-up интервьюера: когда page cache всё-таки становится проблемой? — когда грязных страниц много и dirty_ratio упирается в потолок: тогда запись превращается в синхронную и приложение встаёт колом.

20. Процесс жрёт CPU. Как понять, чем именно он занят?

Иду сверху вниз. top -H -p PID — какой именно поток горит, потому что в многопоточном приложении виноват обычно один. cat /proc/PID/status и wchan — не спит ли он в ядре. Дальше два разных инструмента: strace -c -p PID покажет, если время уходит на системные вызовы (частый случай — миллионы мелких read или futex), а perf top -p PID покажет горячие функции, если время уходит в user space. Для JVM и питона есть свои профайлеры и дампы стека. strace на проде применяю аккуратно: он тормозит процесс кратно, поэтому вешаю на несколько секунд, а не оставляю висеть.

Ограничиваются top и делают вывод «приложение плохое». Ждут, что вы отделите user-время от системного и назовёте разный инструмент под каждый случай.

Follow-up интервьюера: почему strace опасен на проде? — он останавливает процесс на каждом системном вызове через ptrace; на нагруженном сервисе это может дать деградацию в разы.

21. Что такое зомби-процесс и надо ли его убивать?

Зомби — это уже завершившийся процесс, запись о котором осталась в таблице, потому что родитель не забрал код возврата через wait(). Он не занимает ни памяти, ни CPU, только слот в таблице процессов. Убить его нельзя — он уже мёртв; лечится либо тем, что родитель наконец сделает wait, либо перезапуском родителя, после чего зомби усыновит PID 1 и приберёт. Опасны не единичные зомби, а их непрерывный рост: это баг в родительском процессе, и рано или поздно кончатся PID. Отдельно стоит различать сироту — процесс, чей родитель умер: он живой и его просто перевешивают на init.

Пытаются убить зомби через kill и делают вывод, что процесс «не убивается». И путают зомби с сиротой.

Follow-up интервьюера: чем в контейнере опасно отсутствие нормального PID 1? — приложение в роли PID 1 не собирает потомков, зомби копятся; поэтому используют tini или --init.

Блок 4. Сеть на уровне хоста

22. Приложение не открывается по домену. Разложите диагностику по шагам.

Иду по слоям и после каждого шага знаю, что именно проверил. DNS: dig +short домен и сравнение с ожидаемым адресом, отдельно проверяю резолв на самой машине, потому что /etc/hosts и nsswitch могут врать. Дальше связность до адреса: ping ничего не доказывает, если ICMP закрыт, поэтому сразу curl -v или nc -vz host port — открывается ли TCP-соединение. Если соединение не устанавливается, смотрю с той стороны: слушает ли процесс нужный интерфейс через ss -lntp — типичная ошибка, когда сервис прибит к 127.0.0.1 вместо 0.0.0.0. Если слушает, то фильтрация: iptables -L -n -v или nft list ruleset, счётчики покажут, растут ли дропы. И только в конце — логи приложения и TLS, если проблема на уровне сертификата.

Прыгают сразу в логи приложения или, наоборот, бесконечно пингуют. Ждут именно упорядоченную проверку с явным выводом на каждом шаге.

Follow-up интервьюера: curl говорит Connection refused, а не таймаут. О чём это? — до хоста дошли и получили RST: порт никто не слушает или соединение отбил локальный firewall с REJECT; таймаут же обычно означает молчаливый DROP или потерю пакетов по дороге.

23. Как посмотреть, кто слушает порт, и почему ss, а не netstat?

ss -lntup: listening, TCP, UDP, без резолва имён, с указанием процесса. netstat из пакета net-tools во многих дистрибутивах уже не ставится по умолчанию и работает медленнее, потому что читает /proc/net/* целиком, тогда как ss берёт данные через netlink и умеет фильтры вида ss -o state established dport = :443. Если процесс не показывается, значит команда запущена не от root. Для вопроса «кто держит порт 80» рядом полезен lsof -i :80, а для картины «сколько соединений в каком состоянии» — ss -s.

Ответ «netstat -tulpn» без объяснений принимают, но следом почти всегда спрашивают про ss. Плохо, если человек не знает, что без sudo колонка с процессом пустая.

Follow-up интервьюера: сервис слушает, а снаружи не подключиться. Что смотреть первым? — адрес привязки: 127.0.0.1 против 0.0.0.0, и только потом firewall.

24. Что такое conntrack и как он роняет прод?

Это таблица отслеживания соединений в netfilter: чтобы понимать, что пакет относится к уже установленной сессии, ядро держит запись на каждое соединение. Размер таблицы ограничен nf_conntrack_max. Когда она заполняется, новые соединения просто отбрасываются, а в dmesg появляется nf_conntrack: table full, dropping packet. Симптом со стороны приложения выглядит загадочно: сервер не нагружен, но часть клиентов не подключается. Смотрю текущее заполнение в /proc/sys/net/netfilter/nf_conntrack_count, лечу либо увеличением max и хеш-таблицы, либо уменьшением таймаутов, либо через NOTRACK для трафика, которому отслеживание не нужно.

Не знают о существовании таблицы вообще и ищут проблему в приложении. Второй провал — поднимают nf_conntrack_max, не увеличив hashsize, и получают деградацию из-за длинных цепочек.

Follow-up интервьюера: почему на балансировщике таблица кончается быстрее? — каждое клиентское соединение плюс каждое соединение к бэкенду занимают отдельные записи, а TIME_WAIT держит их ещё десятки секунд после закрытия.

25. Десятки тысяч сокетов в TIME_WAIT. Это проблема?

Обычно нет. TIME_WAIT — нормальная фаза закрытия на стороне, которая закрыла соединение первой: ядро держит сокет 2×MSL, то есть около 60 секунд, чтобы не перепутать задержавшиеся пакеты с новым соединением на том же порту. Само по себе большое их число говорит лишь о высокой скорости открытия и закрытия соединений. Проблемой это становится в двух случаях: на исходящих соединениях кончаются локальные порты из ip_local_port_range, и тогда помогает расширение диапазона, keep-alive и переиспользование соединений; либо переполняется conntrack. А вот net.ipv4.tcp_tw_recycle трогать нельзя — его выпилили из ядра именно потому, что он ломал клиентов за NAT.

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

Follow-up интервьюера: чем tcp_tw_reuse отличается от tw_recycle? — reuse позволяет переиспользовать сокет в TIME_WAIT для нового исходящего соединения и это безопасно, recycle делал предположения о временных метках клиента и ломался за NAT.

26. Как читать таблицу маршрутизации и зачем нужен policy routing?

ip route показывает основную таблицу: default gateway, подключённые сети, конкретные маршруты. Выбор идёт по самому длинному совпадающему префиксу, а не по порядку строк. Проверять надо не глазами, а через ip route get 8.8.8.8 — ядро прямо скажет, какой маршрут, интерфейс и исходный адрес оно выберет. Policy routing нужен, когда решение зависит не только от адреса назначения: например, у машины два провайдера, и ответы должны уходить в тот же интерфейс, откуда пришёл запрос. Тогда заводят отдельные таблицы в /etc/iproute2/rt_tables и правила ip rule по исходному адресу или метке пакета.

Классическая беда двух аплинков — ответ уходит через default gateway другого провайдера и режется антиспуфингом; человек ищет проблему в firewall.

Follow-up интервьюера: как убедиться, с какого исходного адреса пойдёт пакет? — ip route get выведет src; его же можно зафиксировать через параметр src у маршрута.

27. Соединение устанавливается, но большие ответы не доходят. Куда смотреть?

Похоже на проблему с MTU. Рукопожатие и мелкие пакеты проходят, а как только появляется полноразмерный сегмент, он не пролезает в туннель или в канал с меньшим MTU. Если по пути кто-то режет ICMP тип 3 код 4, механизм Path MTU Discovery не работает: отправитель не узнаёт, что надо уменьшить пакет, и соединение просто зависает. Проверяю пингом с запретом фрагментации: ping -M do -s 1472 адрес и подбираю размер. Лечится либо приведением MTU в порядок на интерфейсе, либо MSS clamping на маршрутизаторе: --clamp-mss-to-pmtu.

Симптом описывают как «сеть моргает» и ищут потери, хотя потерь нет. Признак, по которому узнают MTU: висят именно большие передачи, ssh коннектится, а вывод команды с длинным ответом обрывается.

Follow-up интервьюера: где чаще всего встречается? — в туннелях: VPN, GRE, IPIP съедают часть кадра, а MTU внутри туннеля забывают уменьшить.

28. Как понять, теряются пакеты в сети или тормозит приложение?

Разделяю ответственность инструментами. Со стороны сети — mtr вместо traceroute: он показывает потери и задержку по каждому хопу за длительный интервал, при этом потери на промежуточном хопе при чистом последнем обычно означают лишь rate limit на ICMP, а не реальную проблему. На самом хосте — ip -s link и ethtool -S на предмет errors и drops, netstat -s для ретрансмитов TCP. Со стороны приложения — время до первого байта в curl -w: если TCP-рукопожатие быстрое, а ответ идёт долго, сеть ни при чём. Финальный аргумент, если спорим со смежниками, — tcpdump с двух сторон одновременно: видно, ушёл ли пакет и дошёл ли он.

Опираются на один ping и делают вывод. Хороший ответ явно отделяет метрику сети от метрики приложения и заканчивается словами «снять дамп с обеих сторон».

Follow-up интервьюера: curl показывает большой time_namelookup. Что это? — сеть здесь ни при чём, тормозит DNS: недоступный резолвер, таймаут на первом сервере в resolv.conf, поиск по search-доменам.

Блок 5. Разбор инцидентов

29. «Сервер тормозит». Ваши первые пять минут?

Сначала уточняю, что значит тормозит и с какого момента: тормозит для всех или для одного клиента, деградация или полный отказ, что менялось последним. Дальше стандартный обход за минуту: uptime — три числа LA и понимание, растёт нагрузка или спадает; vmstat 1 5 — распределение по us/sy/wa/id и колонки si/so, чтобы сразу отделить процессор от диска и от свопа; top с сортировкой по CPU и по памяти — есть ли один очевидный виновник; df -h и df -i — не кончилось ли место; dmesg -T | tail — OOM, ошибки диска, сетевые дропы. За эти пять минут я не чиню, а сужаю до одной подсистемы: CPU, память, диск, сеть или само приложение. И параллельно смотрю, что деплоили за последние сутки, потому что это самая частая причина.

Начинают перезагружать сервис до того, как поняли причину, и убивают улики. Ждут проговорённой последовательности и явной фразы «сначала снимаю состояние, потом чиню».

Follow-up интервьюера: а если ничего из этого не показало аномалий? — значит проблема выше по стеку: смежный сервис, база, DNS или балансировщик; тогда смотрю время ответа зависимостей со стороны приложения.

30. Ночью кончилось место на /var. Что делаете?

Сначала быстро вернуть сервис в работу, потом разбираться. Смотрю df -h /var и df -i /var, потом du -xh --max-depth=1 /var и спускаюсь по самому толстому каталогу. Типичные виновники: журнал systemd без ограничения, логи приложения без ротации, кеш пакетного менеджера, дампы ядра, забытые бэкапы. Быстрые безопасные действия — journalctl --vacuum-size=500M, чистка кеша пакетов, ротация логов вручную через logrotate -f. Отдельно проверяю удалённые открытые файлы через lsof +L1: если место держит удалённый лог, никакая чистка не поможет, нужен перезапуск процесса. Что нельзя делать — удалять активный лог командой rm: место не освободится, а приложение продолжит писать в никуда.

Удаляют большой лог через rm, видят, что df не изменился, и не понимают почему. И не ставят после инцидента ограничение размера, поэтому через месяц всё повторяется.

Follow-up интервьюера: как сделать так, чтобы это не повторилось? — SystemMaxUse в journald, logrotate с maxsize, алерт на заполнение на 80% и отдельный раздел под /var, чтобы переполнение не убивало корень.

31. Приложение отвечает медленно, но CPU, память и диск в норме. Куда смотреть?

Значит ждём чего-то внешнего. Проверяю зависимости: время ответа базы, кеша, соседних сервисов, DNS. Дальше — исчерпание не самых очевидных ресурсов: лимит открытых файлов (ulimit -n и /proc/PID/limits, в логах это выглядит как Too many open files), переполнение очереди на приём соединений (ss -lnt покажет Send-Q как размер backlog и Recv-Q как текущую очередь, плюс счётчик listen overflow в netstat -s), исчерпание пула соединений или потоков внутри самого приложения, блокировки в базе. Отдельно — не упёрлись ли в лимиты cgroup, если сервис живёт под ограничением systemd или в контейнере: снаружи ресурсы свободны, а внутри квота выбрана.

Смотрят только классическую четвёрку CPU/RAM/диск/сеть и упираются в тупик. Сильный ответ упоминает лимиты дескрипторов, backlog и cgroup-квоты.

Follow-up интервьюера: сервис отвечает быстро на localhost, но медленно снаружи. Где искать? — балансировщик, TLS-рукопожатие, MTU или разрешение имён на клиентской стороне.

32. Машина не отвечает по SSH. Действия?

Сначала отделяю недоступность машины от недоступности sshd. Проверяю, отвечает ли что-то ещё на этом хосте — другой порт, мониторинг, метрики. Если хост в сети, но порт 22 молчит, вероятны варианты: sshd упал или не смог запуститься после правки конфига, firewall закрыл порт, кончились дескрипторы или память и новый форк не создаётся, корень заполнен и sshd не может создать сессию. Если хост не отвечает вовсе — иду в консоль гипервизора или в IPMI: там видно kernel panic, приглашение emergency mode или сообщение о недоступном корне. Перезагрузка вслепую — последнее средство, потому что она уничтожает состояние, по которому и восстанавливается причина.

Сразу перезагружают. Ждут упоминания консоли вне сети как единственного надёжного канала и понимания, что «не пингуется» и «не пускает по ssh» — разные диагнозы.

Follow-up интервьюера: как заранее подстелить соломки? — держать доступ в консоль гипервизора, ставить второй sshd на другом порту и резервировать root-квоту в файловой системе, чтобы заполнение диска не блокировало вход.

33. После обновления пакетов сервис сломался. Как откатываться?

Сначала подтверждаю связь: journalctl и история пакетного менеджера — dnf history или /var/log/apt/history.log — покажут, что и когда обновилось. Дальше выбираю способ отката. В rpm-мире есть dnf history undo, что честно возвращает предыдущий набор версий. В deb-мире надёжнее явная установка нужной версии из кеша /var/cache/apt/archives с последующим apt-mark hold, чтобы следующее обновление не вернуло проблему. Отдельно проверяю, не в пакете ли дело вовсе, а в конфиге: при обновлении мог появиться .rpmnew или dpkg мог спросить про конфликт конфигурации и оставить новый файл. И сразу фиксирую версию в системе управления конфигурацией, иначе через неделю всё повторится на соседних машинах.

Откатывают на одной машине и забывают зафиксировать версию, из-за чего проблема возвращается. Ещё частый провал — не проверяют .rpmnew и .dpkg-dist.

Follow-up интервьюера: а если откат невозможен, потому что схема базы уже мигрировала? — тогда откат приложения ломает данные; правильный ответ — двигаться вперёд с исправлением, а на будущее делать миграции обратно совместимыми.

34. Как доказать, что проблема не на вашей стороне?

Собираю симметричные измерения. Со своей стороны — что сервис отвечает локально: curl на 127.0.0.1 с таймингами, метрики времени обработки внутри приложения. Со стороны сети — mtr в обе стороны и tcpdump одновременно на своём хосте и на хосте клиента: видно, ушёл ли ответ и дошёл ли запрос. Со стороны зависимостей — время ответа базы и смежных сервисов за тот же интервал. Дальше сопоставляю таймлайн: когда началось, что менялось у нас, что менялось у них. Важна интонация: цель не победить в споре, а сузить область, поэтому вывод формулирую как «запрос до нас не доходит, вот дамп», а не «у вас всё сломано».

Приносят один график и утверждение. Ждут именно парного измерения с двух сторон и сопоставления по времени.

Follow-up интервьюера: клиент говорит, что видит таймауты, а в ваших логах запросов нет вообще. О чём это? — почти наверняка запросы не доходят: балансировщик, DNS, firewall или неверный адрес; смотреть надо дамп на входящем интерфейсе.

35. Что должно быть в постмортеме?

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

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

Follow-up интервьюера: что делать, если причина так и не найдена? — так и написать, зафиксировать гипотезы и добавить телеметрию, которой не хватило; честный постмортем без причины полезнее выдуманной причины.

Блок 6. Доступы, безопасность, эксплуатация

36. Permission denied (publickey). Как чинить?

Сначала смотрю глазами клиента: ssh -vvv покажет, какие ключи предлагались и на каком этапе сервер отказал. Дальше со стороны сервера — journalctl -u sshd, там причина обычно написана прямым текстом. Типичные виновники: права на домашний каталог и на ~/.ssh шире, чем ожидает sshd, и он молча отвергает ключ (нужны 700 на каталог и 600 на authorized_keys, и домашний каталог не должен быть доступен на запись группе); ключ положен не тому пользователю; в sshd_config стоит AllowUsers или PubkeyAuthentication no; на системах с SELinux у файла неверный контекст, лечится restorecon -R -v ~/.ssh; или клиент предлагает не тот ключ, потому что в агенте их слишком много и сервер обрывает после нескольких попыток.

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

Follow-up интервьюера: почему опасно перезапускать sshd вслепую при правке конфига? — при ошибке в конфиге демон не поднимется и вы потеряете доступ; поэтому сначала sshd -t, потом reload, и вторая сессия открыта до конца проверки.

37. Чем sudo отличается от su и что такое setuid?

su открывает сессию другого пользователя целиком и требует его пароль; после этого всё, что вы делаете, идёт от его имени и в логе не видно, кто именно это был. sudo выполняет одну команду по правилам из /etc/sudoers, спрашивает ваш собственный пароль и пишет в лог, кто и что запустил — поэтому на проде используют именно его, ради разграничения и аудита. setuid — это бит на исполняемом файле, из-за которого процесс запускается с правами владельца файла, а не запускающего; именно так работает passwd, которому нужен доступ к /etc/shadow. Сам sudo тоже setuid-бинарь. Важное следствие: любой лишний setuid-root файл в системе — потенциальный путь к повышению привилегий, поэтому их периодически инвентаризируют через find / -perm -4000.

Ограничиваются формулировкой «sudo безопаснее». Ждут слов про аудит и про то, что sudo ALL без ограничений по сути равен раздаче root.

Follow-up интервьюера: чем NOPASSWD в sudoers опасен и когда оправдан? — оправдан для конкретных команд в автоматизации; опасен как ALL, потому что тогда любая компрометация пользователя сразу даёт root.

38. Что такое capabilities и зачем они, если есть root?

Права root разбиты на отдельные возможности: CAP_NET_BIND_SERVICE — слушать порты ниже 1024, CAP_NET_ADMIN — управлять сетью, CAP_SYS_TIME — менять время, и так далее. Это позволяет выдать процессу ровно то, что ему нужно, вместо полного root. Практический пример: чтобы веб-сервер слушал 80-й порт, не обязательно запускать его от root — достаточно setcap cap_net_bind_service=+ep на бинарь или AmbientCapabilities= в юните systemd. Смотреть текущий набор — getpcaps PID или поле Cap в /proc/PID/status. Тот же механизм лежит в основе контейнеров: docker по умолчанию оставляет процессу урезанный набор, поэтому внутри контейнера «root» заметно слабее настоящего.

Не знают, что root в контейнере ограничен capabilities, и считают его равным хостовому. Второй провал — не подозревают, что setcap слетает при обновлении пакета.

Follow-up интервьюера: почему после обновления пакета сервис перестал биндиться на 80? — новый бинарь пришёл без capabilities, их надо выставлять заново или задавать через systemd, что надёжнее.

39. Как выдать команде доступ на тридцать серверов и не потерять управление?

Ключевой принцип — доступ не раздаётся руками. Учётки и ключи раскатываются из системы управления конфигурацией или из централизованного каталога, чтобы отзыв делался в одном месте, а не обходом тридцати машин. Личные учётные записи, не общий admin: иначе в логе не видно, кто что сделал. Права выдаются через группы и точечные правила sudo, а не полным ALL. Вход по ключам, парольная аутентификация выключена, root по ssh запрещён. Для боевого контура правильнее bastion с записью сессий, чтобы прямых маршрутов на прод не было вовсе. И регулярная ревизия: кто ещё имеет доступ, у кого он остался после смены роли или увольнения.

Отвечают «раскатать authorized_keys ансиблом» и на этом останавливаются. Ждут ещё двух вещей: как отзывается доступ и как в логах видно конкретного человека.

Follow-up интервьюера: сотрудник ушёл. Ваши действия? — удалить из каталога или из группы в системе конфигураций, прогнать её по парку, проверить остаточные ключи и активные сессии, ротировать общие секреты, к которым он имел доступ.

40. SELinux мешает сервису. Что делать кроме setenforce 0?

Сначала подтверждаю, что дело в нём: ausearch -m AVC -ts recent или journalctl | grep AVC покажут отказ с указанием контекста и операции. Дальше самый частый случай — неверный контекст файла, например веб-контент положили в нестандартный каталог: лечится semanage fcontext -a с нужным типом и restorecon -Rv. Второй случай — нужна булева переменная, вроде разрешения веб-серверу ходить по сети: getsebool -a и setsebool -P. И только если ни то, ни другое не подходит, генерируют локальный модуль через audit2allow, обязательно посмотрев глазами, что именно он разрешает. Полное отключение — это не решение, а снятие защиты со всей машины ради одного сервиса.

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

Follow-up интервьюера: как временно проверить гипотезу, не выключая защиту совсем? — перевести в permissive для конкретного домена через semanage permissive -a: нарушения будут логироваться, но не блокироваться.

41. Как обновлять прод, чтобы ничего не уронить?

Порядок, а не смелость. Обновления сначала едут на стенд, потом на канареечную машину, потом на остальной парк. Версии пакетов зафиксированы и одинаковы во всём парке, иначе воспроизвести проблему невозможно. Перед обновлением снимается снапшот или проверяется, что бэкап действительно восстанавливается, и заранее описан план отката. Ноды выводятся из балансировки по одной, после каждой проверяется здоровье сервиса, и только потом берётся следующая. Обновление ядра и всё, что требует перезагрузки, планируется в окно, а для критичных машин рассматривают live patching. И отдельно — обновления безопасности не откладываются бесконечно ради стабильности: это тоже риск, просто отложенный.

Говорят про «сначала на тесте» и не могут ответить, как выглядит откат и как проверяется здоровье после каждой ноды.

Follow-up интервьюера: что делать, если обновление уже раскатано на весь парк и сломало сервис? — откат по истории пакетного менеджера с фиксацией версии, параллельно поднимать канареечную схему, чтобы это не повторилось.

42. Что вы проверите на свежем сервере перед выкаткой в прод?

Базовый набор, который я обычно держу отдельным чеклистом. Доступ: вход по ключам, парольная аутентификация и root по ssh выключены, личные учётки заведены. Сеть: открыты только нужные порты, правила firewall описаны в конфигурации, а не набраны руками. Время: NTP работает — рассинхронизация часов ломает логи, TLS и распределённые системы. Наблюдаемость: агент мониторинга и сбор логов подключены до, а не после инцидента, журнал персистентный и ограничен по размеру. Обслуживание: настроена ротация логов, автоматические обновления безопасности, свободное место с запасом и алерт на заполнение. Ресурсы: лимиты дескрипторов подняты под нагрузку сервиса. И финально — машина описана в системе управления конфигурацией, чтобы её можно было воспроизвести с нуля.

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

Follow-up интервьюера: почему NTP в этом списке? — разъехавшиеся часы дают невозможность сопоставить логи между машинами, ошибки проверки сертификатов и разваливающийся консенсус в кластерах.

Частые вопросы

Сколько вопросов реально задают на собеседовании Linux-администратора?

Обычно 10–20 за час, и почти всегда с уходом вглубь по одному-двум. Ценность подборки не в том, чтобы выучить 42 ответа, а в том, чтобы закрыть пробелы в тех блоках, где вы плаваете.

Нужно ли знать команды наизусть?

Нет. Никто не ждёт, что вы вспомните все ключи find. Ждут, что вы назовёте нужный инструмент и объясните, что рассчитываете увидеть в выводе.

Что делать, если не знаете ответа?

Рассуждать вслух и честно обозначить границу: «с этим не сталкивался, но полез бы смотреть туда-то». Молчание и попытка угадать читаются хуже, чем признание пробела.

Подготовка к собеседованию

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

Мок-собесы и разбор ваших ответов — в менторстве и закрытом чате.