private void _insertNodeIntoLeafsQueue(IList <DockerImageNode> leafs, DockerImageNode node) { var index = leafs.Count; for (int i = 0; i < leafs.Count; i++) { if (ImageDeletionOrder is ImageDeletionOrderType.ByImageCreationDate) { if (node.InspectResponse.Created < leafs[i].InspectResponse.Created) { index = i; break; } } else if (ImageDeletionOrder is ImageDeletionOrderType.ByImageLastTouchDate) { if (node.GetImageLastTouchDate(this._imageLastTouchDate) < leafs[i].GetImageLastTouchDate(this._imageLastTouchDate)) { index = i; break; } } } leafs.Insert(index, node); }
private void DeleteImage(DockerImageNode image, string repoTag) { var imageShortId = DockerImageNode.GetImageShortId(image.InspectResponse.ID); var imageRepoTag = repoTag ?? "<none>"; Console.WriteLine($"[{DateTime.UtcNow.ToString()} UTC] Preparing to delete image: {imageShortId} ({imageRepoTag})"); // Delete image if (!string.IsNullOrEmpty(repoTag)) { _dockerClient.Images.DeleteImageAsync($"{imageRepoTag}", new ImageDeleteParameters() { Force = false, PruneChildren = true }).Wait(); } else { _dockerClient.Images.DeleteImageAsync(image.InspectResponse.ID, new ImageDeleteParameters() { Force = false, PruneChildren = true }).Wait(); } Console.WriteLine($"[{DateTime.UtcNow.ToString()} UTC] Image deleted: {imageShortId} ({imageRepoTag})"); }
// Build image dependency tree public DockerImageNode BuildImageTree(IList <ImageInspectResponse> images, IList <ContainerListResponse> containerListResponses, IList <ContainerInspectResponse> containerInspectResponses, ImageInspectResponse image) { var containerList = containerListResponses.Where(r => string.Equals(r.ImageID, image.ID)).ToList(); IList <ContainerInspectResponse> containers = new List <ContainerInspectResponse>(); foreach (var container in containerList) { containers.Add(containerInspectResponses.Where(c => string.Equals(c.ID, container.ID)).FirstOrDefault()); } var dockerImageNode = new DockerImageNode() { InspectResponse = image, Children = new List <DockerImageNode>(), Containers = containers, }; var children = images.Where(i => string.Equals(i.Parent, image.ID)).ToList(); foreach (var child in children) { var childNode = BuildImageTree(images, containerListResponses, containerInspectResponses, child); childNode.Parent = dockerImageNode; dockerImageNode.Children.Add(childNode); } return(dockerImageNode); }
private long _getTotalDiskSpaceUsage(DockerImageNode imageNode) { var diskUsage = imageNode.DiskSize; foreach (var child in imageNode.Children) { diskUsage += _getTotalDiskSpaceUsage(child); } return(diskUsage); }
private IList <DockerImageNode> _getParents(DockerImageNode imageNode) { var node = imageNode; var parents = new List <DockerImageNode>(); while (node.Parent != null) { node = node.Parent; parents.Add(node); } return(parents); }
public bool CanDelete(DockerImageNode imageNode) { // We DO NOT delete image if it is in the whitelist if (this._imageWhitelist.MatchAny(imageNode.InspectResponse.RepoTags)) { return(false); } // We DO NOT delete image if there is a non blacklist state container exists using that image if (imageNode.GetContainerCount() - imageNode.GetContainerCount(_stateBlacklist) > 0) { return(false); } return(true); }
private IList <DockerImageNode> _getLeafImageNodes(DockerImageNode imageNode) { if (imageNode.Children.Count == 0) { return(new List <DockerImageNode> { imageNode }); } var leafs = new List <DockerImageNode>(); foreach (var child in imageNode.Children) { leafs.AddRange(_getLeafImageNodes(child)); } return(leafs); }
private void DeleteImages(IList <DockerImageNode> images) { var recycledDiskSize = 0L; var deletedImages = 0; var dic = new Dictionary <string, int>(); foreach (var image in images) { var imageShortId = DockerImageNode.GetImageShortId(image.InspectResponse.ID); var imageRepoTags = image.InspectResponse.RepoTags; try { // Remove containers in black list states StopAndRemoveContainers(image); // Delete tagged image references foreach (var repoTag in imageRepoTags) { DeleteImage(image, repoTag); } // Delete untagged image if (imageRepoTags.Count() == 0) { DeleteImage(image, null); } recycledDiskSize += image.DiskSize; deletedImages++; } // If container created before we delete the image, docker will throw exception // In this case, we catch the exception here but keep on deleting catch (Exception e) { Console.Error.WriteLine($"[{DateTime.UtcNow.ToString()} UTC] {e}"); } } Console.WriteLine($"[{DateTime.UtcNow.ToString()} UTC] {deletedImages} images deleted (total of {(int)(recycledDiskSize / (1024 * 1024))} MB)"); _logger.LogCounter("images-recycled-count", deletedImages); _logger.LogCounter("disk-space-recycled-mb", (int)(recycledDiskSize / (1024 * 1024))); }
private void _printDependencyGraph(DockerImageNode node, IList <DockerImageNode> highlights, IMatchlist containerStateBlacklist, int indentOffset = 0, int indent = 2, string highlightMarker = "<---") { Console.Write(_indent(indentOffset) + $"Image: {DockerImageNode.GetImageShortId(node.InspectResponse.ID)} ({node.InspectResponse.RepoTags.FirstOrDefault() ?? "<none>"}) {(int)((DateTime.UtcNow - node.InspectResponse.Created).TotalDays)} days {node.DiskSize/(1024*1024)} MB "); if (node.Containers.Count > 0) { Console.Write($"({node.GetContainerCount() - node.GetContainerCount(containerStateBlacklist)}/{node.Containers.Count}) "); } if (highlights.Any(i => string.Equals(i.InspectResponse.ID, node.InspectResponse.ID, StringComparison.InvariantCultureIgnoreCase))) { Console.Write($"{highlightMarker} {highlights.IndexOf(node) + 1}"); } Console.WriteLine(); foreach (var child in node.Children) { _printDependencyGraph(child, highlights, containerStateBlacklist, indentOffset + indent); } }
// Returns true when all child images can be deleted, meaning all child images have no running containers (all dead or exited) // and they are old enough to be safely deleted. private bool _canDelete(DockerImageNode image, List <DockerImageNode> imagesToBeRecycledInOrder) { var canDelete = true; foreach (var child in image.Children) { if (!_canDelete(child, imagesToBeRecycledInOrder)) { canDelete = false; } else { imagesToBeRecycledInOrder.Add(child); } } if (ImageDeletionOrder is ImageDeletionOrderType.ByImageCreationDate) { if (image.InspectResponse.Created >= DateTime.UtcNow.AddDays(-this.DaysBeforeDeletion)) { return(false); } } else if (ImageDeletionOrder is ImageDeletionOrderType.ByImageLastTouchDate) { var imageLastTouchDate = image.GetImageLastTouchDate(this._imageLastTouchDate); if (imageLastTouchDate >= DateTime.UtcNow.AddDays(-this.DaysBeforeDeletion)) { return(false); } } if (!base.CanDelete(image)) { canDelete = false; } return(canDelete); }
private void StopAndRemoveContainers(DockerImageNode image) { var imageShortId = DockerImageNode.GetImageShortId(image.InspectResponse.ID); // Remove containers in black list states foreach (var container in image.Containers) { var status = _dockerClient.Containers.InspectContainerAsync(container.ID).Result.State.Status; // If container state changed and not in black list states, we should skip deleting if (!_containerStateBlacklist.Match(status)) { throw new Exception($"Postponed deletion for image: {imageShortId} due to container status change"); } else { Console.WriteLine($"[{DateTime.UtcNow.ToString()} UTC] Stop and remove container: {container.ID} using image: {imageShortId}"); _dockerClient.Containers.StopContainerAsync(container.ID, new ContainerStopParameters()).Wait(); _dockerClient.Containers.RemoveContainerAsync(container.ID, new ContainerRemoveParameters() { Force = false, RemoveLinks = false, RemoveVolumes = false }).Wait(); } } }
public long GetDiskspaceUsage(DockerImageNode image) { return(image.DiskSize + image.Children.Sum(i => GetDiskspaceUsage(i))); }