Пакеты, логи, cron и диски
Держите сервер обновлённым, знайте, где лежат логи, планируйте задачи и никогда не упирайтесь в диск.
За 30 секунд
Большая часть обслуживания сервера сводится к четырём вещам: установке и обновлению ПО через пакетный менеджер, чтению и ротации логов, планированию регулярных задач и наблюдению за диском и памятью. Один только заполненный диск может разом положить базу данных, веб-сервер и деплой. Этот урок даёт команды и привычки, которые помогают держать сервер в здоровом состоянии.
Почему я это использую
- unattended-upgrades входит в мой базовый набор для каждого сервера, потому что непропатченные пакеты — один из самых простых способов проникнуть внутрь.
- Я очистил один продакшен-сервер с 91% до 66% заполненности диска, отыскав старые логи, старые сборки и раздутые node_modules.
- Мониторинг диска, нагрузки и аптайма — в моём стандартном списке, потому что заполненный диск — тихий сбой, пока в один момент не ломается всё сразу.
Как это работает
01apt: установка и обновление ПО
В Debian и Ubuntu apt устанавливает ПО из доверенных репозиториев, разрешает зависимости и проверяет подписи пакетов. apt update обновляет список доступных версий, но ничего не устанавливает. apt upgrade ставит новые версии того, что у вас уже есть, а apt full-upgrade может также добавлять или удалять пакеты при изменении зависимостей, что нужно для обновлений ядра. В системах семейства RHEL то же самое делает dnf (dnf check-update, dnf upgrade). Предпочитайте пакеты из репозиториев дистрибутива; сторонние репозитории добавляйте только от вендоров, которым доверяете, с их ключами signed-by. После обновления ядра или базовых библиотек проверьте, не требуется ли перезагрузка.
sudo apt update # refresh package lists
apt list --upgradable # what would change
sudo apt upgrade # install updates
sudo apt full-upgrade # also handle changed dependencies
sudo apt install nginx htop # install packages
sudo apt remove --purge apache2 # remove, including config
sudo apt autoremove # remove unused dependencies
apt show nginx; apt policy nginx # details and versions
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required
02Автоматические обновления безопасности
unattended-upgrades автоматически ставит обновления безопасности каждый день, так что известные дыры закрываются, даже если никто не заходит на сервер. В Ubuntu Server он установлен по умолчанию; проверить и включить его можно через dpkg-reconfigure. По умолчанию он применяет только обновления из security-репозитория, что является разумным балансом между безопасностью и стабильностью. Можно настроить автоматическую перезагрузку в тихий час, когда её требует обновление ядра, и очистку старых ядер. В RHEL аналог — dnf-automatic. Его лог в /var/log/unattended-upgrades/ показывает, что и когда было установлено. Автоматические обновления не заменяют плановые апгрейды между мажорными версиями, которые стоит сначала протестировать.
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades # enable
cat /etc/apt/apt.conf.d/20auto-upgrades
# In /etc/apt/apt.conf.d/50unattended-upgrades you can set:
# Unattended-Upgrade::Automatic-Reboot "true";
# Unattended-Upgrade::Automatic-Reboot-Time "04:00";
# Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
sudo unattended-upgrade --dry-run --debug # test it
03Логи: /var/log, journald и logrotate
На современном сервере две системы логов. Журнал systemd собирает вывод сервисов и ядра; читается он через journalctl. Классические текстовые файлы в /var/log пишут rsyslog и приложения вроде nginx. Полезные файлы в Ubuntu: /var/log/syslog для общих сообщений, /var/log/auth.log для входов и sudo и /var/log/nginx/ для веб-трафика и ошибок (в RHEL — /var/log/messages и /var/log/secure). Логи растут бесконечно, если их ничто не обрезает. Для текстовых файлов этим занимается logrotate: он переименовывает текущий файл, сжимает старые и хранит только заданное количество. Для журнала задайте ограничение размера в конфиге journald или чистите его через vacuum.
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
# Test without changing anything: sudo logrotate -d /etc/logrotate.d/myapp
# Journal size: journalctl --disk-usage
# sudo journalctl --vacuum-size=500M
# Permanent cap: SystemMaxUse=500M in /etc/systemd/journald.conf
04Планирование через cron
cron запускает команды по расписанию. У каждого пользователя есть crontab (редактируется через crontab -e), а системные задачи лежат в /etc/crontab и /etc/cron.d. Строка состоит из пяти полей времени — минута, час, день месяца, месяц и день недели, — за которыми следует команда. Звёздочка означает «каждый», */5 — «каждые пять», а диапазоны вроде 1-5 — с понедельника по пятницу. cron работает с минимальным окружением: PATH короткий, профиль shell не загружается, поэтому используйте абсолютные пути и перенаправляйте вывод в лог, иначе ошибки просто исчезнут. cron использует часовой пояс сервера, а на облачных серверах это часто UTC. Проверить выражение помогает сайт вроде crontab.guru.
# m h dom mon dow command
*/5 * * * * /usr/local/bin/healthcheck.sh >> /var/log/healthcheck.log 2>&1
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
30 2 * * 1 /usr/local/bin/weekly-report.sh
# Laravel scheduler: run every minute as the app user
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
# Prevent overlapping runs with flock
0 * * * * flock -n /tmp/sync.lock /usr/local/bin/sync.sh
05Диски: df, du, lsblk и mount
df показывает, насколько заполнена каждая смонтированная файловая система; du — сколько места занимают файлы и каталоги. lsblk выводит блочные устройства, так что видно диски и разделы, включая только что подключённый новый том. Чтобы использовать новый том, один раз создайте на нём файловую систему (ext4 — безопасный выбор по умолчанию), смонтируйте её и добавьте в /etc/fstab по UUID, чтобы она подключалась после перезагрузки. Проверьте fstab через mount -a до перезагрузки, потому что сломанная запись может не дать серверу загрузиться. Следите и за inode через df -i: диск может оказаться «заполненным» при наличии свободного места, если миллионы мелких файлов (сессии, кэш) исчерпали все inode.
df -h # space per filesystem
df -i # inodes per filesystem
lsblk -f # disks, partitions, filesystems, UUIDs
sudo mkfs.ext4 /dev/sdb # format a NEW empty volume (destroys data!)
sudo mkdir -p /mnt/data
sudo mount /dev/sdb /mnt/data
# /etc/fstab line (use the UUID from lsblk -f):
# UUID=your-uuid /mnt/data ext4 defaults,nofail 0 2
sudo mount -a # test fstab before rebooting
06Ищем, что забивает диск
Когда df показывает диск заполненным на 90% и больше, двигайтесь сверху вниз. du с ограничением глубины показывает самые большие каталоги; повторяйте внутри самого крупного. ncdu — интерактивная версия, которая делает это быстро. Обычные подозреваемые — старые логи и архивы после ротации, журнал systemd, образы Docker и кэш сборки, старые папки релизов от деплоев, каталоги node_modules и vendor, забытые в домашних каталогах дампы БД и кэш пакетов apt. Одна ловушка: если удалить лог-файл, который процесс всё ещё держит открытым, место не освободится, пока процесс не перезапустится или не откроет файл заново. lsof +L1 показывает такие удалённые, но открытые файлы. Обнулить живой лог безопаснее, чем удалить его.
sudo du -xh --max-depth=1 / | sort -h | tail
sudo du -xh --max-depth=1 /var | sort -h | tail
sudo ncdu -x / # interactive (apt install ncdu)
sudo find / -xdev -type f -size +500M -exec ls -lh {} + 2>/dev/null
journalctl --disk-usage
docker system df # images, containers, cache
sudo apt clean # apt package cache
sudo lsof +L1 # deleted files still held open
sudo truncate -s 0 /var/log/myapp/huge.log # empty a live log safely
07Память и swap
free -h показывает память. Не паникуйте из-за маленького значения «free»: Linux использует свободную память как дисковый кэш и отдаёт её, когда она нужна приложениям. Смотреть нужно на колонку available. Когда доступная память заканчивается, OOM killer ядра (out of memory) завершает процесс, часто самый крупный, и нередко это ваша база данных. Swap — это место на диске, используемое как переполнение памяти. Он гораздо медленнее RAM, но на небольшом VPS скромный swap-файл (от 1 до 2 GB) превращает внезапное падение в замедление, которое можно заметить и исправить. Если сервер постоянно свапится, нужно больше RAM или менее прожорливое приложение, а не больше swap.
free -h # read the "available" column
sudo journalctl -k | grep -i "out of memory" # OOM kills
# Create a 2 GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo "/swapfile none swap sw 0 0" | sudo tee -a /etc/fstab
swapon --show
Когда применять
- Любой сервер, который вы ведёте: обновления, ротация логов и мониторинг диска — базовая гигиена.
- Инциденты с заполненным диском, падающие деплои или базы данных, отказывающиеся записывать.
- Регулярные задачи: бэкапы, отчёты, очистка и планировщики фреймворков.
- Небольшие VPS, где swap-файл и лимиты журнала предотвращают падения, которых можно избежать.
Когда не стоит
- Не запускайте apt full-upgrade или обновление до нового мажорного релиза на продакшене без снапшота и окна обслуживания.
- Не используйте swap как замену достаточному объёму RAM на нагруженном сервере базы данных.
- Не удаляйте непонятные файлы только ради освобождения места; сначала выясните, что их пишет.
Альтернативы
- dnf / dnf-automatic
Аналоги apt и unattended-upgrades в RHEL, Rocky и Alma.
- Таймеры systemd
Более наблюдаемая альтернатива cron с логами в журнале и догоняющими запусками.
- Централизованное логирование (Loki, ELK, облачные сервисы)
Отправляйте логи с сервера, чтобы искать по всем машинам и сохранять их, даже если диск умрёт.
- Объектное хранилище
Перенесите пользовательские загрузки и бэкапы в S3-совместимое хранилище, чтобы диск сервера оставался маленьким, а сам сервер — заменяемым.
Лучшие практики
- Включите unattended-upgrades для обновлений безопасности и проверяйте, не требуется ли перезагрузка.
- Делайте снапшот перед крупными обновлениями и сначала обновляйте staging.
- Задайте правило logrotate для каждого лога приложения и ограничьте размер журнала.
- Настройте алерт по заполненности диска задолго до того, как он заполнится, например на 80%.
- В cron используйте абсолютные пути, перенаправляйте вывод в лог и предотвращайте наложение запусков через flock.
- Монтируйте дополнительные тома по UUID с опцией nofail и проверяйте fstab через mount -a.
- Регулярно чистите старые релизы, образы Docker и кэши сборки как часть процесса деплоя.
Частые ошибки
- Запуск apt upgrade без предварительного apt update, из-за чего ничего нового не ставится.
- Удаление живого лога через rm, после которого место не освобождается, потому что процесс всё ещё держит файл открытым.
- cron-задачи, которые работают в терминале, но молча падают из-за PATH или отсутствующего перенаправления вывода.
- Опечатка в /etc/fstab, из-за которой сервер не загружается.
- Смотрят на «free» вместо «available» и добавляют RAM, которая была не нужна.
Глубже
08Под капотом apt: dpkg, источники, pinning и phased updates
apt — планировщик, а устанавливает dpkg. dpkg распаковывает архивы .deb, запускает их maintainer-скрипты и записывает состояние в /var/lib/dpkg. Если обновление прервано, пакеты остаются наполовину настроенными, пока вы не выполните dpkg --configure -a. Начиная с Ubuntu 24.04 репозитории описываются в формате deb822, в файлах вроде /etc/apt/sources.list.d/ubuntu.sources, а сторонние репозитории должны указывать свой ключ через Signed-By, чтобы этот ключ не мог ручаться за другие репозитории. Pinning в /etc/apt/preferences.d задаёт приоритеты между репозиториями, а apt-mark hold замораживает версию пакета, когда с обновлением нужно подождать. Ubuntu также использует phased updates: обновления, не связанные с безопасностью, в течение нескольких дней раскатываются на растущий процент машин, поэтому apt может показывать часть обновлений как «deferred due to phasing». Это ожидаемое поведение, а не сломанное зеркало.
# /etc/apt/sources.list.d/vendor.sources (deb822 format)
Types: deb
URIs: https://packages.example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/vendor.gpg
# Useful commands:
# sudo dpkg --configure -a # finish interrupted installs
# sudo apt-mark hold nginx # freeze a version (unhold to undo)
# apt-cache policy nginx # which repo and priority wins
# dpkg -S /usr/sbin/nginx # which package owns a file
# zgrep ' install ' /var/log/dpkg.log* # install history
09Файловые системы: зарезервированные блоки, расширение томов и LVM
ext4 по умолчанию резервирует 5% блоков для root, чтобы сервисы, работающие от root, продолжали работать, когда пользователи заполнят диск. На томе данных в 500 GB это 25 GB; tune2fs -m 1 уменьшает резерв, но на корневой файловой системе оставьте значение по умолчанию. ext4 можно расширять онлайн, а уменьшать только офлайн; XFS, файловую систему по умолчанию в RHEL, можно расширять онлайн, но никогда нельзя уменьшить. Когда вы увеличиваете диск у провайдера, файловая система сама не растёт: если на диске есть разделы, сначала расширьте раздел через growpart, затем файловую систему через resize2fs (ext4) или xfs_growfs (XFS). Многие облачные образы делают это автоматически для корневого диска при загрузке через cloud-init, но для подключённых томов обычно нужно делать это вручную. LVM добавляет слой, позволяющий объединять диски, расширять логические тома и делать снапшоты, ценой большего числа движущихся частей.
lsblk # disk vs partition sizes
sudo growpart /dev/vda 1 # grow partition 1 to fill the disk
sudo resize2fs /dev/vda1 # grow ext4 online
sudo xfs_growfs / # grow XFS (by mount point)
sudo resize2fs /dev/sdb # unpartitioned volume: grow directly
sudo tune2fs -l /dev/sdb | grep -i 'reserved block count'
sudo tune2fs -m 1 /dev/sdb # 1% reserved on a data volume
sudo lvextend -r -l +100%FREE /dev/vg0/data # LVM: grow LV and filesystem
10Диагностика нагрузки на I/O и память
Когда сервер тормозит, а CPU простаивает, измерьте диск. vmstat 1 каждую секунду показывает процессы, заблокированные на I/O (b), swap-in и swap-out (si, so) и время CPU в ожидании I/O (wa). iostat -x 1 (пакет sysstat) показывает задержки по устройствам в r_await и w_await и загрузку; на SSD и сетевых томах задержка и лимит IOPS провайдера важнее, чем %util. iotop или pidstat -d 1 показывают, какой процесс выполняет I/O. Запись сначала попадает в page cache и сбрасывается позже, поэтому большая запись может выглядеть быстрой, а затем всё застопорить во время writeback. Pressure Stall Information в /proc/pressure/io и /proc/pressure/memory показывает долю времени, когда задачи простаивали, и это гораздо лучший сигнал, чем свободная память. vm.swappiness определяет, насколько охотно ядро использует swap; значение по умолчанию 60 подходит большинству серверов.
vmstat 1 5 # b, si/so, wa columns
iostat -x 1 3 # r_await, w_await, %util per device
sudo iotop -oPa # processes doing I/O (accumulated)
pidstat -d 1 5 # per-process disk reads/writes
cat /proc/pressure/io # some/full stall percentages
grep -E 'Dirty|Writeback' /proc/meminfo
sysctl vm.swappiness
11Проектирование конвейера логов
На одном сервере достаточно journald вместе с logrotate, если ограничить размеры. journald хранит логи в /var/log/journal, если этот каталог существует или задано Storage=persistent; иначе только в памяти в /run, и они исчезают при перезагрузке. Он также ограничивает частоту сообщений от шумных сервисов (RateLimitIntervalSec и RateLimitBurst), так что зациклившаяся ошибка может скрыть собственные повторы; журнал фиксирует, сколько сообщений было подавлено. Когда серверов больше одного, логи должны покидать машину: агент вроде Grafana Alloy (преемник Promtail), Vector или Fluent Bit читает журнал и файлы и отправляет их в Loki, Elasticsearch или облачный сервис. Предпочитайте структурированные JSON-логи с единообразными полями, такими как level, request ID и user ID, чтобы фильтровать, а не грепать. Срок хранения задавайте по типам: отладочные логи — дни, access-логи — недели, audit-логи — столько, сколько требует политика.
# /etc/systemd/journald.conf.d/size.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
SystemKeepFree=2G
MaxRetentionSec=30day
RateLimitIntervalSec=30s
RateLimitBurst=10000
# Apply: sudo systemctl restart systemd-journald
# Check: journalctl --disk-usage; journalctl --verify
Реальные ситуации
apt заблокирован или не завершил работу
Проблема
apt install падает с «Could not get lock /var/lib/dpkg/lock-frontend», а после обрыва SSH-сессии во время обновления apt жалуется, что dpkg был прерван.
Как решить
Сначала проверьте, действительно ли работает другой apt: ps aux | grep -E 'apt|dpkg|unattended' и systemctl status unattended-upgrades apt-daily-upgrade.service. На свежих серверах unattended-upgrades часто запускается сразу после загрузки, поэтому дождитесь его, а не удаляйте lock-файлы — это может повредить базу dpkg. Если ничего не запущено, а предыдущее обновление было прервано, выполните sudo dpkg --configure -a, затем sudo apt -f install, чтобы исправить сломанные зависимости, и снова apt update и upgrade. Прочитайте /var/log/apt/term.log, чтобы найти упавший maintainer-скрипт. В будущем запускайте долгие обновления внутри tmux, чтобы обрыв соединения их не убивал.
Диск у провайдера увеличен, а df показывает старый размер
Проблема
Вы увеличили подключённый том со 100 GB до 200 GB в панели провайдера. lsblk показывает 200 GB, но df -h всё ещё сообщает 100 GB, и диск по-прежнему почти заполнен.
Как решить
Блочное устройство выросло, а раздел и файловая система — нет. Запустите lsblk -f, чтобы увидеть разметку и тип файловой системы. Если файловая система лежит прямо на устройстве (без раздела, что типично для томов), расширьте её онлайн: sudo resize2fs /dev/sdb для ext4 или sudo xfs_growfs /mnt/data для XFS. Если есть раздел, сначала sudo growpart /dev/sdb 1, затем расширьте файловую систему раздела. С LVM используйте pvresize, а затем lvextend -r. Перед началом сделайте снапшот. Затем устраните и первопричину роста, потому что больший диск лишь выигрывает время, если логи или загрузки растут без ограничений.
«No space left on device» при гигабайтах свободного места
Проблема
Загрузки и PHP-сессии падают с «No space left on device», хотя df -h показывает, что диск заполнен на 60%. Перезапуск сервисов не помогает.
Как решить
Проверьте inode через df -i: если IUse% равен 100%, в файловой системе закончились записи для файлов — обычно из-за миллионов крошечных файлов. Найдите каталог с наибольшим числом файлов: sudo find / -xdev -type f | cut -d/ -f2-4 | sort | uniq -c | sort -rn | head. Типичные виновники — файлы PHP-сессий без сборки мусора, каталоги кэша или почтовые очереди. Удалите старые через find -mtime +2 -delete в нужном каталоге. Затем устраните причину: включите сборку мусора для сессий или перенесите сессии в Redis, добавьте таймер очистки и настройте алерты на использование inode наряду с местом. Для новых файловых систем, которые будут хранить огромное число мелких файлов, выбирайте соотношение inode при mkfs.
Шпаргалка
- Завершить прерванную установку пакетов
sudo dpkg --configure -a && sudo apt -f install- Какому пакету принадлежит файл
dpkg -S /usr/bin/curl- Заморозить / разморозить версию пакета
sudo apt-mark hold nginx / sudo apt-mark unhold nginx- Расширить раздел и файловую систему ext4
sudo growpart /dev/vda 1 && sudo resize2fs /dev/vda1- Каталоги с наибольшим числом файлов (inode)
sudo du --inodes -x -d 2 / | sort -n | tail- Задержка диска по устройствам
iostat -x 1 3- Процессы, выполняющие I/O
sudo iotop -oPa- Логи предыдущей загрузки
journalctl -b -1 -p warning- Сжать журнал прямо сейчас
sudo journalctl --vacuum-time=14d- Принудительно запустить logrotate для проверки правила
sudo logrotate -vf /etc/logrotate.d/myapp
В моих реальных проектах
- На одном сервере я снизил заполненность диска с 91% до 66%, очистив старые логи, старые сборки и раздутые node_modules, а затем проверил его бэкапы.
- unattended-upgrades и мониторинг диска, нагрузки и аптайма входят в базовый набор, который я применяю к каждому серверу.
- На своих серверах я использую cron для запуска планировщика Laravel.
- На сервере POS SaaS логи централизованно собираются в Loki и визуализируются в Grafana рядом с метриками Prometheus.
Вопросы и ответы
Q1Чем apt update отличается от apt upgrade?
apt update только скачивает свежие списки пакетов из настроенных репозиториев, чтобы apt знал, какие версии существуют. Никакое ПО он не меняет. Затем apt upgrade устанавливает новые версии уже установленных пакетов, ничего не удаляя. apt full-upgrade идёт дальше и может установить новые зависимости или удалить пакеты, чтобы завершить обновление, — это нужно для ядра и некоторых библиотек. Поэтому нормальная последовательность — update, затем upgrade. На продакшене я сначала просматриваю apt list --upgradable, делаю снапшот перед крупными изменениями, а рутинные исправления безопасности ежедневно ставит unattended-upgrades. Переход между релизами Ubuntu — это отдельный запланированный do-release-upgrade.
Q2На продакшен-сервере закончился диск. Что вы делаете?
Сначала стабилизирую: df -h, чтобы увидеть, какая файловая система заполнена, и df -i, чтобы исключить исчерпание inode. Затем ищу причину через du -xh --max-depth=1 с сортировкой по размеру, углубляясь в самые большие каталоги, или через ncdu. Частые виновники — логи без ротации, журнал, образы Docker и кэш сборки, старые каталоги релизов и забытые дампы БД. Освобождаю место безопасно: обнуляю живые логи вместо удаления, чищу журнал через vacuum, делаю prune в Docker, удаляю старые релизы. Если место не возвращается, lsof +L1 покажет удалённые файлы, которые процесс всё ещё держит открытыми. После этого устраняю первопричину: правила logrotate, лимиты журнала и алерт по диску.
Q3Почему cron-задача работает в терминале, но не из cron?
cron запускает команды с минимальным окружением. В PATH всего несколько системных каталогов, ваш .bashrc или .profile не загружается, рабочий каталог — домашний каталог пользователя, и используется /bin/sh, а не bash, если не указано иное. Поэтому команды вроде node или php, установленные в другие места, не находятся, относительные пути ломаются, а переменных окружения нет. Исправляется это абсолютными путями к бинарникам и файлам, cd в нужный каталог, заданием нужных переменных в crontab или в скрипте-обёртке и обязательным перенаправлением вывода в лог через >> file 2>&1, чтобы видеть ошибки. Проверьте также часовой пояс.
Q4Как не дать логам забить диск?
Для текстовых лог-файлов я добавляю правило logrotate на каждое приложение: ротация ежедневно или еженедельно, фиксированное число хранимых файлов, сжатие старых и copytruncate или сигнал в postrotate, чтобы приложение продолжало писать в новый файл. Для журнала systemd задаю SystemMaxUse в journald.conf, чтобы он не выходил за лимит размера. Приложениям стоит избегать debug-уровня логирования в продакшене. Всё, что важно в долгосрочной перспективе, нужно отправлять в централизованную систему, например Loki или облачный сервис, чтобы на сервере хранилось только короткое локальное окно. А алерт по заполненности диска ловит всё, что пропустили правила.
Q5free показывает почти ноль свободной памяти. У сервера проблемы?
Обычно нет. Linux использует простаивающую RAM как страничный кэш для файлов, что ускоряет чтение с диска, и сразу освобождает её, когда память нужна приложениям. Этот кэш отображается как занятый, поэтому на здоровой машине колонка free выглядит маленькой. Смотреть нужно на available — оценку того, сколько памяти можно отдать новой работе без свопинга. Настоящие проблемы выглядят так: мало доступной памяти, постоянная активность swap, растущая нагрузка с высоким I/O wait или сообщения OOM killer в journalctl -k. Тогда я ищу разросшийся процесс, например утечку или ненастроенную базу данных, прежде чем просто докупать RAM.
Q6Нужен ли серверу swap?
На большинстве небольших и средних VPS — да, в скромном объёме, обычно около 1–2 GB. Он работает как страховочный буфер: кратковременный всплеск потребления памяти делает сервер медленнее вместо срабатывания OOM killer, который может убить базу данных. Он также позволяет ядру выгружать из RAM редко используемые страницы. Но swap — это не дополнительная память: диск гораздо медленнее RAM. Если сервер постоянно свапится, ему не хватает ресурсов или приложение течёт, и решение — больше RAM или тюнинг. Некоторые конфигурации, например узлы Kubernetes или критичные к задержкам базы данных, сознательно работают без swap или с очень низким swappiness.
Вопросы уровня senior
S1Как вы балансируете автоматические обновления и стабильность на продакшен-серверах?
Я разделяю уровни риска. Обновления безопасности из security-репозитория дистрибутива применяются автоматически каждый день через unattended-upgrades, потому что оставленная открытой известная уязвимость — больший риск, чем хорошо протестированный патч безопасности. Функциональные и минорные обновления, сторонние репозитории, например баз данных или рантаймов, и всё, что требует рестарта критичного сервиса, проходят через запланированное окно: сначала staging, снапшот, затем продакшен. Пакеты, которые должны обновляться синхронно с приложением, например мажорная версия базы данных, закрепляются через pin или hold. Для обновлений ядра я либо разрешаю автоматическую перезагрузку в тихий час, если приложение переносит короткий рестарт, либо отслеживаю /var/run/reboot-required и перезагружаю осознанно. В масштабе парка я разношу обновления по серверам во времени, чтобы неудачное обновление никогда не задело всё сразу.
S2Сервер базы данных тормозит, и iowait высокий. Как выяснить, является ли узким местом хранилище?
Прежде чем что-то тюнить, я подтверждаю это цифрами. vmstat показывает заблокированные процессы и wa; iostat -x — задержки чтения и записи и размер очереди по устройствам. На сетевых облачных томах сравните наблюдаемые IOPS и пропускную способность с задокументированными лимитами тарифа, потому что упор в лимит провайдера выглядит в точности как медленный диск. pidstat -d или iotop подтверждают, что I/O выполняет именно база данных, а /proc/pressure/io показывает, сколько времени задачи простаивают. Затем я ищу причину на стороне базы: отсутствующие индексы, вызывающие полные сканирования, слишком маленький buffer pool для рабочего набора, из-за чего чтения идут на диск, или задачу checkpoint либо бэкапа, насыщающую запись. Решения — от тюнинга запросов и памяти до локального NVMe или тарифа с более высоким IOPS.
S3Что бы вы хранили на диске сервера, а что вынесли бы с него?
Я считаю диск сервера заменяемым. На нём лежат операционная система, релиз приложения, короткоживущие кэши, небольшое окно локальных логов и файлы базы данных, если она self-hosted. Всё, потеря чего была бы болезненной, уходит в другое место: пользовательские загрузки — в S3-совместимое объектное хранилище, бэкапы базы данных — в объектное хранилище у другого провайдера или в другом регионе, а логи отправляются в центральную систему. Это делает диск небольшим и предсказуемым, так что он редко заполняется, а пересборка сервера превращается в провижининг плюс восстановление данных, а не в спасение «питомца». Цена — дополнительные задержки и egress для объектного хранилища, больше движущихся частей и необходимость безопасно управлять учётными данными этих сервисов.
Глоссарий
- dpkg
- Низкоуровневый пакетный инструмент Debian, который устанавливает файлы .deb и отслеживает их состояние. apt вызывает его.
- Источники deb822
- Структурированный формат «ключ-значение» для файлов репозиториев apt (.sources); по умолчанию в Ubuntu начиная с 24.04.
- Pinning
- Настройки apt preferences, задающие приоритеты репозиториям или версиям и определяющие, какая версия будет установлена.
- Phased updates
- Постепенная раскатка в Ubuntu обновлений, не связанных с безопасностью, на растущую долю машин, чтобы рано ловить регрессии.
- Зарезервированные блоки
- Место на ext4, по умолчанию 5%, которым может пользоваться только root; сохраняет работоспособность системы при заполнении диска.
- Исчерпание inode
- Ситуация, когда в файловой системе закончились записи для файлов, хотя свободное место ещё есть; обычно из-за миллионов крошечных файлов.
- LVM
- Logical Volume Manager: слой, объединяющий диски в тома, которые можно менять в размере, растягивать на несколько дисков и снимать снапшоты.
- Page cache
- RAM, которую ядро использует для кэширования данных файлов и буферизации записи; освобождается, когда памяти не хватает приложениям.
- I/O wait
- Время простоя CPU, пока процессы ждут диск. Высокие значения указывают на хранилище, а не на CPU как на узкое место.
- Доставка логов
- Отправка логов с серверов в центральное хранилище агентом, чтобы их можно было искать и они переживали потерю сервера.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.