Если директория C:\ProgramData\docker\windowsfilter неприлично разрослась, а команда
docker system prune -a -f
не помогает освобить место, то нужно почистить orphan (сиротские) слои, не принадлежащие никаким образам.
Function Find-OrphanDockerLayers () {
param (
[switch]$RenameOrphanLayers,
[switch]$CalcSize
)
If ($RenameOrphanLayers) {
Write-Warning "$($env:COMPUTERNAME) -RenameOrphanLayers option enabled, will rename all orphan layers"
}
# Get known layers on Docker images
[array]$ImageDetails += docker images -q | ForEach { docker inspect $_ | ConvertFrom-Json }
ForEach ($Image in $ImageDetails) {
$ImageLayer = $Image.GraphDriver.Data.dir
[array]$ImageLayers += $ImageLayer
$LayerChain = Get-Content "$ImageLayer\layerchain.json"
If ($LayerChainFileContent -ne "null") {
[array]$ImageParentLayers += $LayerChain | ConvertFrom-Json
}
}
# Get known layes on Docker containers
[array]$ContainerDetails = docker ps -a -q | ForEach { docker inspect $_ | ConvertFrom-Json}
ForEach ($Container in $ContainerDetails) {
[array]$ContainerLayers += $Container.GraphDriver.Data.dir
}
# Get layers on disk
$LayersOnDisk = (Get-ChildItem -Path C:\ProgramData\Docker\windowsfilter -Directory).FullName
$ImageLayers += $ImageParentLayers
$UniqueImageLayers = $ImageLayers | Select-Object -Unique
[array]$KnownLayers = $UniqueImageLayers
$KnownLayers += $ContainerLayers
# Find orphan layers
$OrphanLayersTotal = 0
ForEach ($Layer in $LayersOnDisk) {
If ($KnownLayers -notcontains $Layer) {
[array]$OrphanLayer += $Layer
If ($CalcSize) {
$LayerSize = (Get-ChildItem -Path $Layer -Recurse -ErrorAction:SilentlyContinue | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum
$OrphanLayersTotal += $LayerSize
Write-Warning "$($env:COMPUTERNAME) - Found orphan layer: $($Layer -Replace '\r\n','') with size: $(($LayerSize -Replace '\r\n','') / 1MB) MB"
}
else {
Write-Warning "$($env:COMPUTERNAME) - Found orphan layer: $($Layer -Replace '\r\n','').."
}
If (($RenameOrphanLayers) -and ($Layer -notlike "*-removing")) {
GrantFullAccessToAdmins $Layer
$LayerNewPath = $Layer + "-removing"
Rename-Item -Path $Layer -NewName $LayerNewPath
}
}
}
Write-Host "$($env:COMPUTERNAME) - Layers on disk: $($LayersOnDisk.count)"
Write-Host "$($env:COMPUTERNAME) - Image layers: $($UniqueImageLayers.count)"
Write-Host "$($env:COMPUTERNAME) - Container layers: $($ContainerLayers.count)"
If ($CalcSize) {
$OrphanLayersTotalMB = $OrphanLayersTotal / 1MB
Write-Warning "$($env:COMPUTERNAME) - Found $($OrphanLayer.count) orphan layers with total size $OrphanLayersTotalMB MB"
}
else {
Write-Warning "$($env:COMPUTERNAME) - Found $($OrphanLayer.count) orphan layers..."
}
}
function GrantFullAccessToAdmins ($Path) {
$NewAcl = Get-Acl -Path $Path
# Set properties
$identity = "BUILTIN\Administrators"
$fileSystemRights = "FullControl"
#$type = "Allow"
# Create new rule
$fileSystemAccessRuleArgumentList = $identity, $fileSystemRights, "None", "None","Allow" # $type (https://stackoverflow.com/a/37015095)
$fileSystemAccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $fileSystemAccessRuleArgumentList
# Apply new rule
$NewAcl.SetAccessRule($fileSystemAccessRule)
Set-Acl -Path $Path -AclObject $NewAcl
}
# Purge untagged images
if ( $(docker images -f "dangling=true" -q) ) { Invoke-Expression 'docker rmi $(docker images -f "dangling=true" -q)' }
GrantFullAccessToAdmins "C:\ProgramData\docker\windowsfilter"
Find-OrphanDockerLayers -RenameOrphanLayers
# Due to short docker service shutdown timeout I will restart it untill all labeled layers be purged.
while (Get-ChildItem -Path C:\ProgramData\Docker\windowsfilter -Directory -Filter "*-removing") {
Stop-Service *docker*
Restart-Service *docker*
}
Discussion