How to create the smallest working docker image every time?
A Dockerfile creates a new layer for each of the commands in the file. Since layers are well, layered on top of each other - you cannot remove files that a previous layer added. This is why when you install packages, or download files, or create builds each in a separate command - these are still there in the image, even if in a future layer you removed them.

So if you just change this:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package


To this:

RUN apt-get update -y \
    &amp;&amp; apt-get install -y wget a-package \
    &amp;&amp; mkdir a-build-dir \
    &amp;&amp; wget http://some-site/very-big-source-code.tar.gz \
    &amp;&amp; tar xzvf very-big-source-code.tar.gz \
    &amp;&amp; do-some-compilation \
    &amp;&amp; apt-get purge -y wget \
    &amp;&amp; cd .. \
    &amp;&amp; rm -rf a-build-dir \
    &amp;&amp; apt-get purge -y a-package


You will get a much smaller image.



Another option, is to squash the image after you built it.
Q: How does the new docker --squash work?



Yet another option, is to choose a slim base image. For example, images that use Alpine Linux as their base instead of Debian, take just 10-15mb instead of 180-250mb. And this is before adding your own application and data. Many official base images on Docker Hub have an alpine version.