Last active
July 14, 2022 19:48
-
-
Save shreve/1a8cab41ecc344c1fbc2b4b0ca0745ac to your computer and use it in GitHub Desktop.
Docker layer size report
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Docker layer size report | |
python docker_layer_sizes.py <image> | |
Returns the size of each layer of the image and the command that created it. | |
This is a decorative layer on top of the docker history command. | |
""" | |
import subprocess | |
import sys | |
import re | |
from pygments import highlight | |
from pygments.styles import get_style_by_name | |
from pygments.lexers import DockerLexer | |
from pygments.formatters import Terminal256Formatter | |
INDENT = 8 | |
LEXER = DockerLexer() | |
FORMATTER = Terminal256Formatter(style=get_style_by_name("rrt")) | |
MULTISPACE = re.compile(r" {2,}") | |
NOP_PREFIX = re.compile(r".*#\(nop\) +", re.DOTALL) | |
class Command: | |
shell = "" | |
def __init__(self, string): | |
self.size, self.instr = string.split("\t", 1) | |
if self.size == "0B": | |
self.size = "" | |
if self.cmd == "SHELL": | |
self.__class__.shell = self.text[1:-1] | |
@property | |
def cmd(self): | |
return self.instr.split(" ", 1)[0] | |
@property | |
def text(self): | |
return self.instr.split(" ", 1)[1] | |
def __repr__(self): | |
instr = re.sub(NOP_PREFIX, "", self.instr) | |
instr = re.sub(MULTISPACE, " ", instr) | |
if self.cmd != "SHELL": | |
instr = instr.replace(f"RUN {self.__class__.shell}", "RUN") | |
instr = instr.replace(self.__class__.shell, "RUN") | |
instr = instr.replace(" RUN", "\n" + " " * (INDENT + 3)) | |
instr = highlight(instr, LEXER, FORMATTER).strip() | |
instr = [x.strip() for x in instr.split("&&")] | |
instr = f"\n{'':>12}&&".join(instr) | |
return f"{self.size:>6} {instr}" | |
def data(image) -> str: | |
"""Ask docker for our data.""" | |
proc = subprocess.run( | |
[ | |
"docker", | |
"history", | |
"--no-trunc", | |
"--format", | |
"{{.Size}}\t{{.CreatedBy}}", | |
image, | |
], | |
check=True, | |
capture_output=True, | |
) | |
return [Command(line) for line in proc.stdout.decode("utf-8").strip().split("\n")][ | |
::-1 | |
] | |
def main(image): | |
"""Run the program.""" | |
output = data(image) | |
for line in output: | |
print(line) | |
if __name__ == "__main__": | |
main(sys.argv[1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment