Chris Mitchell Online

Chris blogging about cloud, IT, and programming. What could go wrong?

Local Drupal Docker

2019-07-20

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.

Prerequisits

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:

FROM drupal:8.7.5-apache

Now that we have our base Drupal core in an extendable image, next we are going to install Composer.

Installing 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.

Installing Drush

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.

Installing XDEBUG

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

Lets Build

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.

Closing Thoughts

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.

comments powered by Disqus