Афоризмы Мёрфи #8: Шестое следствие

Продолжаем разбирать классику Артура Блоха. После пятого следствия (“природа всегда на стороне скрытого дефекта”) — шестое: «Если всё, кажется, идёт хорошо — значит, вы просто кое-что упустили» Ночь без алертов после деплоя — не повод расслабляться, а повод перепроверить, что алерты вообще доехали до канала. Тишина в мониторинге не означает стабильность системы, она означает только то, что никто пока не заметил, что сломалось. #юмор #murphy #sysadmin

1 августа 2026 г. · llexa

diff: не только -u — сравнение файлов и директорий

Голый diff old new выводит формат, неудобный для чтения и не применимый обратно. На практике почти всегда нужны конкретные флаги. diff -u old.conf new.conf > fix.patch # unified — как git diff patch < fix.patch # применить патч diff -rq /etc/nginx/sites-available /backup/sites-available # только имена разных файлов diff -w old.conf new.conf # игнор пробелов -u — unified diff, тот же формат, что и git diff, единственный, который patch применяет без путаницы со смещением строк. -r рекурсивно по директориям, -q — не печатать содержимое, только “differ”/“only in”. -w спасает, когда разница только в отступах после автоформатера. ...

31 июля 2026 г. · llexa

FUSE с нуля #1: файловая система без правки ядра

FUSE позволяет писать файловую систему обычной программой в userspace — ядро только проксирует VFS-вызовы демону через /dev/fuse, без строчки кода в ядре. Практичный пример — sshfs, который уже реализует это за тебя. sshfs user@host:/remote/path /local/mnt -o reconnect,ServerAliveInterval=15 ls /local/mnt # трафик идёт через ssh fusermount -u /local/mnt # отмонтировать — не umount sshfs user@host:/path /local/mnt -o allow_other # доступ другим локальным юзерам По умолчанию FUSE-ФС видна только тому, кто её примонтировал — allow_other (плюс user_allow_other в /etc/fuse.conf) открывает доступ остальным. Отключать — fusermount -u, не umount: демон живёт в userspace, обычный umount про него не знает. ...

31 июля 2026 г. · llexa

nftables с нуля #1: таблицы, цепочки и первое правило

nftables заменяет разом iptables, ip6tables и arptables — один синтаксис на все семейства адресов, и весь рулсет заменяется атомарно, без окна с частично применёнными правилами. nft add table inet filter nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; } nft add rule inet filter input iif lo accept nft add rule inet filter input ct state established,related accept nft add rule inet filter input tcp dport 22 accept nft list ruleset hook input — стадия перехвата пакетов (input/output/forward), priority — порядок среди chains на том же hook. Правила читаются сверху вниз, как в pg_hba.conf. Рулсет живёт только в памяти ядра — дамп в файл через nft list ruleset > /etc/nftables.conf. ...

31 июля 2026 г. · llexa

auditd: кто прочитал файл и кто запустил команду

Обычные логи покажут, что сервис что-то сделал с файлом — но не покажут, какой процесс и пользователь его открыл. В ядре есть audit-подсистема, auditd — её демон-приёмник. auditctl -w /etc/passwd -p wa -k passwd_watch # следить за записью/атрибутами файла auditctl -a always,exit -F arch=b64 -S execve -k exec_track # логировать все exec ausearch -k passwd_watch # события по ключу aureport --file --summary # сводка по файловым событиям -p wa — какие операции отслеживать (write, attribute change; есть ещё r/x). Ключ (-k) — метка для поиска через ausearch, без неё фильтруй по PID вручную. Правила из auditctl живут до перезагрузки — постоянные пишутся в /etc/audit/rules.d/*.rules. ...

30 июля 2026 г. · llexa

HAProxy: frontend, backend и health check по отдельности

HAProxy проще воспринимать не как веб-сервер, а как балансировщик L4/L7 — логика делится на frontend (кто принимает трафик) и backend (куда отдать). frontend http_in bind *:80 acl is_api path_beg /api use_backend api_servers if is_api default_backend web_servers backend web_servers balance roundrobin server web1 10.0.0.1:8080 check server web2 10.0.0.2:8080 check backend api_servers balance leastconn server api1 10.0.0.3:9000 check inter 2000 rise 2 fall 3 check — обязательный флаг, без него HAProxy не уберёт мёртвый сервер из ротации. inter 2000 rise 2 fall 3 — проверка раз в 2 секунды, 2 успеха возвращают сервер в строй, 3 провала выводят. ACL по path_beg роутит /api в отдельный backend без отдельного frontend. ...

30 июля 2026 г. · llexa

systemd-nspawn: контейнер без Docker за одну команду

Когда нужен один изолированный Linux, а поднимать Docker ради этого избыточно — есть systemd-nspawn, встроенный в systemd, без демона и без отдельного рантайма. debootstrap bookworm /var/lib/machines/mybox # подготовить rootfs systemd-nspawn -D /var/lib/machines/mybox --network-veth -b # запустить как систему (boot) machinectl list # список запущенных контейнеров machinectl shell mybox # зайти внутрь machinectl poweroff mybox -b запускает полноценный init внутри, а не одну команду — контейнер ведёт себя как отдельная машина. --network-veth поднимает veth-пару с NAT на хосте, без него контейнер живёт в сетевом namespace хоста. Для постоянных контейнеров — machinectl enable mybox, автозапуск через systemd. ...

30 июля 2026 г. · llexa

pg_dump, pg_restore, pg_basebackup: три инструмента, а не один

Три утилиты, три разных уровня бэкапа — путаница возникает, когда пытаются взаимозаменить логический и физический бэкап там, где это не работает. pg_dump -Fc mydb > mydb.dump # логический дамп одной БД pg_restore -d mydb_new --clean --if-exists mydb.dump pg_basebackup -D /backup/base -Ft -z -P -U replicator # физическая копия кластера pg_dump — логический: SQL-представление данных, можно восстановить одну таблицу из дампа целой БД, версии источника и назначения могут отличаться. pg_basebackup — физический: побайтовая копия PGDATA, восстанавливается только целиком, зато на её основе строится репликация и point-in-time recovery через WAL. Для одной таблицы — pg_dump -t, для кластера с минимальным RPO — pg_basebackup плюс архив WAL. ...

29 июля 2026 г. · llexa

pg_hba.conf: кто и как подключается к PostgreSQL

pg_hba.conf решает не “кто может логиниться”, а “каким методом проверять” — и правила читаются сверху вниз, первое совпадение по типу/базе/пользователю/адресу побеждает. # TYPE DATABASE USER ADDRESS METHOD local all postgres peer host all all 127.0.0.1/32 scram-sha-256 host mydb app 10.0.0.0/24 scram-sha-256 peer — только для local (сверяет пользователя ОС с ролью PostgreSQL, пароль не нужен). trust — без пароля вообще, годится только на loopback в закрытом окружении. md5 устарел, scram-sha-256 — текущий стандарт. После правки — pg_ctl reload или SELECT pg_reload_conf();, restart не нужен и обрывает соединения. ...

29 июля 2026 г. · llexa

pg_locks: кто кого блокирует в PostgreSQL

Запрос висит, в логах тихо — почти всегда блокировка. pg_stat_activity покажет статус active, но не покажет, кто держит блокировку. Для этого — pg_locks. -- цепочка блокировок без ручных JOIN SELECT pid, pg_blocking_pids(pid) AS blocked_by, query FROM pg_stat_activity WHERE cardinality(pg_blocking_pids(pid)) > 0; SELECT pid, locktype, relation::regclass, mode, granted FROM pg_locks WHERE NOT granted; granted = false — это и есть ожидающий процесс. Row-level локи (RowExclusiveLock от UPDATE) конфликтуют не со всеми — а AccessExclusiveLock (от ALTER TABLE, VACUUM FULL) блокирует вообще всё, включая SELECT. DDL в очереди на busy-таблице сам блокирует все следующие запросы, даже read-only. ...

29 июля 2026 г. · llexa