Смонтировать сетевую шару и не подвесить процессы, когда сервер отвалится.
Убрать пароль из fstab
Файл
Отцепить зависшую шару
Проверил на tmpfs: после
Посмотреть, что отдаёт сервер
Нюанс:
Монтировать по требованию, а не при загрузке
Нюанс:
Не залипнуть на медленном NFS
Нюанс: man про
А вы сетевые шары монтируете через fstab или отдаёте systemd с automount?
#Linux #NFS #Samba #systemd #DevOps
Убрать пароль из fstab
mount -t cifs -o credentials=/etc/cifs-creds \
//10.0.0.10/share /mnt/samba
Файл
/etc/cifs-creds из трёх строк: username=, password=, domain=. Нюанс: chmod 600 на нём — целиком на вашей совести, mount права не проверяет и с файлом 644 отработает молча. Заодно проверьте, что каталог с ним не уезжает в бэкап открытым текстом.Отцепить зависшую шару
umount -l /mnt/nfs
Проверил на tmpfs: после
-l каталог пуст и монтирования в mount больше нет, но процесс, державший файл открытым, спокойно дочитал его по старому дескриптору. Нюанс: -l убирает точку из дерева, а не освобождает ресурсы — пока живы процессы, ФС остаётся. Ищите их через lsof +D до того, как отцепите, иначе искать будет негде.-f имеет смысл только для NFS и только вместе с недоступным сервером, для cifs он почти ничего не даёт.Посмотреть, что отдаёт сервер
showmount -e 10.0.0.10
Нюанс:
showmount говорит по протоколу MOUNT, которого в NFSv4 нет вообще. На сервере с отключёнными v2 и v3 получите clnt_create: RPC: Program not registered — и это не значит, что сервер мёртв. Для v4 просто монтируйте корень экспорта: mount -t nfs4 10.0.0.10:/ /mnt.Монтировать по требованию, а не при загрузке
//10.0.0.10/share /mnt/samba cifs
noauto,x-systemd.automount,_netdev,
credentials=/etc/creds 0 0
Нюанс:
_netdev нужен наравне с x-systemd.automount. Без него systemd не знает, что монтирование сетевое, и может дёрнуть его до поднятия интерфейсов. Плюс x-systemd.idle-timeout= отцепит шару после простоя — на нестабильном канале это лучше, чем висящая точка.Не залипнуть на медленном NFS
mount -t nfs -o soft,timeo=50,retrans=2 \
10.0.0.10:/data /mnt/nfs
timeo в децисекундах, так что 50 — это 5 секунд. По умолчанию для TCP стоит 600, то есть минута, да ещё с линейным ростом после каждой переотправки.Нюанс: man про
soft пишет прямо — silent data corruption. Приложение получит I/O error, и если оно его не обработает, запись потеряется тихо. Для баз и любой записи оставляйте hard. И не тащите из старых шпаргалок intr — опция игнорируется с ядра 2.6.25.А вы сетевые шары монтируете через fstab или отдаёте systemd с automount?
#Linux #NFS #Samba #systemd #DevOps
👍5
Не оставить пароль в bash_history и не удивиться, что он всё равно там оказался.
Скрыть команду от истории
Ведущий пробел, и строка не попадёт в
Если пусто — трюк не сработает вообще, а вы будете уверены в обратном.
Исправить опечатку в предыдущей команде
Заменяет и сразу выполняет. Нюанс: только первое вхождение. Проверил на
Открыть длинную команду в редакторе
Вытаскивает последнюю команду в
Оживить терминал после вывода бинарника
Отвязать процесс от закрывающейся сессии
Нюанс:
И про главное ограничение трюка с пробелом: он прячет команду от файла истории, но не от системы. Пока процесс жив, его аргументы видны в
А чем вы правите длинные пайплайны —
#Linux #Bash #Terminal #Security #DevOps
Скрыть команду от истории
mysql -u root -p'super_secret'
Ведущий пробел, и строка не попадёт в
~/.bash_history. Работает, если в HISTCONTROL есть ignorespace. Нюанс: в Ubuntu это уже настроено, но по-разному. В /etc/skel/.bashrc стоит ignoreboth, а в root-сессии у меня было ignoredups:ignorespace. Проверьте своё:
echo "$HISTCONTROL"
Если пусто — трюк не сработает вообще, а вы будете уверены в обратном.
Исправить опечатку в предыдущей команде
systemctl status nginx-confg
^confg^config
Заменяет и сразу выполняет. Нюанс: только первое вхождение. Проверил на
echo aaa bbb aaa — после ^aaa^XXX получилось XXX bbb aaa. Для всех вхождений другая конструкция:
!!:gs/aaa/XXX/
Открыть длинную команду в редакторе
fc
Вытаскивает последнюю команду в
$EDITOR, после сохранения bash её выполняет. Нюанс: порядок поиска редактора — FCEDIT, потом EDITOR, и только потом vi по умолчанию. На голом сервере без vi получите bash: vi: command not found и никакого редактирования. Заранее пропишите export FCEDIT=nano или что вам ближе.Оживить терминал после вывода бинарника
reset
clear только прокручивает экран, а reset переинициализирует терминал целиком. Если и это не помогает — stty sane возвращает настройки ввода, когда не видно набираемых символов.Отвязать процесс от закрывающейся сессии
bg
disown -h %1
Нюанс:
-h и без него — разные вещи. С -h задача остаётся в jobs, но не получит SIGHUP при закрытии терминала. Без флага задача исчезает из таблицы совсем. Проверил оба варианта, разница именно в этом.И про главное ограничение трюка с пробелом: он прячет команду от файла истории, но не от системы. Пока процесс жив, его аргументы видны в
ps -eo args любому пользователю. Пароль в командной строке остаётся паролем в командной строке — читайте его из файла или переменной окружения.А чем вы правите длинные пайплайны —
fc или сразу пишете в файл?#Linux #Bash #Terminal #Security #DevOps
👍4
Собрать дерево каталогов одной строкой и не получить папку с фигурными скобками в имени.
Создать вложенную структуру
Нюанс: раскрытие скобок — фича bash, а не mkdir. В
Если скрипт начинается с
Вернуться в предыдущий каталог
Нюанс:
Ходить по каталогам стеком
Нюанс: лишний
Пройти сквозь симлинк
Проверил на своём симлинке: обычный
Снести пустую цепочку каталогов
Поднимается снизу вверх, пока каталоги пустые. Нюанс: наткнувшись на непустой, останавливается с
А вы по дереву каталогов ходите
#Linux #Bash #Terminal #Scripting #DevOps
Создать вложенную структуру
mkdir -p project/src/{configs,utils,tests}
Нюанс: раскрытие скобок — фича bash, а не mkdir. В
sh строка отработает буквально, создав каталог с именем {configs,utils,tests} — проверил, ошибки при этом никакой. То же будет от пробела после запятой и от одного элемента без запятой: {only} останется как есть.Если скрипт начинается с
#!/bin/sh, скобки не использовать.Вернуться в предыдущий каталог
cd -
Нюанс:
cd - печатает путь в stdout. В скрипте это мусор в выводе, а $(cd -) вообще бесполезен — подстановка уходит в подоболочку, и рабочий каталог самого скрипта не меняется. Для скриптов тише так:
cd "$OLDPWD"
Ходить по каталогам стеком
pushd /var/log >/dev/null
popd >/dev/null
Нюанс: лишний
popd возвращает directory stack empty и код 1. Под set -e скрипт на этом падает — а такое легко получить, если между pushd и popd стоит выход по ошибке. Перенаправление в /dev/null тоже нужно: обе команды печатают содержимое стека.Пройти сквозь симлинк
cd -P /var/run
Проверил на своём симлинке: обычный
cd оставляет PWD равным /tmp/dd/link, с -P он становится /tmp/dd/real. Нюанс не в самом переходе, а в том, что будет дальше. Из link/sub команда cd .. вернёт в link, а cd -P .. — в real. Скрипт, который ходит относительными путями через симлинк, легко уедет не туда. Заодно pwd -P показывает физический путь, когда pwd показывает логический.Снести пустую цепочку каталогов
rmdir -p a/b/c
Поднимается снизу вверх, пока каталоги пустые. Нюанс: наткнувшись на непустой, останавливается с
Directory not empty — но то, что успел удалить ниже, уже удалено. Возврата нет, так что для глубоких цепочек лучше сначала посмотреть find a -type d -empty.А вы по дереву каталогов ходите
pushd или всё-таки алиасами и cd -?#Linux #Bash #Terminal #Scripting #DevOps
👍6
Собрать архив с исключениями и не обнаружить потом, что исключения не сработали.
Исключить каталог из архива
Нюанс:
Достать один файл из архива
Нюанс: при упаковке по абсолютному пути tar срезает ведущий слеш и пишет
Дописать или удалить файл в архиве
Нюанс: только для несжатых архивов. На
Сжать быстрее и плотнее gzip
На моих тестовых данных zstd дал 199 байт против 225 у gzip. Нюанс: если пакета
Не перезаписать свежие файлы при распаковке
Работает: файл, который новее архивного, остаётся нетронутым, в выводе
Про сравнение архива с диском:
А вы чем сжимаете бэкапы — gzip по привычке или уже переехали на zstd?
#Linux #tar #Backup #Bash #DevOps
Исключить каталог из архива
tar --exclude='data/logs' -czf arch.tgz data
Нюанс:
--exclude обязан стоять до источника. Поставил после — tar честно предупредил --exclude 'data/logs' has no effect и всё равно упаковал логи. Второе: шаблон сравнивается с тем, как путь записан внутри архива. Упаковываете data, значит исключать надо data/logs, а не /tmp/ta/data/logs — с абсолютным путём совпадения не будет.Достать один файл из архива
tar -tf arch.tar | grep app.conf
tar -xf arch.tar tmp/ta/data/conf/app.conf
Нюанс: при упаковке по абсолютному пути tar срезает ведущий слеш и пишет
Removing leading '/' from member names. Поэтому распаковать по тому же абсолютному пути не выйдет — получите Not found in archive. Сначала посмотрите список через -t, потом копируйте путь оттуда.Дописать или удалить файл в архиве
tar -rf arch.tar newfile.txt
tar --delete -f arch.tar oldfile.txt
Нюанс: только для несжатых архивов. На
.tgz обе команды падают с Cannot update compressed archives и Error is not recoverable: exiting now. Чтобы поправить сжатый архив, его придётся распаковать целиком.Сжать быстрее и плотнее gzip
tar --zstd -cf arch.tar.zst data
На моих тестовых данных zstd дал 199 байт против 225 у gzip. Нюанс: если пакета
zstd в системе нет, tar создаст файл нулевого размера и завершится с кодом 2. Файл при этом лежит на месте и выглядит как архив — в скрипте бэкапа такое заметят не сразу. Проверяйте код возврата, а не наличие файла.Не перезаписать свежие файлы при распаковке
tar -xf arch.tar --keep-newer-files
Работает: файл, который новее архивного, остаётся нетронутым, в выводе
Current 'data/logs/a.log' is newer or same age. Нюанс: код возврата при этом 2, как при ошибке. Под set -e скрипт упадёт, хотя всё прошло по плану.Про сравнение архива с диском:
tar -df arch.tar показывает Mod time differs и Size differs по каждому расхождению. Удобно проверить бэкап, не распаковывая.А вы чем сжимаете бэкапы — gzip по привычке или уже переехали на zstd?
#Linux #tar #Backup #Bash #DevOps
👍7
Добавить пользователя в группу и не выкинуть его при этом из sudo
Добавить во вторичную группу
Нюанс, ради которого стоит перечитать свои скрипты: без
Удалить из группы
Печатает
Сменить GID существующей группы
Нюанс:
Создать группу в скрипте
Нюанс: обычный
Удалить группу
Нюанс: если группа у кого-то основная, команда откажет —
Про проверку:
А вы группы раскатываете Ansible-модулями или скриптом с
#Linux #Security #Ansible #DevOps #Bash
---
Что нашлось при проверке
Главную ловушку воспроизвёл. Завёл lisa в
Находка сверх исходника: `groupmod -g` оставляет файлы без группы. Сменил GID у
`groupadd -f` для идемпотентности. Обычный вызов на существующей группе — код 9. В скриптах инициализации, о которых говорит сам исходник, это ровно та причина, по которой люди начинают городить проверки через
`groupdel` на основной группе.
`groupadd -r` даёт GID из системного диапазона. У меня 996 против 2002 у обычной. Исходник пишет «GID до 1000» — подтвердилось.
Из пятнадцати пунктов оставил шесть. Убрал
Метрики: объём 2027, подводка 67 символов, форма — инфинитив цели. Строк кода длиннее 60 нет, восклицательных нет, хештегов 5.
Добавить во вторичную группу
usermod -aG developers lisa
Нюанс, ради которого стоит перечитать свои скрипты: без
-a флаг -G не добавляет, а заменяет весь список. Было sudo,developers,ops — после usermod -G developers lisa осталось только developers. Ни ошибки, ни предупреждения, код возврата 0. Человек узнает об этом, когда в следующий раз наберёт sudo.Удалить из группы
gpasswd -d bob developers
Печатает
Removing user bob from group developers. В отличие от usermod -G, трогает ровно одну группу.Сменить GID существующей группы
groupmod -g 2000 developers
find / -xdev -nogroup 2>/dev/null
chgrp -R developers /data
Нюанс:
groupmod меняет запись в /etc/group, но файлы на диске остаются со старым числовым GID. У меня после смены ls -ld /data показал вместо имени голое 1004 — каталог стал ничьим. Ищите такие через find -nogroup и чините chgrp -R, иначе доступ к данным потеряется молча.Создать группу в скрипте
groupadd -f developers
groupadd -r pgsql
Нюанс: обычный
groupadd на существующей группе возвращает код 9 и роняет скрипт под set -e. Флаг -f делает операцию идемпотентной — то, что нужно для повторных прогонов Ansible или cloud-init. А -r создаёт системную группу: у меня она получила GID 996, обычная — 2002.Удалить группу
groupdel testers
Нюанс: если группа у кого-то основная, команда откажет —
cannot remove the primary group of user 'bob', код 8. Вторичную удалит без вопросов, и у пользователей она просто исчезнет из списка.Про проверку:
id -nG lisa показывает актуальный список из базы, а groups в чужой открытой сессии — то, что было на момент входа. Пользователь не увидит новых групп, пока не перелогинится или не выполнит newgrp.А вы группы раскатываете Ansible-модулями или скриптом с
groupadd -f?#Linux #Security #Ansible #DevOps #Bash
---
Что нашлось при проверке
Главную ловушку воспроизвёл. Завёл lisa в
sudo, developers, ops. После usermod -G developers lisa осталась одна developers, код возврата 0, ни слова в выводе. Исходник называет это в «честном минусе», но в самом пункте 7 стоит только скобка «обязательно -a» — я вынес разбор в тело, потому что это главное содержание всей темы.Находка сверх исходника: `groupmod -g` оставляет файлы без группы. Сменил GID у
developers с 1004 на 2000 — каталог /data стал показывать 1004 вместо имени. Формально данные не потеряны, но группа к ним больше не имеет отношения. Исходник даёт команду без единой оговорки. Добавил find -nogroup и chgrp -R как лечение.`groupadd -f` для идемпотентности. Обычный вызов на существующей группе — код 9. В скриптах инициализации, о которых говорит сам исходник, это ровно та причина, по которой люди начинают городить проверки через
grep /etc/group. Флага -f в исходнике нет.`groupdel` на основной группе.
cannot remove the primary group of user 'bob', код 8. Проверил обе ветки — вторичная удаляется молча.`groupadd -r` даёт GID из системного диапазона. У меня 996 против 2002 у обычной. Исходник пишет «GID до 1000» — подтвердилось.
Из пятнадцати пунктов оставил шесть. Убрал
groups, id, chgrp, find -group, newgrp, groupmod -n, gpasswd -A как отдельные блоки — по ним нечего добавить сверх справки. Мысль про groups против id вплёл в текст: она объясняет, почему пользователь «не видит» новую группу.Метрики: объём 2027, подводка 67 символов, форма — инфинитив цели. Строк кода длиннее 60 нет, восклицательных нет, хештегов 5.
👍3
Закрыть периметр правилами iptables и не остаться при этом за дверью вместе с атакующим.
Посмотреть, что слушает наружу
Даёт порт, состояние и процесс:
Найти, кто держит больше всего соединений
Нюанс: в шпаргалках этот однострочник идёт без
Закрыть вход по умолчанию
Нюанс: в подборках порядок обратный — сначала
Заодно
Ограничить SSH подсетью и числом сессий
Оба правила встали. Полезная деталь:
Отправить подсеть в никуда без файрвола
Нюанс: это не тихий дроп. Локальные попытки получают отлуп сразу —
И общее: всё это живёт до перезагрузки.
А вы вредоносные IP баните iptables напрямую или отдаёте это CrowdSec и fail2ban?
#Linux #Security #iptables #Networking #DevOps
Посмотреть, что слушает наружу
ss -tulpn
Даёт порт, состояние и процесс:
0.0.0.0:8099 users:(("python3",pid=3545,fd=3)). Первое, с чего начинается любой аудит — половина находок обычно в том, что сервис слушает 0.0.0.0 вместо 127.0.0.1.Найти, кто держит больше всего соединений
ss -Hntu | awk '{print $5}' |
sed 's/:[^:]*$//' | sort | uniq -c | sort -rn
Нюанс: в шпаргалках этот однострочник идёт без
-H и с cut -d: -f1. Оба места ломаются. Без -H в подсчёт попадает строка заголовка, и в топе появляется несуществующий адрес Local. А cut по первому двоеточию режет IPv6: адрес [2001:db8::2]:54321 превращается в [2001. Отсечение через sed берёт только порт с конца.Закрыть вход по умолчанию
iptables -A INPUT -m conntrack \
--ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
Нюанс: в подборках порядок обратный — сначала
-F, потом -P INPUT DROP, а разрешающие правила ниже. Между этими двумя строками сессия уже мертва, и до правил вы не дойдёте. Политика ставится последней, всегда.Заодно
-m state там устаревший, актуален -m conntrack --ctstate.Ограничить SSH подсетью и числом сессий
iptables -A INPUT -p tcp --dport 22 \
! -s 10.0.0.0/24 -j DROP
iptables -A INPUT -p tcp --dport 22 \
-m connlimit --connlimit-above 3 -j REJECT
Оба правила встали. Полезная деталь:
iptables -S показывает, что модуль сам дописал --connlimit-mask 32 --connlimit-saddr — лимит считается по одному адресу, а не по подсети. Если нужен другой охват, маску задавайте явно.Отправить подсеть в никуда без файрвола
ip route add blackhole 192.168.10.0/24
Нюанс: это не тихий дроп. Локальные попытки получают отлуп сразу —
ping вернул connect: Invalid argument, curl завершился с кодом 7. Для исходящего трафика это плюс, ошибка приходит мгновенно вместо таймаута, но маскировки не ждите.И общее: всё это живёт до перезагрузки.
netfilter-persistent для правил, ip route — в конфигурацию сети, иначе следующий ребут откроет всё обратно.А вы вредоносные IP баните iptables напрямую или отдаёте это CrowdSec и fail2ban?
#Linux #Security #iptables #Networking #DevOps
👍4
Разобрать строку штатным <regex.h> и не получить молчаливое «нет совпадения».
Проверял на glibc, gcc 13.3, Ubuntu 24.04. Все фрагменты ниже собраны в одну программу и скомпилированы с
Скомпилировать шаблон
Понять, почему не скомпилировалось
Буфер обязан быть массивом. На незакрытой скобке
Сопоставить и достать группы
Не забыть освободить
Замерил: 100 тысяч компиляций в цикле без
Где POSIX молчит вместо ошибки
Самое неприятное не в том, чего API не умеет, а в том, как он об этом сообщает:
Просмотры и именованные группы падают на компиляции — это честно. А вот
А вы в C-утилитах держитесь
#Linux #C #POSIX #regex #DevOps
Проверял на glibc, gcc 13.3, Ubuntu 24.04. Все фрагменты ниже собраны в одну программу и скомпилированы с
-Wall -Wextra без единого предупреждения.Скомпилировать шаблон
regex_t re;
int rc = regcomp(&re, "^([a-z]+)=([0-9]+)$",
REG_EXTENDED);
REG_EXTENDED включает ERE: скобки и + работают без обратных слешей. Без флага получите BRE, где группа пишется как \(...\).Понять, почему не скомпилировалось
char err[256];
if (rc != 0) {
regerror(rc, &re, err, sizeof err);
fprintf(stderr, "regcomp: %s\n", err);
}
Буфер обязан быть массивом. На незакрытой скобке
[a-z получите Unmatched [, [^, [:, [., or [=. Нюанс: regfree вызывайте только после успешного regcomp, для неудачной компиляции освобождать нечего.Сопоставить и достать группы
regmatch_t m[3];
const char *s = "app=100";
if (regexec(&re, s, 3, m, 0) == 0)
printf("%.*s\n", (int)(m[1].rm_eo - m[1].rm_so),
s + m[1].rm_so);
m[0] — всё совпадение, m[1] и дальше — группы по порядку. На app=100 вышло app в первой группе и 100 во второй. Нюанс: смещения в байтах, не в символах. В строке ключ=42 вторая группа начинается с байта 9, хотя символов перед ней пять. И если компилировали с REG_NOSUB, массив m не заполняется вовсе.Не забыть освободить
regfree(&re);
Замерил: 100 тысяч компиляций в цикле без
regfree раздули процесс до 1.4 ГБ, с ним — 1.8 МБ. В демоне, который компилирует шаблон на каждый запрос, это вопрос часов.Где POSIX молчит вместо ошибки
Самое неприятное не в том, чего API не умеет, а в том, как он об этом сообщает:
\d+ на "abc 123" -> No match
<.*?> на "<a><b>" -> <a><b>
(?<=x)y -> Invalid preceding regular expression
Просмотры и именованные группы падают на компиляции — это честно. А вот
\d компилируется и тихо ничего не находит, вместо него нужен [0-9]. И .*? не ошибка, а просто жадный .*: вернул всю строку вместо <a>. Привычки из PCRE здесь ломают логику молча.А вы в C-утилитах держитесь
<regex.h> или сразу тянете PCRE2?#Linux #C #POSIX #regex #DevOps
🔥 Знаешь только ip a? 10 неочевидных команд ip для Linux
Большинство админов знают про ip ровно две команды —
1️⃣ Вся сеть одним экраном, в цвете:
Интерфейс, состояние и адреса — по строке на каждый.
2️⃣ Куда реально уйдёт пакет:
Покажет интерфейс, шлюз и source-адрес. Незаменимо, когда маршрутов много и непонятно, какой победил.
3️⃣ Маршруты, которых нет в
ВАЖНО:
4️⃣ Сменить шлюз без риска потерять сервер:
Атомарно: нет окна без маршрута, как между
5️⃣ Дропы и ошибки на интерфейсе:
Растут errors или dropped — копай в кабель, драйвер или буферы, а не в приложение.
6️⃣ Жив ли шлюз на L2:
7️⃣ Сеть в прямом эфире:
Каждое изменение с меткой времени: упал линк, DHCP или VPN переписали маршрут. Оставь в tmux и лови, кто ломает сеть по ночам.
8️⃣ Отрезать IP без фаервола:
Ответы на этот адрес уходят в никуда, TCP-сессия с ним не установится.
9️⃣ IP интерфейса в скрипте без awk-акробатики:
🔟 Процесс без сети за две команды:
В новом namespace только выключенный
Всё, что меняешь через ip, живёт до перезагрузки. Постоянные настройки — в netplan, NetworkManager или systemd-networkd.
А какую из десяти ты уже держишь в алиасах?
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Networking #iproute2 #CheatSheet #SysAdmin #DevOps
Большинство админов знают про ip ровно две команды —
ip a и ip r, а дальше ifconfig по старой памяти. Держи 10 команд, которые покажут то, чего не видно в ip a: скрытые маршруты VPN, дропы на интерфейсе и мёртвый шлюз. Проверил на iproute2 6.1.1️⃣ Вся сеть одним экраном, в цвете:
ip -br -c a
Интерфейс, состояние и адреса — по строке на каждый.
-br работает и с link.2️⃣ Куда реально уйдёт пакет:
ip route get 8.8.8.8
# какая запись в таблице сработала
ip route get fibmatch 8.8.8.8
Покажет интерфейс, шлюз и source-адрес. Незаменимо, когда маршрутов много и непонятно, какой победил.
3️⃣ Маршруты, которых нет в
ip route:
ip rule
ip route show table all
ВАЖНО:
ip route показывает только таблицу main. wg-quick с AllowedIPs = 0.0.0.0/0 уводит дефолт в таблицу 51820, а ip route делает вид, что всё как раньше.4️⃣ Сменить шлюз без риска потерять сервер:
sudo ip route replace default via <gw>
Атомарно: нет окна без маршрута, как между
del и add. Упадёт с ошибкой — старый маршрут останется на месте.5️⃣ Дропы и ошибки на интерфейсе:
ip -s link show <iface>
# двойной -s — ошибки с разбивкой: crc, frame, fifo
ip -s -s link show <iface>
Растут errors или dropped — копай в кабель, драйвер или буферы, а не в приложение.
6️⃣ Жив ли шлюз на L2:
ip neigh show dev <iface>
REACHABLE и STALE — норма. Шлюз висит в FAILED или INCOMPLETE — он не отвечает на ARP, и пинговать дальше бесполезно.7️⃣ Сеть в прямом эфире:
ip -ts monitor link route
Каждое изменение с меткой времени: упал линк, DHCP или VPN переписали маршрут. Оставь в tmux и лови, кто ломает сеть по ночам.
8️⃣ Отрезать IP без фаервола:
sudo ip route add blackhole 203.0.113.5/32
# проверить и убрать
ip route show type blackhole
sudo ip route del blackhole 203.0.113.5/32
Ответы на этот адрес уходят в никуда, TCP-сессия с ним не установится.
ip route get по нему вернёт Invalid argument — так ядро отвечает на blackhole, это не ошибка.9️⃣ IP интерфейса в скрипте без awk-акробатики:
ip -j -4 addr show dev <iface> \
| jq -r '.[0].addr_info[0].local'
-j отдаёт JSON: парсинг не сломается, когда поменяется формат вывода. Нужен пакет jq.🔟 Процесс без сети за две команды:
sudo ip netns add lab
sudo ip netns exec lab <command>
# убрать за собой
sudo ip netns del lab
В новом namespace только выключенный
lo. Удобно проверить, как приложение переживёт падение сети, не трогая хост.Всё, что меняешь через ip, живёт до перезагрузки. Постоянные настройки — в netplan, NetworkManager или systemd-networkd.
А какую из десяти ты уже держишь в алиасах?
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #Networking #iproute2 #CheatSheet #SysAdmin #DevOps
👍18🔥2
💀 CPU под 100%, а в top пусто? Ловим невидимые процессы через eBPF
Сервер греется, в шапке top
Ловим каждый запуск
Один и тот же PPID и новые процессы каждые 50 мс — вот он, виновник.
Кто плодит больше всех
Почему не strace -f
Проверил:
ВАЖНО: bcc-версия
Вместо «CPU горит, а кто — непонятно» получаешь имя процесса, аргументы и PID родителя. Дальше дело техники: поправить крон или скрипт.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #bpftrace #Troubleshooting #SysAdmin #DevOps
Сервер греется, в шапке top
us под 90%, а в списке процессов — никого. Классика: кто-то плодит процессы, которые живут 10–50 мс, а top опрашивает /proc раз в 3 секунды и их просто не застаёт. Показываю, как поймать виновника, не роняя прод.Ловим каждый запуск
# 1. В Ubuntu утилита идёт в пакете bpftrace
sudo apt install bpftrace
# Каждый execve() в реальном времени:
# время, PID и PPID родителя.
sudo execsnoop.bt
TIME PID PPID ARGS
16:55:42.684175 1112 1097 /bin/true
16:55:42.685129 1113 1097 curl --version
16:55:42.691294 1114 1097 sleep 0.05
Один и тот же PPID и новые процессы каждые 50 мс — вот он, виновник.
Кто плодит больше всех
# 2. Считаем запуски по родителю за 10 секунд.
# Подсчёт идёт ПРЯМО в ядре, без потока событий.
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_execve
{ @[comm, curtask->real_parent->tgid] = count(); }
interval:s:10 { exit(); }'
# Вывод: @[bash, 1097]: 525
# bash с PID 1097 за 10 секунд породил 525 процессов.
# 3. Смотрим, кто это и откуда он взялся
pstree -sp \<PPID>
ps -o pid,etime,cmd -p \<PPID>
Почему не strace -f
Проверил:
dd с bs=1 под strace работает в ~47 раз медленнее. И в ~37 раз — даже если трассировать только accept(), которого dd вообще не вызывает: ptrace останавливает процесс на КАЖДОМ системном вызове. eBPF процесс не останавливает и считает события в ядре.ВАЖНО: bcc-версия
execsnoop-bpfcc компилирует программу на лету и без linux-headers-$(uname -r) падает с «Unable to find kernel headers». execsnoop.bt работает через BTF, заголовки ему не нужны. Есть ли BTF в ядре: ls /sys/kernel/btf/vmlinux.Вместо «CPU горит, а кто — непонятно» получаешь имя процесса, аргументы и PID родителя. Дальше дело техники: поправить крон или скрипт.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #bpftrace #Troubleshooting #SysAdmin #DevOps
🔥5👍4
📊 Диск тормозит, а iostat показывает норму? Ищем хвост задержек
Приложение подвисает на записи, в логах таймауты к БД, а
Что на самом деле показывает iostat
ВАЖНО:
Гистограмма вместо среднего
Проверил на тестовой нагрузке (столбики убрал, чтобы влезло в экран): iostat в тот же момент показывал
Чей I/O висит
Видишь
Среднее говорит «всё хорошо», гистограмма показывает хвост, а третья команда — чей он. Дальше — по месту: вынести бэкап, развести нагрузку или идти к провайдеру с цифрами.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #Storage #Troubleshooting #SysAdmin #DevOps
Приложение подвисает на записи, в логах таймауты к БД, а
iostat рисует w_await в пару миллисекунд. Подвох в том, что iostat показывает среднее: 990 запросов по 0.1 мс и 10 по 200 мс дают в среднем 2 мс. Показываю, как достать хвост, который тонет в среднем.Что на самом деле показывает iostat
# 1. -x — расширенные колонки, раз в секунду
iostat -x 1
# r_await и w_await — СРЕДНЕЕ за интервал:
# редкие зависшие запросы в нём растворяются
ВАЖНО:
%util под 100% на SSD, NVMe и RAID не значит, что диск упёрся: они обслуживают запросы параллельно. Это прямо написано в man iostat.Гистограмма вместо среднего
# 2. В Ubuntu утилита идёт в пакете bpftrace.
# Ctrl+C — и получаешь распределение задержек.
sudo biolatency.bt
@usecs:
[16, 32) 426043
[32, 64) 15436
[64, 128) 527
...
[1K, 2K) 24
[2K, 4K) 17
[4K, 8K) 13
Проверил на тестовой нагрузке (столбики убрал, чтобы влезло в экран): iostat в тот же момент показывал
w_await 0.02 мс, а в хвосте висели запросы по 4–8 мс — в сотни раз дольше среднего.Чей I/O висит
# 3. Каждый запрос дольше 10 мс — с процессом.
# Порог подстрой: для HDD 10 мс — норма.
# На tracepoint'ах: не сломается с новым ядром.
sudo bpftrace -e '
t:block:block_bio_queue {
@ts[args->sector] = nsecs;
@who[args->sector] = comm;
}
t:block:block_rq_complete /@ts[args->sector]/ {
$ms = (nsecs - @ts[args->sector]) / 1000000;
if ($ms >= 10) {
printf("%s %d ms\n", @who[args->sector], $ms);
}
delete(@ts[args->sector]);
delete(@who[args->sector]);
}
END { clear(@ts); clear(@who); }'
Видишь
kworker или jbd2 вместо своего процесса — это отложенная запись из page cache. Настоящего писателя покажет pidstat -d 1.Среднее говорит «всё хорошо», гистограмма показывает хвост, а третья команда — чей он. Дальше — по месту: вынести бэкап, развести нагрузку или идти к провайдеру с цифрами.
❗️ Нравится формат? Ставь 👍
👉 Рубрика: #шпаргалка@LinuxSkill
#Linux #eBPF #Storage #Troubleshooting #SysAdmin #DevOps
👍8
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3