Docker Links in 'windowsfilters'
« | 14 Mar 2021 | »Dank Docker war bei mir
vor ein paar Wochen eine Reparaturinstalltion notwendig geworden.
Offiziell war ich natürlich selbst daran Schuld, weil man den von Docker
angelegten windowsfilters
Ordner auf gar keinen Fall selbst löschen darf!
Grund genug sich das Thema mal etwas genauer anzusehen …
Docker für Windows Server
speichert seine Images standardmäßig im Verzeichnis c:\ProgramData\docker\windowsfilters
.
Und damit das richtig undurchschaubar wird, werden tausende Links im
Dateisystem angelegt, damit alle Docker-Container auf “das gleiche”
Basissystem verweisen (verlinken) können.
Wenn man Docker deinstalliert, bleibt dieser Ordner gerne übrig und
sein Inhalt lässt sich großteils nicht löschen, weil bei den Dateien
sowohl der Administrators
Gruppe wie auch dem LocalSystem
sämtliche
Schreib und Löschrechte fehlen.
Die offizielle Lösung, die mir ein sehr lieber Kollege empfohlen hat,
lautet docker-ci-zap.
Der dokumentierte Aufruf .\docker-ci-zap.exe -folder "C:\ProgramData\docker"
löscht das ganze Verzeichnis inklusive dem windowsfilters
Ordner
über einige spezielle API Funktionen im Systemkern.
Doch wenn man per Konfiguration die Speicherung wo anders hin verlagert hat
(z.B.: per Konfiguration in c:\ProgramData\docker\config\daemon.json
) aber
schon vorher Images geladen hat, dann stürzt (bei mir zumindest) das Tool
docker-ci-zap
einfach ab und macht gar nichts.
Auf keinen Fall den Ordner direkt löschen!
Tja, als Admin löst man das Problem von nicht-löschbaren Ordnern gerne mit
so etwas wie:
icacls C:\ProgramData\docker\windowsfilters /grant Administrators:F /Q /C /T
Dann erhält die Admin-Gruppe auf alles Schreibrechte und das Löschen kann
beginnen (manchmal muss man auch noch den Besitz übernehmen).
Und damit löscht man sich auch gleich die halbe Windows Umgebung weg.
Zumindest fehlen aber diverse Benutzerprofile und Registry-Hive-Dateien.
Denn innerhalb der Images gibt es diverse Dateisystem-Links. Man nennt sie
auch “symbolische Verknüpfungen”,
die in NTFS
durch so genannte Reparse-Points
umgesetzt werden.
Während innerhalb einer Docker-Session ein Link auf C:\Windows
auf einen Ordner innerhalb der windowsfilters
verweist, glaubt aber die
Windows-API von außerhalb, dass die Link-Verfolgung auf dem realen
C:\Windows
weiterläuft.
Und so löscht man sich mit einem
rmdir /s /q c:\ProgramData\docker\windowsfilters
wichtige Dateien des Host-Systems weg. Zwar lassen sich geladene DLLs
und Programme nicht löschen, aber diverse INF
und MANIFEST
Dateien in
System32
wandern still und heimlich ins Nirvana. Vor allem sind C:\Users
,
C:\ProgramData
und C:\Program Files
betroffen.
Ich weiß nicht, welche Dateien es am Ende genau trifft, aber es reichte aus,
dass mein System nicht mehr booten konnte. Das war mit der
Systemwiederherstellung zwar reparierbar, aber Spaß machte mir diese Aktion
absolut nicht.
Vor allem weil es meinen Rechner in der Firma betraf.
Lösungsansatz
Tatsächlich konnte ich dann nicht widerstehen und begann die APIs zu
studieren und ließ die Ergebnisse sofort ins GATE Projekt einfließen.
Junctions, “SymLinks” und das von
Docker und Hyper-V benutzte
“HCM” (Host Compute Service)
bauen alle auf Reparse-Points auf und ein jeder dieser Verzeichnis-Einträge
hat das Attribute FILE_ATTRIBUTE_REPARSE_POINT
gesetzt.
Und das bekommt man per GetAttributes()
oder FindFirstFile()
mitgeteilt.
Das Schöne dabei ist, dass klassische Windows APIs wie DeleteFile() und RemoveDirectory() im Normalfall nur den Reparse-Point löschen und nicht das Ziel, wo dieser hinzeigt.
Bei einer Standard-Löschung gehen die Tools durch alle Unterverzeichnisse
und löschen zuerst deren Inhalt und am Ende erst das Verzeichnis selbst.
Deshalb wird auch das reale C:\
Laufwerk durchlöchert, wenn man nur
windowsfilters
wegputzen will.
Die Lösung ist also bei jedem windowsfilters
Unterverzeichnis zu prüfen,
ob dieses ein Reparse-Point ist. Wenn ja, dann sollte RemoveDirectory()
funktionieren, obwohl der Inhalt gar nicht leer ist.
Und bei allen Nicht-Reparse-Points geht man wie üblich vor.
Auf diese Weise wird nur “innerhalb” des Docker-Images gelöscht.
Aber Achtung! Diese Angabe ist ohne Gewähr. Auch durch dieses Verfahren kann das laufenden System beschädigt oder zumindest beeinträchtigt werden. Anwendung auf eigene Gefahr!
Fazit
Bei einem Test der Link-Lösch-Prozedur wurde mein privater Docker-Server
scheinbar nicht beschädigt und ich konnte 11 GB auf C:\
freigeben, weil
die Images ohnehin auf D:\
nochmals heruntergeladen wurden.
Ein Packages
Verzeichnis ließ sich trotzdem nicht Löschen, aber das
ignoriere ich vorläufig mal.
Ich habe also wieder etwas gelernt und dem GATE Framework Reparse-Points
beigebracht.
Interessant dabei ist, dass Windows zwischen Datei und Verzeichnis-Links
per API unterscheidet, während POSIX SymLinks immer wie Dateien mit
unlink()
löscht und rmdir()
ausschließlich bei realen leeren Verzeichnissen funktioniert.
Angefressen bin ich trotzdem!
Von Docker hätte ich erwartet, dass es seine eigenen “Reinigungskräfte”
mitbringt. Wie die Netzsuche zeigte, haben sich auch schon andere Leute wegen
Docker einen PC oder einen Server zerschossen. Und eine gute Software sollte
solche “Missverständnisse” im Dateisystem erst gar nicht möglich machen.