Composer install in Dockerfile Without Breaking Cache
When building a Docker image for your PHP application there are some steps you should take to prevent the cache from being invalidated prematurely. Cache misses can slow down the build process drastically.
Consider the following Dockerfile snippet:
RUN curl -sS https://getcomposer.org/installer | \ php -- --install-dir=/usr/bin/ --filename=composer WORKDIR /app COPY . ./ RUN composer install --no-dev --no-interaction -o
The first instruction is to install Composer. Then we change the working directory to
/app which is created if it doesn’t already exist.
COPY instruction will copy your application’s source directory to the file system of the container. These files have likely been changed and the
COPY instruction will invalidate the cache, which means that all subsequent Dockerfile instructions will run on every build.
Having Composer install all its dependencies on every build is not ideal.
Here’s an alternative Dockerfile:
RUN curl -sS https://getcomposer.org/installer | \ php -- --install-dir=/usr/bin/ --filename=composer COPY composer.json ./ COPY composer.lock ./ RUN composer install --no-scripts --no-autoloader COPY . ./ RUN composer dump-autoload --optimize && \ composer run-scripts post-install-cmd
Instead of copying all the source files we only copy
composer.lock. These rarely change and will not invalidate the cache. Neither will the
RUN instruction unless you change the command itself.
With these files in place we can run
composer install before the cache is invalidated by the new application source files; our dependencies will not be downloaded with every Docker build. However, without the source files we cannot run our Composer scripts or build the autoloader just yet, so we use the
Then, only after we have copied all the source files, we dump the autoloader and run the scripts.
The output from
docker build will look something like this:
Step 9 : COPY composer.json ./ ---> Using cache ---> b9c0e85272f6 Step 10 : COPY composer.lock ./ ---> Using cache ---> b9e7a481b7ab Step 11 : RUN composer install --no-scripts --no-autoloader ---> Using cache ---> 415b3cc08fdf Step 12 : COPY . ./ ---> ff26e89ee2d7
Now Docker is reusing the cache for all but the last layer where the source code is copied.
Because we’re copying the entire source directory into the image, any file change will invalidate the cache, even the change of a log file. We can easily remove certain files and directories from the build context by adding a
.dockerignore file which lists all the items we want to exclude, e.g. a
Generally speaking, any file that isn’t required by your image should be added to
.dockerignore in order to increase build performance.