[2026-10-21] eagle: personal/index.md personal/tech/docker-mac-disk-issues.md personal/tech/macos-voom-cleanup.md
This commit is contained in:
1 parent
ad67e528a6
commit
12674ef2ad
3 files changed
+262
No files matched your search
@@ -139,6 +139,7 @@ Hub: [[personal/projects/media-pipeline-tracker-parsers|Media Pipeline Roadmap]]
|
|||||||
- [[personal/projects/virfield|Virfield — macOS VM control plane]] — релиз, статус и каноническая документация.
|
- [[personal/projects/virfield|Virfield — macOS VM control plane]] — релиз, статус и каноническая документация.
|
||||||
|
|
||||||
- [[docker_colima_setup|Docker Colima Setup]]
|
- [[docker_colima_setup|Docker Colima Setup]]
|
||||||
|
- [[personal/tech/macos-voom-cleanup|macOS — автоматическая очистка: Voom, Eagle, Docker и бэкапы]]
|
||||||
- [[truenas-remote-access-reverse-proxy|TrueNAS Remote Access]]
|
- [[truenas-remote-access-reverse-proxy|TrueNAS Remote Access]]
|
||||||
- [[Swift cross-platform testing|Swift Cross-Platform Testing]]
|
- [[Swift cross-platform testing|Swift Cross-Platform Testing]]
|
||||||
- [[Dyld dynamic interposing|Dyld Dynamic Interposing]]
|
- [[Dyld dynamic interposing|Dyld Dynamic Interposing]]
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Docker на Mac — проблема с диском и сборкой образов
|
# Docker на Mac — проблема с диском и сборкой образов
|
||||||
|
|
||||||
|
> **2026-10-21: действующие автоматические правила** — [[personal/tech/macos-voom-cleanup|Voom, Eagle и автоматическая очистка Mac]]. Там описаны расписания, сроки, защита данных и ограничения Docker. Ниже сохранены исторические разборы и ручные сценарии очистки.
|
||||||
|
|
||||||
_Последнее обновление: 2026-09-29_
|
_Последнее обновление: 2026-09-29_
|
||||||
|
|
||||||
> **2026-09-29: выполнена большая чистка, освобождено 41 ГБ** (57 ГБ → 16 ГБ, 61% → 17%).
|
> **2026-09-29: выполнена большая чистка, освобождено 41 ГБ** (57 ГБ → 16 ГБ, 61% → 17%).
|
||||||
|
|||||||
@@ -0,0 +1,259 @@
|
|||||||
|
---
|
||||||
|
title: 'macOS — Voom, Eagle и автоматическая очистка'
|
||||||
|
type: how-to
|
||||||
|
status: active
|
||||||
|
created: '2026-10-21'
|
||||||
|
updated: '2026-10-21'
|
||||||
|
tags:
|
||||||
|
- macos
|
||||||
|
- maintenance
|
||||||
|
- voom
|
||||||
|
- docker
|
||||||
|
- eagle-dashboard
|
||||||
|
aliases:
|
||||||
|
- Автоматическая очистка Mac
|
||||||
|
- Voom и Eagle
|
||||||
|
related:
|
||||||
|
- '[[personal/tech/docker-mac-disk-issues]]'
|
||||||
|
- '[[personal/tech/eagle-dashboard-launchd]]'
|
||||||
|
- '[[personal/projects/virfield]]'
|
||||||
|
---
|
||||||
|
# macOS — Voom, Eagle и автоматическая очистка
|
||||||
|
|
||||||
|
Состояние проверено **21 октября 2026** по установленным скриптам, конфигурациям и включённым заданиям Eagle. Это описание действующих правил; разовые ручные удаления могли быть шире автоматической политики.
|
||||||
|
|
||||||
|
## Сетап и расписание
|
||||||
|
|
||||||
|
Управление — [Eagle Dashboard → Crons](http://127.0.0.1:8880/?tab=crons). Eagle управляет пользовательскими LaunchAgent macOS; отдельных дублирующих расписаний в Codex нет. Все четыре задания включены. `RunAtLoad=false`: загрузка задания сама по себе не запускает очистку.
|
||||||
|
|
||||||
|
| Задание в Eagle | Label | Расписание |
|
||||||
|
|---|---|---|
|
||||||
|
| Очистка артефактов и симуляторов — каждые 2 часа | `local.voom.cleanup` | Каждые 7200 секунд |
|
||||||
|
| Docker — кэш и старые образы | `com.voom.docker-policy` | Каждые 7200 секунд |
|
||||||
|
| Бэкапы Balda и Virfield — хранить сутки | `com.voom.backup-retention` | Каждые 7200 секунд |
|
||||||
|
| Штатная очистка кэшей — воскресенье, 12:00 | `local.voom.weekly-caches` | Воскресенье, 12:00 по локальному времени Mac |
|
||||||
|
|
||||||
|
Период проверки и возраст удаления — разные параметры: например, бэкапы проверяются раз в два часа, а удаляются после суток.
|
||||||
|
|
||||||
|
### Установленные файлы
|
||||||
|
|
||||||
|
Базовый каталог: `/Users/admin/.local/share/voom-cleanup/` (`~/.local/share/voom-cleanup`). Python: `/opt/homebrew/bin/python3`. Voom: `~/.local/bin/voom`.
|
||||||
|
|
||||||
|
| Файл | Назначение |
|
||||||
|
|---|---|
|
||||||
|
| `cleanup.py` | Основной проход: временные файлы, Xcode/SwiftPM, симуляторы, merged worktree |
|
||||||
|
| `tmp_cleanup.py` | Помощник для `/private/tmp`, вызывается основным проходом |
|
||||||
|
| `docker_cleanup.py`, `docker_images.py` | BuildKit, наблюдение за ссылками образов и их ограниченная очистка |
|
||||||
|
| `docker-policy.json` | Параметры Docker |
|
||||||
|
| `docker-image-observations.json` | История наблюдаемых ссылок контейнеров; нужна для отсчёта 30 дней |
|
||||||
|
| `backup_cleanup.py`, `backup-policy.json` | Суточное хранение явно перечисленных бэкапов |
|
||||||
|
| `weekly-caches.py` | Штатные команды uv, npm и Homebrew |
|
||||||
|
|
||||||
|
Скрипты используют блокировки, чтобы повторный запуск того же задания не шёл параллельно предыдущему.
|
||||||
|
|
||||||
|
### Что сейчас действительно включено
|
||||||
|
|
||||||
|
На момент проверки существуют все три файла разрешения:
|
||||||
|
|
||||||
|
- `enable-deletion` — основной проход с `--apply`.
|
||||||
|
- `enable-docker-deletion` — Docker с `--apply`.
|
||||||
|
- `enable-tmp-deletion` — отдельное разрешение удаления из `/private/tmp`.
|
||||||
|
|
||||||
|
**Очистка `/private/tmp` включена.** Основной скрипт вызывает `run_cleanup(apply and not args.scan_only)`. Прежний вызов `run_cleanup(False)` заменён. Одного изменения описания Eagle для включения недостаточно — проверены и код, и файл разрешения.
|
||||||
|
|
||||||
|
Бэкапы запускаются отдельным заданием с `--apply`, без дополнительного файла разрешения. Немедленный разовый запуск при установке этого задания не выполнялся; расписание включено. Успех конкретного прохода проверяется по отчёту, отдельно от факта включения задания.
|
||||||
|
|
||||||
|
## Worktree и артефакты Xcode/SwiftPM
|
||||||
|
|
||||||
|
### Worktree
|
||||||
|
|
||||||
|
Репозиторий: `~/DuckDuckGo/apple-browsers.git`.
|
||||||
|
|
||||||
|
- Voom удаляет вмерженные worktree без локальных изменений; merge через squash/rebase проверяется с GitHub.
|
||||||
|
- `main`, ветки Git, заблокированные worktree и worktree с защищаемыми локальными изменениями сохраняются.
|
||||||
|
- Используются `--remove-merged-worktrees --github-merged-worktrees` с явным исключением `main`.
|
||||||
|
|
||||||
|
### Стандартный DerivedData
|
||||||
|
|
||||||
|
Каталог: `~/Library/Developer/Xcode/DerivedData`.
|
||||||
|
|
||||||
|
Проектная папка подходит для удаления, если:
|
||||||
|
|
||||||
|
1. Её `WorkspacePath` указывает на уже отсутствующий проект в домашнем каталоге; либо
|
||||||
|
2. Во всём содержимом нет изменений **48 часов**, и `LastAccessedDate` не указывает на недавнее обращение.
|
||||||
|
|
||||||
|
Требуются метаданные проекта или узнаваемые признаки Xcode output. Общие кэши без таких признаков сохраняются. Для возрастного правила учитывается максимум `mtime` и `ctime` всех элементов, включая каталоги; перед удалением условие перепроверяется.
|
||||||
|
|
||||||
|
### Внутрипроектные папки
|
||||||
|
|
||||||
|
Поиск **рекурсивный** внутри:
|
||||||
|
|
||||||
|
- `~/Developer`
|
||||||
|
- `~/DuckDuckGo`
|
||||||
|
- `~/.codex/worktrees`
|
||||||
|
- `~/Documents/Codex`
|
||||||
|
- `~/Documents/code`
|
||||||
|
|
||||||
|
| Имена каталогов | Условие |
|
||||||
|
|---|---|
|
||||||
|
| `.build` | 48 часов без изменений во всём дереве и признаки SwiftPM: `workspace-state.json`, `build.db`, `debug.yaml` или `release.yaml` |
|
||||||
|
| `dd`, `deriveddata`, `DerivedData`, `.build-dd` | 48 часов без изменений во всём дереве и признаки Xcode output |
|
||||||
|
|
||||||
|
Имена Xcode-папок сравниваются без учёта регистра. Признаки Xcode: например, `Build/Intermediates.noindex/XCBuildData/build.db`, либо `info.plist` с `WorkspacePath` вместе со стандартными каталогами результатов сборки. Одного имени папки недостаточно.
|
||||||
|
|
||||||
|
При обходе пропускаются ссылки, `.git`, `node_modules`, `.venv`, `venv`, `target`, `.Trash`, `SourcePackages` и сами корни артефактов. Внутри найденного корня возраст проверяется по всему содержимому.
|
||||||
|
|
||||||
|
Основной проход откладывает удаление при обнаружении процессов сборки `xcodebuild`, `swift-build`, `swiftc`, `swift-frontend`, `clang`, `ld` или при невозможности проверить процессы.
|
||||||
|
|
||||||
|
## Симуляторы Xcode
|
||||||
|
|
||||||
|
- Используется **непустой `lastUsedAt`** из `device.plist`.
|
||||||
|
- Давность последнего использования — **от 7 дней**.
|
||||||
|
- Последнее использованное устройство сохраняется; при одинаковой максимальной дате сохраняются все совпадения.
|
||||||
|
- Запущенные устройства сохраняются. Непосредственно перед удалением повторно проверяются даты и состояние через `simctl`; удаляется только `Shutdown`.
|
||||||
|
- Устройства без даты использования не удаляются. Возраст создания и `lastBootedAt` не подставляются вместо `lastUsedAt`.
|
||||||
|
- Принудительной остановки и `simctl delete all` нет.
|
||||||
|
|
||||||
|
## `/private/tmp`: 4 часа
|
||||||
|
|
||||||
|
Удаление включено в основном проходе раз в два часа.
|
||||||
|
|
||||||
|
- Рассматриваются обычные файлы любых расширений, включая исходники, патчи, логи и результаты сборок.
|
||||||
|
- Условие: **не менее 4 часов с `mtime` каждого файла**. `ctime` и возраст родительской папки не используются.
|
||||||
|
- Старый файл может быть удалён рядом со свежим; свежий файл внутри старой папки сохраняется.
|
||||||
|
- Открытые файлы сохраняются. Открытый каталог или рабочий каталог процесса защищает всё своё поддерево. Проверка — через `lsof`.
|
||||||
|
- Ссылки, сокеты, специальные файлы, чужие владельцы и другие файловые системы пропускаются. Непустые каталоги целиком не удаляются; пустые каталоги скрипт также отдельно не убирает.
|
||||||
|
- Перед удалением перепроверяются inode, размер, `mtime`, принадлежность, открытые пути; проход по каталогам выполняется без следования ссылкам.
|
||||||
|
- При недоступности `lsof` удаление запрещено. При активной сборке удаление откладывается.
|
||||||
|
|
||||||
|
## Бэкапы Balda и Virfield: сутки
|
||||||
|
|
||||||
|
Порог — **24 часа**. Для снимка берётся самая новая дата создания (`birthtime`) или `mtime` во всём дереве. Это защищает свежие APFS-клоны, у которых сохранились старые даты содержимого. Недавнее изменение любого элемента откладывает удаление всего снимка.
|
||||||
|
|
||||||
|
### Balda
|
||||||
|
|
||||||
|
Полностью проверяются отдельные снимки внутри:
|
||||||
|
|
||||||
|
- `~/.local/share/balda-workspace/backups/`
|
||||||
|
- `~/Docker/balda-mm-mac/state/setup-backups/`
|
||||||
|
- `~/Docker/balda-mm-eagle/state/setup-backups/`
|
||||||
|
|
||||||
|
Только в корнях `~/Docker/balda-mm-mac/` и `~/Docker/balda-mm-eagle/` дополнительно выбираются:
|
||||||
|
|
||||||
|
- Каталоги/файлы `backup-*`, `state-backup-*`, `state-failed-*`.
|
||||||
|
- Файлы с шаблонами `*.before-*`, `*.backup`, `*.backup-*`, `*.bak`, `*.bak-*`.
|
||||||
|
|
||||||
|
Рабочие `state`, текущие Compose/config-файлы и рабочая БД под эти шаблоны не попадают.
|
||||||
|
|
||||||
|
### Virfield
|
||||||
|
|
||||||
|
- `backups/` и `migration-backups/` внутри `~/.virfield-tart/` и `~/.virfield-v2/`.
|
||||||
|
- `~/.virfield-v2/upgrades/`.
|
||||||
|
- `~/.virfield-v2/retained-maintenance/`.
|
||||||
|
- В корнях `~/.virfield-tart/` и `~/.virfield-v2/` — только резервные файлы `*.before-*`, `*.backup`, `*.backup-*`, `*.bak`, `*.bak-*`.
|
||||||
|
|
||||||
|
Рабочие `state.db`, `images`, `leases`, `nodes`, текущие конфиги и обычные диски VM целями не являются.
|
||||||
|
|
||||||
|
### Защита бэкапов
|
||||||
|
|
||||||
|
- Используемый снимок или его содержимое сохраняются по проверке `lsof`; использование выделенного каталога бэкапов также защищает его содержимое.
|
||||||
|
- Возраст, inode и открытые пути проверяются повторно перед удалением.
|
||||||
|
- Корни со ссылками в пути, чужие владельцы, другие файловые системы, сокеты и специальные файлы пропускаются с записью в отчёт.
|
||||||
|
- Ссылки внутри снимка не обходятся. Для удаления read-only каталогов снимка добавляются права только владельцу каталогов; файлы и внешние цели ссылок не изменяются.
|
||||||
|
- Последний бэкап не закреплён навсегда: по этой политике все подходящие снимки старше суток могут быть удалены.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
Цель жёстко закреплена: context **`colima`**, builder **`colima`**, socket `/Users/admin/.colima/default/docker.sock`. Перед работой проверяется соответствие контекста и работающего builder. Другие и неактивные builders не запускаются.
|
||||||
|
|
||||||
|
### BuildKit cache
|
||||||
|
|
||||||
|
| Тип | Минимальное неиспользование |
|
||||||
|
|---|---:|
|
||||||
|
| Обычный поддерживаемый build cache | 14 дней от `LastUsedAt` |
|
||||||
|
| Cache mounts и распознанные слои установки зависимостей | 30 дней от `LastUsedAt` |
|
||||||
|
|
||||||
|
Зависимости распознаются по типу `exec.cachemount` и описаниям с apt/apk/dnf/yum, pip/uv, npm/pnpm/yarn, cargo, gem/bundler/composer, `go mod`.
|
||||||
|
|
||||||
|
Сохраняются `InUse`, `Shared`, internal/frontend, неизвестные типы и записи без корректной даты. Удаление ограничено точным списком cache-ID и фильтром возраста; BuildKit повторно проверяет использование. Broad `--all` не используется.
|
||||||
|
|
||||||
|
### Образы: 30 дней без наблюдаемых ссылок
|
||||||
|
|
||||||
|
Область автоматической очистки:
|
||||||
|
|
||||||
|
- `execution-broker` и `execution-broker-*`.
|
||||||
|
- `execution-prism-adapter`.
|
||||||
|
- `balda` и `balda-*`, включая старые обычные версии.
|
||||||
|
- Образы без тегов и без digest-reference.
|
||||||
|
|
||||||
|
Условия и исключения:
|
||||||
|
|
||||||
|
- Нет ссылок **любых контейнеров**, включая остановленные, не менее 30 дней по журналу наблюдений.
|
||||||
|
- При появлении ссылки таймер сбрасывается; после исчезновения начинается новый отсчёт.
|
||||||
|
- Сохраняются образы, найденные в доступных файлах конфигураций и переменных окружения работающих контейнеров.
|
||||||
|
- Для обычных версий сохраняется одна самая новая сборка **для каждого repository** по Docker `Created`; одинаковые максимальные даты сохраняются все. Это дата сборки, а не сравнение номеров версий.
|
||||||
|
- Явно тестовые/временные/резервные Balda-теги (`test`, `temp`, `tmp`, `scratch`, `fixture`, `acceptance`, `prNN`, `backup`, `bak`, `rollback`) могут истечь и без сохранения «последнего тестового» образа.
|
||||||
|
- Для Broker дополнительно защищены теги/имена с `rollback`, `base`, `accepted`, `approved`, `stable`, `latest`, `current`, `production`, `prod`. Эти закрепления могут сохранять больше одной версии.
|
||||||
|
- Для Balda постоянная защита всех исторических версий отключена; действуют ссылки, конфигурации, последняя обычная версия и срок 30 дней.
|
||||||
|
- Перед каждым удалением повторно проверяются Docker inventory, конфигурации, ссылки, возраст наблюдений и теги. Удаление — по точному ID без `--force`, с `--no-prune`.
|
||||||
|
|
||||||
|
`docker-image-observations.json` отражает периодические наблюдения за ссылками контейнеров. Он **не даёт полного last used**: использование в `FROM` и короткоживущие контейнеры между проверками могут не попасть в историю. Нельзя подменять эти 30 дней возрастом создания образа. История начата 21 октября 2026; потеря журнала запускает отсчёт заново.
|
||||||
|
|
||||||
|
### Известные ограничения Docker
|
||||||
|
|
||||||
|
- Именованные образы вне списка выше сохраняются независимо от отсутствия контейнеров. Например: **Mattermost**, `budget-*`, `workspace-smb`, `workspace-nfs-client`, `ssh-manager-isolation-fixture`, `go-cli*`, базовые Go/Node/Python и прочие внешние образы.
|
||||||
|
- Для Mattermost отсутствие ссылок контейнеров/конфигураций проверено; причина сохранения — ограничение списка разрешённых имён.
|
||||||
|
- При нескольких тегах удаление по ID может закончиться конфликтом; скрипт сохраняет образ и пишет `kept_conflict_or_error`.
|
||||||
|
- Полной очистки графа скрытых промежуточных образов нет: используется `/system/df` и `--no-prune`. Проявившийся безымянный родитель должен отдельно попасть под возрастное правило; ручная дочистка всей цепочки была шире автоматической политики.
|
||||||
|
- **Контейнеры, volumes и networks автоматически не удаляются.** Удаление Broker/restore-контейнеров 21 октября было отдельным ручным действием.
|
||||||
|
|
||||||
|
## Еженедельное обслуживание кэшей
|
||||||
|
|
||||||
|
По воскресеньям в 12:00 выполняются штатные команды:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
/opt/homebrew/bin/uv cache prune
|
||||||
|
/opt/homebrew/bin/npm cache verify
|
||||||
|
/opt/homebrew/bin/brew cleanup
|
||||||
|
```
|
||||||
|
|
||||||
|
Возраст и выбор данных определяют сами инструменты. `npm cache verify` проверяет/обслуживает кэш; полного удаления всего npm-кэша правило не обещает. Автообновление Homebrew на время этого задания отключено.
|
||||||
|
|
||||||
|
## Что ещё не входит в автоматические правила
|
||||||
|
|
||||||
|
- `WebKitBuild` из Downloads и архив прошивки iPhone `.ipsw`: 21 октября удалены вручную, общих правил для них нет.
|
||||||
|
- Android SDK исключён из согласованной очистки; отдельно его не трогать.
|
||||||
|
- Claude VM bundles/Cowork VM не очищаются этим сетапом.
|
||||||
|
- Все произвольные кэши приложений, все Docker images или все файлы Downloads не охватываются широким правилом.
|
||||||
|
|
||||||
|
## Проверка, отчёты и управление
|
||||||
|
|
||||||
|
JSON-отчёты в `~/.local/share/voom-cleanup/`:
|
||||||
|
|
||||||
|
| Отчёт | Что смотреть |
|
||||||
|
|---|---|
|
||||||
|
| `last-report.json` | Xcode/SPM, симуляторы, worktree, сводка tmp |
|
||||||
|
| `tmp-report.json` | Кандидаты tmp, `deleted_files`, `deletion_deferred`, ошибки |
|
||||||
|
| `docker-report.json` | BuildKit, образы, причины сохранения, результаты удаления |
|
||||||
|
| `backup-report.json` | Бэкапы, возраст, занятые пути, результаты и ошибки |
|
||||||
|
| `weekly-caches-report.json` | Exit code и вывод каждой штатной команды |
|
||||||
|
|
||||||
|
Основные логи: `launchd.log`, `launchd.stderr.log`; для еженедельного задания — `weekly-caches.log`, `weekly-caches.stderr.log`.
|
||||||
|
|
||||||
|
Включённое задание и поле `apply` сами по себе не подтверждают освобождение места: проверять время отчёта, `results`, ошибки и причины отложенного удаления. Основной скрипт при активной сборке может завершиться до обновления `last-report.json`; смотреть также лог и отдельный `tmp-report.json`.
|
||||||
|
|
||||||
|
Предпросмотр без удаления:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/cleanup.py --scan-only
|
||||||
|
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/tmp_cleanup.py
|
||||||
|
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/docker_cleanup.py
|
||||||
|
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/backup_cleanup.py
|
||||||
|
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/weekly-caches.py --check
|
||||||
|
```
|
||||||
|
|
||||||
|
`--scan-only` у основного скрипта показывает кандидатов артефактов/симуляторов/tmp, но пропускает Voom-проход worktree. Эти проверки могут обновлять отчёты; Docker также обновляет журнал наблюдений.
|
||||||
|
|
||||||
|
Для паузы задания использовать Eagle → Crons. Чтобы отключить только tmp, можно переименовать `enable-tmp-deletion`; остальные задачи основного прохода сохранят свои настройки. Для бэкапов отдельного файла разрешения нет — управлять их заданием в Eagle. Не создавать второе расписание поверх существующих labels.
|
||||||
|
|
||||||
|
Связанные заметки: [[personal/tech/eagle-dashboard-launchd|Eagle и launchd]], [[personal/tech/docker-mac-disk-issues|Docker на Mac: диск и история очисток]], [[personal/tech/docker_colima_setup|Colima]], [[personal/projects/virfield|Virfield]].
|
||||||
Reference in new issue
Block a user