├── Dockerfile ├── entrypoint.py └── README.md /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | RUN apk add --update python3 wget \ 4 | && wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py \ 5 | && python3 get-pip.py --break-system-packages \ 6 | && apk del wget \ 7 | && pip3 install --break-system-packages -U docker \ 8 | && rm -f get-pip.py \ 9 | && yes | pip3 uninstall --break-system-packages pip 10 | 11 | COPY entrypoint.py /root 12 | 13 | ENTRYPOINT ["/root/entrypoint.py"] 14 | -------------------------------------------------------------------------------- /entrypoint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from sys import argv, exit 4 | import re 5 | 6 | import docker 7 | 8 | 9 | class ImageNotFound(Exception): 10 | pass 11 | 12 | 13 | class Main: 14 | def __init__(self): 15 | self.cmds = [] 16 | self.client = docker.from_env() 17 | if len(argv) < 2: 18 | exit(f"No image provided!") 19 | self.image = self._get_image(argv[-1]) 20 | self.history = self.image.history() 21 | self._parse_history() 22 | self.cmds.reverse() 23 | self._print_cmds() 24 | 25 | def _print_cmds(self): 26 | for i in self.cmds: 27 | print(i) 28 | 29 | def _get_image(self, image_id): 30 | try: 31 | return self.client.images.get(image_id) 32 | except: 33 | raise ImageNotFound("Image {} not found\n".format(image_id)) 34 | 35 | def _insert_step(self, step): 36 | # ignore the end "# buildkit" comment 37 | step = re.sub("\s*# buildkit$", "", step) 38 | if "#(nop)" in step: 39 | to_add = step.split("#(nop)")[1].strip() 40 | else: 41 | # step may contains "/bin/sh -c ", just ignore it 42 | to_add = "RUN {}".format(step.replace("/bin/sh -c ", "")) 43 | to_add = to_add.replace("&&", "\\\n &&") 44 | self.cmds.append(to_add.strip(" ")) 45 | 46 | def _parse_history(self, rec=False): 47 | first_tag = False 48 | actual_tag = False 49 | for i in self.history: 50 | if i["Tags"]: 51 | actual_tag = i["Tags"][0] 52 | if first_tag and not rec: 53 | break 54 | first_tag = True 55 | self._insert_step(i["CreatedBy"]) 56 | if not rec: 57 | self.cmds.append("FROM {}".format(actual_tag)) 58 | 59 | 60 | Main() 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dockerfile from image 2 | 3 | **This project is only at the proof-of-concept state yet** 4 | 5 | I would happily add features to this project, feel free to create an issue 6 | for any suggestion. 7 | 8 | ## How To 9 | 10 | The goal of this project is to easily generate a Dockerfile from an existing 11 | Docker image. 12 | 13 | To build the image from source (this step is not mandatory as the image also 14 | is on the Docker Hub): 15 | 16 | git clone https://github.com/lukapeschke/dockerfile-from-image.git 17 | cd dockerfile-from-image 18 | docker build -t lukapeschke/dfa . 19 | 20 | To get a Dockerfile from an existing image: 21 | 22 | docker run --rm -v '/var/run/docker.sock:/var/run/docker.sock' lukapeschke/dfa 23 | 24 | ## Example with the official ubuntu image: 25 | 26 | $ docker images 27 | REPOSITORY TAG IMAGE ID CREATED 28 | ubuntu latest c73a085dc378 12 days ago 29 | 30 | $ docker run --rm -v '/var/run/docker.sock:/var/run/docker.sock' lukapeschke/dfa c73a085dc378 31 | FROM ubuntu:latest 32 | ADD file:cd937b840fff16e04e1f59d56f4424d08544b0bb8ac30d9804d25e28fb15ded3 in / 33 | RUN /bin/sh -c set -xe \ 34 | && echo '#!/bin/sh' > /usr/sbin/policy-rc.d \ 35 | && echo 'exit 101' >> /usr/sbin/policy-rc.d \ 36 | && chmod +x /usr/sbin/policy-rc.d \ 37 | && dpkg-divert --local --rename --add /sbin/initctl \ 38 | && cp -a /usr/sbin/policy-rc.d /sbin/initctl \ 39 | && sed -i 's/^exit.*/exit 0/' /sbin/initctl \ 40 | && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \ 41 | && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \ 42 | && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \ 43 | && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \ 44 | && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \ 45 | && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes \ 46 | && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests 47 | RUN /bin/sh -c rm -rf /var/lib/apt/lists/* 48 | RUN /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list 49 | RUN /bin/sh -c mkdir -p /run/systemd \ 50 | && echo 'docker' > /run/systemd/container 51 | CMD ["/bin/bash"] 52 | --------------------------------------------------------------------------------