Series Pt. V — Optimizing Composer and Drush Docker images
In today’s story I narrate how I cut the size of my Docker Container for Drush from 224MB to 66MB.
Today it’s turn to shed some weight on my Compose and Drush images. These are their current sizes:

That’s simply unacceptable! Sounds like I have a lot of bloatware inside there.
Let’s fix that up real quick:
Technically if you employ the verb version of Marie Kondo on something you’re supposed to say “thank you” and get rid of it, so … I’m not sure it will 100% apply here — but I’ve moved all dependencies not strictly required to run Composer and Drush out of the core images and into additional, new, optional build targets.
A quick build later and here’s the result:

The php7-cli.core
image houses Composer and is built from the php7-fpm.dev
image. Now instead of going from 31.4MB
on the PHP FPM image to a whopping 143MB
just for the Composer image, the Composer image measures a paltry 49.9MB
. The Composer image adds php7-phar
(required for Composer), bash, git, and curl.
Of all the added Alpine dependencies to the Composer image, the Alpine git package is the heaviest, coming in at 13.91MB
installed size for the x86_64
architecture. The rest (bash, curl, phar) are almost negligible in terms of size. The rest of the size increase is due to Composer itself, which is the file downloaded from getcomposer.org/installer.
As for the Drush image itself, it adds 74.1MB
. The installed size of the openssh-client
Alpine package is only 3.34MB
, so almost 70 megabytes are being added by Drush, defined by the followingcomposer.json
:
Sadly, the Composer install command --no-dev
and -a
flags to the Composer install made no difference in image build size.
There were however, some concerning warnings showing up in the console about autoload interoperability in Drush:
Some of the Drush classes Composer is flagging for deprecation are:
Drush\Internal\Config\Yaml\Tag\TaggedValue
Drush\Internal\Config\Yaml\Escape
Class Drush\Internal\Config\Yaml\Parse
Class Drush\Internal\Config\Yaml\Yaml
The -a
flag in Composer enhances performance because it tells the autoloader to not scan for new classes and is useful in a production, but not dev environment.
Disable Composer Cache For Docker Builds
Adding the Composer global flag --no-cache
prevents Composer from writing to a cache directory. In my case enable the--no-cache
option results in an almost 50% percent size reduction while building my Drush container — from 124MB
megabytes to 66.1MB
.
Here’s the Composer command with the cache disabled:
# Inside Drush image build target.RUN composer global -vvv \
--no-cache \
install \
--no-dev
And here’s the end result:

You can see the previous image builds right below the .drush9
image for contrast.
This results now in the Drush image adding only 66.1— 49.9=16.2MB
megabytes on top of the Composer image. Consider me a happy person already!
I could add other options, such as --no-autoloader
to skimp on size, but to say that would be detrimental to Drush’s performance is probably an understatement, and not a small one at that.
Now the --optimize-autoloader
is not geared specifically towards saving or increasing space, but rather for increasing performance by generating static lookup files (class maps) for classes as opposed to relying on finding PHP classes dynamically at run-time, however while it is advised for use in production it is also advised that it increases build time. The impact on size is indeterminate in the documentation, but technical discovery is the whole purpose of writing these stories:
# Inside Drush image build target.RUN composer global -vvv \
--no-cache \
install \
--no-dev \
# added this option
--optimize-autoloader

Adding the optimize autoloader option yielded a .4MB
megabyte increase to the build, most likely in the now newly generated class map files. My container is meant for development, but I do not expect to be changing any files in the Drush distribution itself, so I’m leaving this flag enabled in the Drush image build. I did not note any significant difference in build time after adding the flag for optimizing the autoloader.
And here’s a test to check that Drush is still working after modifying the install options with drush --version
:

And by clearing my currently installed Drupal site cache:

And that’s it!
I’ve completely achieved my goal of significantly reducing the size of my Composer and Drush containers. I did so by:
- Removing a lot of unused or unnecessary Alpine Linux dependencies to a separate build target. I could have as well deleted them or commented out from the build file.
- Policing what I write into
composer.json
to make sure it’s the bare minimum. - Adding the global Composer flag
--no-cache
to thecomposer install
command inside myDockerfile
when installing any Composer dependencies such as Drush.
If you’re starting with Docker, found this useful, and want to know more about building containers by hand (instead of just downloading and using other people’s work), be sure to follow. If there is anything you want me to write about, please do let me know in the comments!
Until next time.