In this article I’m going to show how I setup a local Docker container running Drupal core to work on modules and other Drupal development tasks. By extending the prebuilt Docker Hub Drupal we can start with a clean Drupal core, then extend to install Composer and Drush, install XDEBUG, and finally launch our container using Docker Compose.
I’ll assume you have Docker installed are comfortable with creating new images with Dockerfiles and can launch images with Docker Compose.
Extending the Drupal Image
First, download the official Drupal container from Docker Hub. I’m going to use the latest version of Drupal with the 8.7.5-apache tag to keep my version of Drupal consistant and to get the Apache version:
docker pull drupal:8.7.5-apache
This will be our starting point image as the Drupal team has done a good job keeping these images up to date on Docker Hub. Next we’ll build our Dockerfile to add more goodies to this image.
Create a new Dockerfile and use our new Drupal image drupal:8.7.5-apache in the FROM instruction:
Now that we have our base Drupal core in an extendable image, next we are going to install Composer.
The process for installing Composer is fairly straightforward, you use PHP to download a .php script to create a .phar file, and then copy to your system path. To simplify the install process I’ve included the instructions in a composer.sh file that can be copied and run during Docker image build time, just ensure the composer.sh file is in the same directory as the Dockerfile. The .sh file looks like this:
#!/bin/sh php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php composer-setup.php --quiet RESULT=$? rm composer-setup.php mv composer.phar /usr/local/bin/composer exit $RESULT
And then add the following to your Dockerfile to include and run this file during build time, so our full Dockerfile looks like this:
FROM drupal:8.7.5-apache #### Install Composer #### COPY composer_install.sh /tmp RUN chmod +777 /tmp/composer_install.sh RUN /tmp/composer_install.sh RUN rm /tmp/composer_install.sh ### End Composer install ###
At this point if we were to build our Docker image we would have Drupal core ready to be installed and Composer available to install packages and modules. Next lets get Drush installed.
The image from Docker Hub does not include Drush, but we can use our new Composer capabilities to install it, and then put it on the path.
A quick pre-requisite for installing Drush (or any package using Composer) we’ll need to install GIT. Add this line to the Dockerfile:
RUN apt-get update && apt-get install git
And to now install Drush, add the following lines to the Dockerfile:
RUN cd /var/www/html/ && composer require drush/drush
Then put Drush on the path:
RUN cd /usr/sbin/ && ln -s /var/www/html/vendor/drush/drush/drush drush
Now Drush will be available on the command line.
As it turns out having XDEBUG installed to step through PHP code, including Drupal and modules is very handy. We can include the instructions to have XDEBUG installed for us in our Dockerfile. Add the following to the end of our working Dockerfile:
#install XDEBUG RUN pecl install xdebug RUN touch /usr/local/etc/php/conf.d/debugging.ini RUN echo 'zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so' >> /usr/local/etc/php/conf.d/debugging.ini
Disabling Op Cache
While Opcache can be extremely useful when running PHP in production, this caching feature can make writing and debugging PHP confusing. If you are not familiar with Opcache, this is a feature introduced in PHP 5.5 that loads your scripts into memory and executes them from there, eliminating the need for PHP to process your scripts on every page load. Essentially what this means in the debugging world is if you change a file and refresh the page too fast, you won’t see the change. It can get annoying! To disable Opcache, we disable it with a flag in our configuration INI files.
Add the following to your Dockerfile:
RUN echo 'opcache.enable=0' >> /usr/local/etc/php/conf.d/debugging.ini
Our full Dockerfile will contain the following at this point:
FROM drupal:8.7.5-apache #### Install Composer #### COPY composer_install.sh /tmp RUN chmod +777 /tmp/composer_install.sh RUN /tmp/composer_install.sh RUN rm /tmp/composer_install.sh ### End Composer install ### #Install GIT RUN apt-get update && apt-get install git -y #Install Drush RUN cd /var/www/html/ && composer require drush/drush #Add Drush to path RUN cd /usr/sbin/ && ln -s /var/www/html/vendor/drush/drush/drush drush #install XDEBUG RUN pecl install xdebug RUN touch /usr/local/etc/php/conf.d/debugging.ini RUN echo 'zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so' >> /usr/local/etc/php/conf.d/debugging.ini #disable opcache RUN echo 'opcache.enable=0' >> /usr/local/etc/php/conf.d/debugging.ini
Our Dockerfile is now complete! Lets run it and build our Docker image with the following (I call my image drupal-docker-dev:001)
docker build . -t drupal-docker-dev:001
Launching a Docker Image
I can now launch as many of these images as containers that I want. Go ahead, break Drupal! I’ll use __docker-compose– with a .yml file to configure how I launch these containers. I want to be able to launch a Drupal container, launch a MySQL container, and map the Drupal modules folder to my local machine for easy code access.
Note: Mysql:latest Docker images looks to run version 8, which does not play well with Drupal intalls out of the box. Notice my docker-compose.yml file is using image:mysql:5.7
Here is my docker-compose.yml file:
version: '2.1' services: drupal_dev_db: image: mysql:5.7 container_name: "drupal_dev_db" environment: MYSQL_ROOT_PASSWORD: drupal drupal_dev_: image: drupal-docker-dev:001 container_name: "drupal_dev" ports: - 8099:80 volumes: - /drupal_dev/modules:/var/www/html/modules links: - drupal_dev_db
To launch my containers in a permanent state as background processes I run the following command:
docker-compose up -d
Now I can access my Drupal site at localhost:8099 in the browser where I can run through a quick install of Drupal.
Using the database connection info from my docker-compose.yml file I can install Drupal with the following parameters (root password is drupal):
And now I’m up and running with a local Drupal container ready to install modules using Composer, and execute any Drush commands. To access your container run the following command:
docker exec -it drupal_dev bash
and run your Composer / Drush commands from there. If you need to work on modules, check the volumes section of the docker-compose.yml file to see where the modules are mounted to your local computer, and you can use that source in your editor.
Another alternative to building a development Docker image would be to use composer to build Drupal instead of downloading the image from Docker Hub. This alternative method would include extending a Docker image from a lower OS level such as Ubuntu, installing Composer, and running the following command:
composer create-project drupal-composer/drupal-project:8.x-dev some-dir --no-interaction
I believe this might be the more recommended way of doing local dev as Drush comes pre-installed, indicating ready for development.
I would be curious to hear from the community, please drop me a line in the comments section below or email me.