Search code examples
dockerdocker-build

Prevent docker from building the image from scratch after making changes to the code


A docker newbie, trying to develop in a docker container; I have a problem which is every time I make a single line change of code and try to rerun the container, docker will rebuild the image from scratch which takes a very long time; How should I set up the project correctly so it makes the best use of cache? Pretty sure it doesn't have to reinstall all the apt-get and pip installs (btw I am developing in python) whenever I make some changes to the source code. Anyone have any idea what I am missing. Appreciate any help.

My current docker file:

FROM tiangolo/uwsgi-nginx-flask:python3.6

# Copy the current directory contents into the container at /app
ADD ./app /app

# Run python's package manager and install the flask package
RUN apt-get update -y \
    && apt-get -y install default-jre \
    && apt-get install -y \
    build-essential \
    gfortran \
    libblas-dev \
    liblapack-dev \
    libxft-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app
ADD ./requirements.txt /app/requirements.txt
RUN pip3 install -r requirements.txt

Solution

  • Once the cache breaks in a Dockerfile, all of the following lines will need to be rebuilt since they no longer have a cache hit. The cache search looks for an existing previous layer and an identical command (or contents of something like a COPY) to reuse the cache. If both do not match, then you have a cache miss and it performs the build step. For your scenario, you simply need to reorder your lines to make sure the frequently changing part is at the end rather than the beginning of the file:

    FROM tiangolo/uwsgi-nginx-flask:python3.6
    
    # Run python's package manager and install the flask package
    RUN apt-get update -y \
        && apt-get -y install default-jre \
        && apt-get install -y \
        build-essential \
        gfortran \
        libblas-dev \
        liblapack-dev \
        libxft-dev \
        && rm -rf /var/lib/apt/lists/*
    
    WORKDIR /app
    COPY requirements.txt /app/requirements.txt
    RUN pip3 install -r requirements.txt
    
    # Copy the current directory contents into the container at /app
    COPY app /app
    

    I've also modified your ADD lines to COPY because you don't need the extra features provided by ADD.

    During development, I'd recommend mounting app as a volume in your container so you don't need to rebuild the image for every code change. You can leave the COPY app /app inside your Dockerfile and the volume mount will simply overlay the directory, hiding anything in your image at that location. You only need to restart your container to pickup your modifications. Once finished, a build will create an image that looks identical to your development environment.