Add safe monthly maintenance installer

This commit is contained in:
andrey271192
2026-07-31 12:14:48 +03:00
commit 8890a4110c
8 changed files with 904 additions and 0 deletions

298
README.md Normal file
View File

@@ -0,0 +1,298 @@
# Safe Monthly Maintenance
Безопасное ежемесячное обслуживание Ubuntu/Debian одной командой.
Скрипт устанавливает systemd timer, обновляет пакеты без `dist-upgrade`, чистит
безопасные кэши и журналы, проверяет состояние `dpkg`, свободное место и
необходимость перезагрузки. Автоматическая перезагрузка, `autoremove` и очистка
Docker выключены по умолчанию.
> Проверено на Debian 12. Скрипт рассчитан на Ubuntu и Debian с systemd и APT.
> Перед массовым развертыванием проверьте его на одной тестовой VM.
## Установка одной командой
Закрепленная версия:
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/safe-monthly-maintenance/v1.0.2/install.sh | sudo bash -s -- --run-now
```
Команда:
1. скачивает `install.sh`;
2. устанавливает maintenance-скрипт и systemd units;
3. включает ежемесячный timer;
4. сразу выполняет первое обслуживание.
Установка без немедленного запуска:
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/safe-monthly-maintenance/v1.0.2/install.sh | sudo bash
```
Если `curl` отсутствует:
```bash
wget -qO- https://raw.githubusercontent.com/andrey271192/safe-monthly-maintenance/v1.0.2/install.sh | sudo bash -s -- --run-now
```
## Более безопасная установка с проверкой
Не запускайте неизвестный код от `root` вслепую. Скачайте, проверьте, затем
выполните:
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/safe-monthly-maintenance/v1.0.2/install.sh -o /tmp/install-safe-maintenance.sh
sha256sum /tmp/install-safe-maintenance.sh
less /tmp/install-safe-maintenance.sh
sudo bash /tmp/install-safe-maintenance.sh --run-now
```
SHA-256 версии `v1.0.2`:
```text
247312aaca5eb5b40c8893edb065203b2e4f0121c47421d85b46f9ae46770367
```
## Что устанавливается
| Путь | Назначение |
|---|---|
| `/usr/local/sbin/safe-monthly-maintenance` | Основной maintenance-скрипт |
| `/etc/default/safe-monthly-maintenance` | Настройки конкретной VM |
| `/etc/systemd/system/safe-monthly-maintenance.service` | Одноразовый systemd service |
| `/etc/systemd/system/safe-monthly-maintenance.timer` | Ежемесячный запуск |
| `/var/backups/safe-monthly-maintenance/` | Снимки списка пакетов |
Повторный запуск installer обновляет скрипт и units, но сохраняет существующий
файл настроек.
## Расписание
Timer запускается первого числа каждого месяца в 03:00 с случайной задержкой до
шести часов:
```ini
OnCalendar=*-*-01 03:00:00
RandomizedDelaySec=6h
Persistent=true
```
Случайная задержка уменьшает одновременную нагрузку на репозитории, если один
installer установлен на много VM. `Persistent=true` выполняет пропущенный запуск
после включения сервера.
## Что делает обслуживание
### 1. Проверяет окружение
- требует права `root`;
- разрешает только Ubuntu/Debian и Debian-подобные системы;
- использует `flock`, поэтому два запуска не идут одновременно;
- использует ожидание APT-lock до 600 секунд;
- повторяет сетевые обращения APT до трех раз.
### 2. Сохраняет список пакетов
Перед обновлением выполняется:
```bash
dpkg --get-selections
```
Снимок записывается в `/var/backups/safe-monthly-maintenance/`. Снимки старше
120 дней удаляются. Это не полный rollback системы, но помогает восстановить
состав пакетов.
### 3. Чистит только безопасные данные
- `systemd-tmpfiles --clean` — применяет штатные политики очистки временных
файлов;
- `logrotate` — запускает штатную ротацию логов;
- `journalctl --vacuum-time=30d` — удаляет старый journal;
- `journalctl --vacuum-size=500M` — ограничивает размер journal;
- `apt-get autoclean` — удаляет устаревшие package-файлы;
- `apt-get clean` — очищает скачанный APT-кэш после обновления.
Скрипт не выполняет ручной `rm -rf` для `/tmp`, `/var/log`, Docker volumes или
пользовательских каталогов.
### 4. Проверяет пакетную систему
`dpkg --audit` запускается до обновления. Если пакетная операция была прервана,
обновление пропускается. Скрипт не пытается автоматически ремонтировать
неоднозначное состояние.
После обновления выполняется:
```bash
apt-get check
```
### 5. Проверяет свободное место
Обновление пропускается, если:
- на `/` осталось меньше 1 ГиБ;
- на отдельном `/boot` осталось меньше 200 МиБ.
Порог можно изменить в конфигурации.
### 6. Обновляет пакеты
Используется:
```bash
apt-get -y \
-o Dpkg::Options::=--force-confold \
--with-new-pkgs \
--no-remove \
upgrade
```
Почему:
- `upgrade`, не `dist-upgrade`/`full-upgrade`: пакеты не удаляются;
- `--with-new-pkgs`: разрешает новые зависимости, включая новое ядро;
- `--no-remove`: аварийно останавливает операцию, если APT захочет удалить
пакет;
- `--force-confold`: сохраняет локальные конфиги вместо тихой замены;
- `NEEDRESTART_MODE=l`: показывает сервисы со старыми библиотеками, но не
перезапускает все сервисы автоматически.
Пакетные maintainer scripts все равно могут перезапустить собственный сервис.
Абсолютно гарантировать отсутствие краткого service interruption при системном
обновлении невозможно.
### 7. Не удаляет зависимости автоматически
По умолчанию выполняется только dry-run:
```bash
apt-get --dry-run autoremove
```
Кандидаты попадают в журнал. Реальный `autoremove` включается только вручную
через конфигурацию.
### 8. Не перезагружает сервер
Скрипт проверяет `/var/run/reboot-required` и сравнивает текущее ядро с
`/vmlinuz`. При необходимости пишет:
```text
REBOOT REQUIRED. Automatic reboot disabled.
```
Решение о reboot остается у администратора.
### 9. Показывает итог
В конце журнал содержит:
- failed systemd units;
- использование диска;
- необходимость reboot;
- успешные и неуспешные этапы.
## Настройка
Файл:
```bash
sudo nano /etc/default/safe-monthly-maintenance
```
Параметры:
| Параметр | По умолчанию | Значение |
|---|---:|---|
| `ENABLE_AUTOREMOVE` | `0` | `1` разрешает `apt-get autoremove --purge` |
| `ENABLE_DOCKER_PRUNE` | `0` | `1` удаляет только dangling Docker images |
| `JOURNAL_MAX_AGE` | `30d` | Максимальный возраст systemd journal |
| `JOURNAL_MAX_SIZE` | `500M` | Максимальный размер journal |
| `MIN_ROOT_FREE_KB` | `1048576` | Минимум свободного места на `/` |
| `MIN_BOOT_FREE_KB` | `204800` | Минимум на отдельном `/boot` |
Для серверов с важными stopped-контейнерами и локальными Docker-образами
оставляйте `ENABLE_DOCKER_PRUNE=0`.
## Управление
Следующий запуск:
```bash
systemctl list-timers safe-monthly-maintenance.timer --all
```
Запустить вручную:
```bash
sudo systemctl start safe-monthly-maintenance.service
```
Последний статус:
```bash
systemctl status safe-monthly-maintenance.service
```
Логи:
```bash
journalctl -u safe-monthly-maintenance.service
```
Логи текущего запуска:
```bash
journalctl -u safe-monthly-maintenance.service --since today
```
Отключить автоматический запуск:
```bash
sudo systemctl disable --now safe-monthly-maintenance.timer
```
Удалить:
```bash
sudo systemctl disable --now safe-monthly-maintenance.timer
sudo rm -f /etc/systemd/system/safe-monthly-maintenance.timer
sudo rm -f /etc/systemd/system/safe-monthly-maintenance.service
sudo rm -f /usr/local/sbin/safe-monthly-maintenance
sudo systemctl daemon-reload
```
Конфигурация и package snapshots при удалении сохраняются намеренно.
## Массовое развертывание
Пример с локальным списком серверов:
```bash
for host in vm1.example.com vm2.example.com vm3.example.com; do
ssh "$host" \
'curl -fsSL https://raw.githubusercontent.com/andrey271192/safe-monthly-maintenance/v1.0.2/install.sh | sudo bash -s -- --run-now'
done
```
Сначала используйте одну тестовую VM. Для большой инфраструктуры лучше Ansible,
Salt или другой configuration-management инструмент.
## Ограничения
- Скрипт не делает filesystem/provider snapshot.
- Скрипт не исправляет сломанный `dpkg` автоматически.
- Скрипт не обновляет Ubuntu/Debian между major releases.
- Скрипт не управляет сторонними package managers.
- Скрипт не гарантирует отсутствие service restart от maintainer scripts.
- Скрипт не заменяет мониторинг, резервные копии и тестирование обновлений.
Подробная модель безопасности: [docs/SAFETY.md](docs/SAFETY.md).
## Лицензия
[MIT](LICENSE)