Deploying Drupal Sites with Docker Compose

Posted on: 2016-05-14 Last edited: 2016-05-14
Language:
  • English

Deploying a Drupal site (or any website) could be cumbersome, in particular if you have multiple websites running on one server. The amount of time wasted in configuring the server could be considerable.

Docker is one of the tools that can save us from the "configuration hell". Thanks to pre-built images, I no longer have to worry about dependencies since they can be all included in one image. Also, unlike virtual machine, Docker is fast and take only a few seconds to start. Another benefit is that now you can have the same environment on your local machine and on the server -- just use the same image.

Now I would like to quickly walk through the steps of using Docker Compose to deploy Drupal.

Step 0: Install Docker and Docker Compose

Follow the official documentation for Docker and Docker Compose.

Step 1: Create a image

I adapted this Dockerfile from Drupal's official Docker image.

FROM php:7-apache
RUN a2enmod rewrite

# install the PHP extensions we need (git for Composer, mysql-client for mysqldump)
RUN apt-get update && apt-get install -y libpng12-dev libjpeg-dev libpq-dev git mysql-client-5.5 wget \
	&& rm -rf /var/lib/apt/lists/* \
	&& docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \
	&& docker-php-ext-install gd mbstring opcache pdo pdo_mysql pdo_pgsql zip

# set recommended PHP.ini settings
# see https://secure.php.net/manual/en/opcache.installation.php
RUN { \
		echo 'opcache.memory_consumption=128'; \
		echo 'opcache.interned_strings_buffer=8'; \
		echo 'opcache.max_accelerated_files=4000'; \
		echo 'opcache.revalidate_freq=60'; \
		echo 'opcache.fast_shutdown=1'; \
		echo 'opcache.enable_cli=1'; \
	} > /usr/local/etc/php/conf.d/opcache-recommended.ini

WORKDIR /root

#Configure PHP memory limit
RUN {  \
		echo "memory_limit = 256M"; \
	} >> /usr/local/etc/php/php.ini

#Install Drush 8.1.2
RUN wget https://github.com/drush-ops/drush/releases/download/8.1.2/drush.phar && php drush.phar core-status && chmod +x drush.phar \
	&& mv drush.phar /usr/local/bin/drush

#Install Drupal Console
RUN curl http://drupalconsole.com/installer -L -o drupal.phar
RUN mv drupal.phar /usr/local/bin/drupal && chmod +x /usr/local/bin/drupal
RUN drupal init


WORKDIR /var/www/html

I added Drush and Drupal Console because these are handy for debugging and maintenance tasks.

After you created a Dockerfile, navigate to the folder containing it and execute:

docker build -t YOUR_IMAGE_NAME .

Replace YOUR_IMAGE_NAME with the name you want to use. If you want to push the image to Docker Hub, you may want to add your user name before it.

Step 2 Create a Docker Compose configuration file

The reason we use Docker Compose is that with Docker you still need to type a couple of commands, with a lot of arguments. This is not very elegant and is error-prone. Docker Compose solves this issue by allowing you to store arguments in a file and also manage several containers together.

A sample docker-compose.yml looks like:

version: '2'
services:
  drupal-web:
    image: YOUR_IMAGE_NAME:latest
    ports:
      - "8080:80"
    depends_on:
      - mysql-server
    links:
      - mysql-server:mysql
    volumes:
      - /home/user/webdev/drupal-test/htmlroot:/var/www/html
  mysql-server:
    image: mysql
    environment:
      MYSQL_DATABASE: drupal
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: drupal
      MYSQL_PASSWORD: drupal
    volumes:
      - /home/user/webdev/drupal-test/mysql:/var/lib/mysql

Notice that for both services we created "volumes". This is because Docker containers are ephemeral: the moment you destroy a container, all data will be gone. Volumes allow you to link some directories with containers with directories on the host system, so that they remain persistent. In our case, the htmlroot folder is where our Drupal code lives, and mysql folder contains the data files used by MySQL server.

Step 3: Getting Drupal Ready

Copy or move your Drupal folder to the "htmlroot" folder we just mentioned. (Note that we are not creating a "drupal" subfolder inside "htmlroot", otherwise your site cannot be accessed at / of your domain)

Modify settings.php to use the correct MySQL username, password, server URL and database name. In our case they are:

$databases['default']['default'] = array (
  'database' => 'drupal',
  'username' => 'drupal',
  'password' => 'drupal',
  'prefix' => '',
  'host' => 'mysql',
...

You can change them in docker-compose.yml.

Now, if you already have a existing site, we need to migrate the database to our container. In your old environment, export the entire database as a SQL file. (You can use Drush to do that.)

Copy the SQL file to "htmlroot", rename it as "import.sql".

In command line execute:

docker-compose up -d
docker-compose exec drupal-web bash

And you are now "inside" the Docker container. Now use Drush to import the database:

drush sql-query --db-url=mysql://drupal:[email protected]/drupal --file=import.sql

And don't forget to clear cache:

drush cr

Now you should be able to access your site at http://localhost:8080/. (To change the port, edit docker-compose.yml)

Summary

After reading this post, hopefully you will know how to switch from your existing web hosting environment (e.g. Apache / Nginx on your host system) to using Docker. In future post I will talk about how to easily deploy your Drupal site from your local machine to your server.