Skip to main content
flotsam — cover

Izabrani projekti

flotsam

Čišćenje Docker diska koje zna iz kog projekta je ostao svaki objekat — indeks „projekat → direktorijum", pošten obračun slojeva i dry run podrazumevano.

  • Go 1.25
  • Docker SDK v28
  • SQLite (modernc.org)
  • Cobra
  • Vue 3 + Vite
  • GitHub Actions
  • ghcr.io multi-arch

Problem

docker system df rado će vam reći da je nestalo 84 GB. Ali ne odgovara na jedino pitanje koje je bitno pre brisanja:

Ovaj volume — iz kog je projekta i smem li da ga uklonim bez gubitka podataka?

Čim se kontejneri projekta uklone, njegovi volume-i postaju siročići. Na njima i dalje stoji labela com.docker.compose.project, ali nigde nije zapisano gde je taj projekat živeo na disku — i Docker tu vezu više ne može da rekonstruiše. Izbor se svodi na docker system prune -a (obriši sve i nadaj se) ili na to da desetine gigabajta stoje godinama.

Flotsam je ono što ispliva nakon što brod potone. Upravo to ovaj alat i sakuplja.

Šta zna, a Docker ne

flotsam vodi sopstveni indeks: projekat → direktorijum, u SQLite-u (čist Go, bez CGO), punjen pasivno pri svakom pokretanju iz labele com.docker.compose.project.working_dir — dakle dok kontejneri još postoje. Mesecima kasnije, kada kontejnera odavno nema, indeks i dalje odgovara:

🟢 legacy-crm                                     12.4 GB   ⚠ direktorijum ne postoji
   /home/v/work/legacy-crm  (poslednji put 2025-11-03, izvor: index)
   ├─ volume  legacy-crm_pgdata          8.1 GB   postgresql   🟡 sadrži podatke baze
   ├─ volume  legacy-crm_uploads         3.9 GB   unknown-data 🟢 direktorijum projekta obrisan
   └─ image   legacy-crm-app:latest       340 MB               🟢 direktorijum projekta obrisan

Razrešavanje imena je lanac sa eksplicitnim „nepoznato” na kraju: živa labela → indeks → skeniranje fajl sistema → unknown. A read-only proba montira volume da kaže šta je zaista unutra — postgres, mysql, mongo, redis ili neprepoznati podaci. Jer „8 GB nečega” nije osnov za odluku.

Pošten obračun oslobođenog prostora

Brisanje pet imidža ne oslobađa zbir njihovih veličina: dele slojeve. flotsam gradi graf slojeva i sloj računa kao oslobodiv samo kada sve reference na njega leže unutar skupa koji brišete, dok se imidži zakačeni za pokrenute kontejnere isključuju.

Najzanimljiviji deo bilo je poklapanje ImageHistory zapisa sa slojevima iz RootFS.Layers. Očigledno pravilo — uzeti zapise sa Size > 0 — dalo je na stvarnoj mašini svega 55 % poklapanja. Razlog: WORKDIR pravi pravi sloj nulte veličine. Klasifikacija zapisa po CreatedBy (RUN/COPY/ADD/WORKDIR prave sloj; ENV/CMD/ENTRYPOINT ne; #(nop) ne), uz relaxed prolaz za imidže od bazel/ko, podigla je cifru na 99,4 % — 333 od 335 imidža poklopilo se tačno.

Model rizika

Klasifikacija je 18 uređenih pravila, pobeđuje prvo koje se poklopi, a sve što se ne poklopi ni sa čim podrazumevano dobija risky, a ne „verovatno je u redu”:

NivoZnačenje
🟢safeDirektorijum projekta obrisan, dangling imidž, prazan volume, davno zaustavljen kontejner
🟡probably-safeProjekat miruje > 30 dana, skorašnji nekorišćen imidž, skorašnji build cache
🔴riskyVolume sadrži podatke baze, projekat je aktivan, poreklo nepoznato, putanja dvosmislena
neverZaštićen konfiguracijom, volume zakačen za kontejner, imidž pokrenutog kontejnera

risky i never nikada ne ulaze u plan, bez obzira na flagove. Crveni objekat se briše samo pojedinačno, po punom imenu, uz --force-risky.

Bezbednosne garancije

  1. apply je podrazumevano dry run; stvarno brisanje traži --no-dry-run.
  2. Volume sa RefCount > 0 nikada se ne briše — ni sa --force-risky.
  3. Inventar se ponovo prikuplja neposredno pre brisanja; sve što se u međuvremenu promenilo preskače se uz upozorenje.
  4. Nikakav docker system prune -a — samo ciljana brisanja po ID-u.
  5. Ništa van Docker-a se ne dira: ni direktorijumi projekata, ni disk imidž VM-a. flotsam host ispisuje komande za sažimanje Docker.raw / ext4.vhdx; vi ih pokrećete.
  6. Svaka operacija se dopisuje u ~/.local/share/flotsam/history.jsonl.
  7. Direktorijum se smatra „nestalim” samo kada je njegov roditelj vidljiv — nemontirano podstablo se nikada ne pomeša sa obrisanim projektom.

To poslednje pravilo nije teorijsko. Na macOS-u i Windows-u -v /:/host:ro montira koren virtuelne mašine Docker Desktop-a, a ne vaš disk: /host/Users postoji i prazan je. Bez pravila o vidljivom roditelju, kontejnerski build je 8 od 12 živih projekata proglasio siročićima. Sada flotsam prepoznaje situaciju, označava host fajl sistem kao neproverljiv, odbija da bilo šta nazove siročetom i to jasno kaže — umesto da vas poziva da obrišete žive podatke.

Isporuka

Po jedan statički binarni fajl po platformi, ukupno šest (linux/darwin/windows × amd64/arm64), koje GitHub Actions gradi na v* tagu, sa checksums.txt uz release; multi-arch imidž od 22 MB na ghcr.io; i Vue 3 SPA ugrađen u binarni fajl, pa go build ne traži Node — CI pada ako komitovan bundle odstupi od izvora. Sve što CLI ume dostupno je i u browseru na 127.0.0.1:7333: uz token, sa validacijom Host/Origin i bez kolačića.

Pouke

  • Vredni podaci nikada nisu bili u Docker-u: to je veza „projekat → direktorijum”, i morala je da se uhvati pre nego što zatreba. Pasivan indeks ne košta ništa po pokretanju — a u njemu je cela funkcija.
  • Benchmark iz specifikacije je hipoteza. Opisana heuristika za poklapanje slojeva na stvarnim imidžima radila je na 55 %; cifru „koliko će se zaista osloboditi” poštenom je učinila tek klasifikacija po CreatedBy.
  • Kada alat nešto ne može da proveri — na primer, ne vidi host fajl sistem — ispravan izlaz je odbijanje, a ne najbolja pretpostavka. Alati za brisanje nemaju pravo na optimizam.