title: Conventional way to resolve docker derived image build time vs. image size tradeoff
body: <p>Two constraints are often important in writing Dockerfiles: image size and image build time.</p>
  
  <p>It's a commonplace observation that time and space usage can often be traded off for one another.  However, it can be useful to avoid that choice by going for fast build time in development and small-but-slower builds in production.</p>
  
  <p>For example, if I write something like this in a project I can quickly rebuild the images in development when <code>frequently_changing_source_code</code> changes, because there is a layer with <code>build-essential</code> installed that can be reused in the derived image:</p>
  
  <p>base image:</p>
  
  <pre><code>RUN apt install build-essential python-dev &amp;&amp; \
   pip install some-pypi-project
  ADD frequently_changing_source_code
  </code></pre>
  
  <p>derived image:</p>
  
  <pre><code>FROM base_image
  RUN pip install another-pypi-project-requiring-build-essential
  ADD more_stuff
  </code></pre>
  
  <p>The above results in larger builds than this next version, which achieves the same functionality but sacrifices build times. Now whenever <code>frequently_changing_source_code</code> changes, rebuilding the derived image results in a re-install of <code>build-essential</code>:</p>
  
  <p>base image:</p>
  
  <pre><code>RUN apt install build-essential python-dev &amp;&amp; \
   pip install some-pypi-project &amp;&amp; \
   apt remove build-essential python-dev
  ADD frequently_changing_source_code
  </code></pre>
  
  <p>derived image:</p>
  
  <pre><code>FROM base_image
  RUN apt install build-essential python-dev &amp;&amp; \
   pip install another-pypi-project-requiring-build-essential &amp;&amp; \
   apt remove build-essential python-dev
  ADD more_stuff
  </code></pre>
  
  <p>I can imagine ways of solving this: for example, writing a slightly more complicated set of Dockerfiles that are parameterized on some sort of development flag, which has the first behaviour for development builds, and the second for production builds.  I suspect that would not result in Dockerfiles that people like to read and use, though.</p>
  
  <p><strong>So</strong>, how can I best achieve my ends <strong>without surprising other developers</strong>: i.e. using Dockerfiles that respect docker conventions as much as I can?</p>
  
  <p>Some notes about answers I've considered:</p>
  
  <p>I'm aware of the layer-caching behaviour of docker (that is why the ADD commands for both images in my example are at the end).</p>
  
  <p>I'm aware that one can mount code using -v.  Using -v is my usual practice, but this question is about building images, which is also something that happens in development (from time to time, it happens quite a lot).</p>
  
  <p>One obvious suggestion is to eliminate the base image.  However, note that for the projects concerned, the base image is typically a base for multiple images, so merging the base with those would result in a bunch of repeated directives in each of those Dockerfiles.  Perhaps this is the least-worst option, though.</p>
  
  <p>Also note that (again, in the projects I'm involved with) the mere presence of the <code>frequently_changing_source_code</code> does not by itself significantly contribute to build times: it is re-installs of packages like build-essential that does that.  <code>another-pypi-project-requiring-build-essential</code> typically does contribute significantly to build times, but perhaps not enough to need to eliminate that step in development builds too.</p>
  
  <p>Finally, though it is a commonly-cited nice feature of docker that it's possible to use the same configuration in development as in production, this particular source of variation is not a significant concern for us.</p>