Уведомление о нехватке места на диске
Заполнившийся диск — одна из самых частых причин падения сервисов: PostgreSQL перестаёт принимать запросы, nginx — писать логи, контейнеры не могут стартовать. Лучше узнать о проблеме за несколько дней, чем читать post-mortem.
Что мы будем делать
Заголовок раздела «Что мы будем делать»Скрипт каждые 15 минут смотрит занятость всех смонтированных дисков и:
- если занято ≥ 80 % — присылает обычное предупреждение;
- если занято ≥ 95 % — присылает сообщение с высоким приоритетом.
Чтобы не получать одно и то же сообщение каждые 15 минут, мы будем хранить
состояние «уже отправили» в /var/lib/notifly-disk/.
Сохраните как /usr/local/bin/notifly-disk-check:
#!/usr/bin/env bashset -euset -a; source /etc/notifly.env; set +a
WARN=80CRIT=95STATE_DIR=/var/lib/notifly-diskmkdir -p "$STATE_DIR"
HOST=$(hostname -s)
# Берём только реальные ФС, без tmpfs/devtmpfsdf -PH -x tmpfs -x devtmpfs -x overlay | tail -n +2 | while read -r line; do USE=$(echo "$line" | awk '{print $5}' | tr -d '%') MNT=$(echo "$line" | awk '{print $6}') SIZE=$(echo "$line" | awk '{print $2}') AVAIL=$(echo "$line" | awk '{print $4}')
KEY=$(echo "$MNT" | tr '/' '_') STATE_FILE="$STATE_DIR/$KEY" LAST=$(cat "$STATE_FILE" 2>/dev/null || echo 0)
LEVEL=ok [ "$USE" -ge "$WARN" ] && LEVEL=warn [ "$USE" -ge "$CRIT" ] && LEVEL=crit
if [ "$LEVEL" != "$LAST" ]; then case "$LEVEL" in warn) /usr/local/bin/notifly-send \ "💾 Диск заполнен на $USE% — $HOST" \ "Раздел $MNT: занято $USE%, свободно $AVAIL из $SIZE." 5 ;; crit) /usr/local/bin/notifly-send \ "🔥 КРИТИЧНО: диск $USE% — $HOST" \ "Раздел $MNT: занято $USE%, свободно $AVAIL из $SIZE. Срочно освободите место!" 9 ;; ok) /usr/local/bin/notifly-send \ "✅ Диск в норме — $HOST" \ "Раздел $MNT снова в пределах нормы ($USE%)." 3 ;; esac echo "$LEVEL" > "$STATE_FILE" fidoneСделайте исполняемым:
sudo chmod +x /usr/local/bin/notifly-disk-checkЗапуск по расписанию
Заголовок раздела «Запуск по расписанию»Через cron
Заголовок раздела «Через cron»sudo crontab -eДобавьте строку:
*/15 * * * * /usr/local/bin/notifly-disk-check >/dev/null 2>&1Через systemd timer (рекомендуется)
Заголовок раздела «Через systemd timer (рекомендуется)»/etc/systemd/system/notifly-disk.service:
[Unit]Description=Notifly disk space check
[Service]Type=oneshotExecStart=/usr/local/bin/notifly-disk-check/etc/systemd/system/notifly-disk.timer:
[Unit]Description=Run notifly-disk every 15 minutes
[Timer]OnBootSec=5minOnUnitActiveSec=15min
[Install]WantedBy=timers.targetАктивируем:
sudo systemctl daemon-reloadsudo systemctl enable --now notifly-disk.timersudo systemctl list-timers notifly-disk.timerWindows: PowerShell + Task Scheduler
Заголовок раздела «Windows: PowerShell + Task Scheduler»Эквивалент скрипта для Windows-серверов. Использует общую функцию Send-Notifly
из шаблона sysadmin/index.
. C:\scripts\Notifly.ps1
$Warn = 80$Crit = 95$StateDir = "C:\ProgramData\Notifly\disk-state"New-Item -ItemType Directory -Path $StateDir -Force | Out-Null$Host = $env:COMPUTERNAME
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object { if (-not $_.Size) { return } $usedPct = [int]((($_.Size - $_.FreeSpace) / $_.Size) * 100) $freeGB = [math]::Round($_.FreeSpace / 1GB, 1) $sizeGB = [math]::Round($_.Size / 1GB, 1) $letter = $_.DeviceID.TrimEnd(":")
$stateFile = Join-Path $StateDir "$letter.txt" $last = if (Test-Path $stateFile) { Get-Content $stateFile -Raw } else { "ok" }
$level = "ok" if ($usedPct -ge $Warn) { $level = "warn" } if ($usedPct -ge $Crit) { $level = "crit" }
if ($level -ne $last.Trim()) { switch ($level) { "warn" { Send-Notifly -Title "💾 Диск $letter`: $usedPct% — $Host" ` -Message "Свободно $freeGB ГБ из $sizeGB ГБ." -Priority 5 } "crit" { Send-Notifly -Title "🔥 КРИТИЧНО: диск $letter`: $usedPct% — $Host" ` -Message "Свободно всего $freeGB ГБ. Срочно освободите место!" -Priority 9 } "ok" { Send-Notifly -Title "✅ Диск $letter в норме — $Host" ` -Message "Раздел $letter: занято $usedPct%." -Priority 3 } } $level | Set-Content $stateFile }}Регистрация в Task Scheduler (от администратора, каждые 15 минут от SYSTEM):
$Action = New-ScheduledTaskAction ` -Execute "powershell.exe" ` -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\scripts\Notifly-Disk-Check.ps1"$Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) ` -RepetitionInterval (New-TimeSpan -Minutes 15)$Princ = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel HighestRegister-ScheduledTask -TaskName "Notifly Disk Check" ` -Action $Action -Trigger $Trigger -Principal $Princ -Description "Notifly: проверка дисков"- Никаких упавших ночью БД из-за полного диска — вы узнаёте об этом за дни до катастрофы.
- Один и тот же канал для всех серверов — заголовок содержит hostname, в админке Notifly легко создать один канал на парк машин или по одному на каждую.
- Трехуровневая логика (
ok→warn→crit) исключает спам: пока ничего не меняется — уведомлений нет.
Что улучшить дальше
Заголовок раздела «Что улучшить дальше»- Добавить в сообщение ссылку на дашборд / wiki.
- Прикладывать вывод
du -sh /var/log/* | sort -h | tail -10, чтобы сразу видеть, что съело место — передавайте через полеextras. - Настроить разные каналы Notifly для prod / staging — у них будут разные звуки.