How can I view the Dockerfile in an image?

Hi,

Looking at some images in the repository (this one, for example: https://hub.docker.com/r/filippobosi/mfi/) I do not see the Dockerfile used to create it.

Is there a way to pull the image and then see the Dockerfile at the origin of this image?

Thanks

Hi. I don’t know why it isn’t like in dockerhub, but most entries in the public registry are built from github. A quick search reveals https://github.com/filippobosi/docker-mfi where you can find a dockerfile. As far as I know, you cannot get the used Dockerfile from the image. It’s just used to build it.

1 Like

TL;DR
So if you have a docker image that was built by a dockerfile, you can recover this information (All except from the original FROM command, which is important, I’ll grant that. But you can often guess it, especially by entering the container and asking “What os are you?”). However, the maker of the image could have manual steps that you’d never know about anyways, plus they COULD just export an image, and re-import it and there would be no intermediate images at that point.


There is only one reason why the Dockerfile is not on the hub.

  1. It wasn’t “auto built” from the git repo.

Instead, the images are pushed from the users computer after building.

Now there are a few reasons why this would happen

  1. The user just didn’t set it up that way, that simple.
  2. It is a base image, created from a chroot-like directory of files. There is no Dockerfile to represent this process.
  3. Building requires special arguments/files not available in the auto build process
  4. It doesn’t makes sense to use the auto build structure to create multiple tags.
  5. Building the docker image required an interactive step that wasn’t/can’t be Dockerfile-ed
  6. etc…

However, if a Dockerfile is used (as ipptyf found it was in this case), when you docker pull the image, you can recover a history of the Dockerfile commands (which are not the dockerfile itself, but close enough). However, keep in mind that manual edits to images could have been performed and committed, and would not show up with this procedure

Manual version

  1. docker inspect filippobosi/mfi
    Shows the last command in the dockerfile used under ConatinerConfig.Cmd. It also shows the parent (aac12014)
  2. docker inspect aac12014
    Shows the second last command in the dockerfile used, etc…

Bash magic

function dc_trace_cmd() {
  local parent=`docker inspect -f '{{ .Parent }}' $1` 2>/dev/null
  declare -i level=$2
  echo ${level}: `docker inspect -f '{{ .ContainerConfig.Cmd }}' $1 2>/dev/null`
  level=level+1
  if [ "${parent}" != "" ]; then
    echo ${level}: $parent 
    dc_trace_cmd $parent $level
  fi
}
  1. dc_trace_cmd filippobosi/mfi
    This will not print in “Last command first” order, the list of dockerfile commands. Remember, if an intermediate image is run and commited, there is no record of what happened. This does not guarantee you can re-create a dockerfile, only shows you the cookie crumb trail left behind.
0: {[/bin/sh -c #(nop) CMD [/usr/lib/jvm/java-6-openjdk-amd64/jre/bin/java -Xmx1024M -jar /usr/lib/mfi/lib/ace.jar start]]}
1: aac1201414083a093c714c8b7090408edf970445e119883a74b7b9453fd9db9f
1: {[/bin/sh -c #(nop) EXPOSE 6080/tcp 6443/tcp]}
2: 4db9381d42448ed494d0ce33f544ca0e9356692053251f2a266e71675da16952
2: {[/bin/sh -c apt-get install -y mfi-beta]}
3: 431cc26d6aeb1a996114b6f8db99b3b3922632edffaa52958c1002e6520aedf0
3: {[/bin/sh -c apt-get update]}
4: b3443169958a009f6215b96417d9d0b865255726596f177d2e36fd9f049788c5
4: {[/bin/sh -c apt-key adv --keyserver keyserver.ubuntu.com --recv C0A52C50]}
5: a800750eed1fe2ea9c86cf5c828b54a23cbefc7e2d06b966ebfbd75914963dca
5: {[/bin/sh -c echo 'deb http://dl.ubnt.com/mfi/distros/deb/ubuntu ubuntu ubiquiti' >> /etc/apt/sources.list]}
6: 996ab0d2afe09131de6c3bbce375b517cacf54ca7bc6cfed1a0eb9c66852fa62
6: {[/bin/sh -c apt-get update]}
7: fc0d0fd55e22a3bc558b2b51dfb16ca873b3cfce1f712a527921490b8f0bad28
7: {[/bin/sh -c #(nop) MAINTAINER filippobosi]}
8: 1185472e68e981b60e1b9b2fdf50b535a99cace38d9a2963168806496c9db78d
8: {[/bin/sh -c #(nop) CMD ["/bin/bash"]]}
9: a8444a8212ea7f2d92e73c5464a0e81113428c3c6e34f1f60bff6f807cf8a778
9: {[/bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list]}
10: 398cb6c3acd3b3b63a0fa77ebac4e673e38218248bd068f4a240f0301945d933
10: {[/bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-rc.d && echo 'exit 101' >> /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d && dpkg-divert --local --rename --add /sbin/initctl && cp -a /usr/sbin/policy-rc.d /sbin/initctl && sed -i 's/^exit.*/exit 0/' /sbin/initctl && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup && 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 && 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 && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes]}
11: bfb92c15de016926b76a101de38d1ddfd2b114cdd2999de1b36050f8f3fd9c9f
11: {[/bin/sh -c #(nop) ADD file:b43bf069650bac07b66289f35bfdaf474b6b45cac843230a69391a3ee342a273 in /]}

What does all this mean?

  1. The Last step (0:) is the CMD line of the dockerfile (here)
  2. 1: is the sha of the intermediate image (parent of 0:), and that command corresponds to this
  3. 2: is where it gets interesting. Instead of apt-get clean it is the apt-get install -f mfi-beta command. Why is this different? I would guess this is because the Dockerfile up on github is out of date. Notice it is dated June 4th, 2015, while the dockerhub image is actually dated June 3rd, but pushed 2 months ago. Either I missed something, or he added that command after building the particular image that was pushed to dockerhub (which I think is more likely).
  4. And so on…
  5. Step 8 is where it may get confusing. That sha probably refers to the ubuntu:14.04 image, as it was back in June of 2015… The CMD command is actually the last line in the ubuntu image. Knowing this is I guess this is where my method breaks apart… Running dc_trace_cmd ubuntu:14.04 will reveal a very similar trace of commands matching 8: - 11:
5 Likes

Thank you for the detailed and thorough response.

Why not just “docker history”?

$ docker history filippobosi/mfi
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
d6d2fff8c7a4        3 years ago         /bin/sh -c #(nop) CMD [/usr/lib/jvm/java-6-o…   0B
<missing>           3 years ago         /bin/sh -c #(nop) EXPOSE 6080/tcp 6443/tcp      0B
<missing>           3 years ago         /bin/sh -c apt-get install -y mfi-beta          248MB
<missing>           3 years ago         /bin/sh -c apt-get update                       2.84kB
<missing>           3 years ago         /bin/sh -c apt-key adv --keyserver keyserver…   25.9kB
<missing>           3 years ago         /bin/sh -c echo 'deb http://dl.ubnt.com/mfi/…   1.96kB
<missing>           3 years ago         /bin/sh -c apt-get update                       20.8MB
<missing>           3 years ago         /bin/sh -c #(nop) MAINTAINER filippobosi        0B
<missing>           3 years ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0B
<missing>           3 years ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$…   1.9kB
<missing>           3 years ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/poli…   195kB
<missing>           3 years ago         /bin/sh -c #(nop) ADD file:b43bf069650bac07b…   188MB

@qingvincentyin back then, docker history didn’t exist. Now, as long as you have a modern version of docker, docker history is far better :+1:

1 Like

I know it is a couple years later, but permit me to compliment you on the excellent scripting. --Bob

2 Likes

I’m an absolute beginner, and probably there are far more better ways to achieve, but the trick I do that works even if for any reason you can’t start the image.
1: first I get the files inside with
docker run -it <name_of_image> ls -la
2: I dump the content of whatever file I want (i.e: Dockerfile)
docker run -it <name_of_image> cat Dockerfile

–Javier