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:
1 | RUN curl -sS https://getcomposer.org/installer | \ |
The first instruction is to install Composer. Then we change the working directory to /app
which is created if it doesn’t already exist.
The 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:
1 | RUN curl -sS https://getcomposer.org/installer | \ |
Instead of copying all the source files we only copy composer.json
and 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 --no-scripts
and --no-autoloader
flags.
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:
1 | Step 9 : COPY composer.json ./ |
Now Docker is reusing the cache for all but the last layer where the source code is copied.
Create a .dockerignore file
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 log/
directory.
Generally speaking, any file that isn’t required by your image should be added to .dockerignore
in order to increase build performance.