Docker for Legacy Drupal Development
Tags: tutorial, drupal, docker
Published: 2020-02-19 03:44:10

---
title: Docker for Legacy Drupal Development
published: true
date: 2018-10-14 02:14:03 UTC
tags: tutorial,drupal,docker
canonical_url: https://medium.com/@jonesrussell42/docker-for-legacy-drupal-development-6df4dec8b309
---

#### Leveraging Linux containers for Migrating Drupal 6 to Drupal 8

Ahnee. Let me start by saying this article/tutorial (artorial, tutarticle!?), this _artorial_ could be titled “ **Docker for Development** , _Leveraging Linux containers_” and be applied to virtually any stack you want.

![](https://cdn-images-1.medium.com/max/1024/1*s-YgL1NW7evYyCBWI-7w8Q.png)

I’m using Drupal because I recently began a Drupal 6 (D6) to Drupal 8 (D8) website migration.

> Drupal is a free, open-source content management system (CMS) with a large, supportive community. It’s used by millions of people and organizations around the globe to build and maintain their websites.

Both versions run on a LAMP stack but with different versions of PHP. D6 reached it’s end-of-life in early 2016, almost a year before PHP 7 was released. Consequently it requires PHP 5.6 and lower to run.

_The folks at_ [_myDropWizard.com_](https://www.mydropwizard.com/blog/drupal-6-year-2020-and-php-7-support) _are bravely supporting D6 until the cows come home, props to them! I have no affiliation with them, I’m just thunderstruck by their_ [_level of commitment_](https://www.mydropwizard.com/blog/drupal-6-2019-yes-really)_._

According to the docs D8 will run on PHP 5.5.9+, but any version less than 7.1 is [not recommended](https://www.drupal.org/docs/8/system-requirements/php-requirements#php_required). **If running Drupal 8 on PHP 5.6 you go, only pain will you find**.

So how do you run PHP 5 and PHP 7 simultaneously on the same host? Spin up a pair of VMs? [Slip in Nginx and PHP-FPM alongside Apache](https://www.tecmint.com/install-different-php-versions-in-ubuntu/)? The former option is acceptable. The latter borders on sadomasochism.

![](https://cdn-images-1.medium.com/max/244/1*4jh-4MnN2NkYxWZVOKBklw.jpeg)<figcaption>And there is, Kevin!</figcaption>

The answer is, of course, Docker.

### This Guy’s Setup

I use Linux as my primary Operating System (OS). Ubuntu 18.04 loaded with the latest packages of Apache 2.4, MySQL 5.7, and PHP 7.2 from Ubuntu’s official repositories.

#### Drupal 8

My Ubuntu host is similar enough to the production environment where D8 is to be deployed that I created an Apache Virtual Host (vhost) and MySQL database then [downloaded D8 using a composer template](https://www.drupal.org/docs/develop/using-composer/using-composer-to-manage-drupal-site-dependencies#download-core-option-a) and installed it with [Drupal Console](https://docs.drupalconsole.com/en/commands/site-install.html).

> What is the Drupal Console? The Drupal CLI. A tool to generate boilerplate code, interact with and debug Drupal. From the ground up, it has been built to utilize the same modern PHP practices which were introduced in Drupal 8.

#### Drupal 6

This is where the fun begins. But first I’ll explain the differences between a VM and a Container.

### VMs and Containers Compared

#### VM

There are many VM providers. [VirtualBox](https://www.virtualbox.org/), [QEMU](https://www.qemu.org/), and [VMWare](https://www.vmware.com/) to name a few. A VM contains a full OS and [kernel](https://en.wikipedia.org/wiki/Kernel_(operating_system)) running in isolation (so lonely) from the host. It is indistinguishable from a proper desktop or server.

Before booting, VMs are allocated resources such as RAM and CPU cores. The VM provides a hardware emulation layer between the guest OS and the host, which looks and feels like bare metal as far as the guest OS is concerned.

Because they resemble physical desktops and servers, VMs require significant amounts of the host’s system resources. In contrast to Containers this severely limits the amount of VMs that can run concurrently on a single host. The boot-up and shutdown time is also the same as a physical machine; another significant difference.

#### Containers

Containers offer the advantages of VMs without the overhead. By virtualizing at the kernel level containers share resources with the host. Many more containers can run simultaneously on a single machine compared to VMs.

Containers worry more about resource prioritization rather than resource allocation. In other words, a container says “When will you run this process for me niijikiwenh?” rather than “How much CPU do I have to run this process?”.

Finally, starting up or shutting down a Container is super fast _\*whoooooosh\*_. Because Containers share a fully loaded kernel with the host, they can be started, perform a task, then shut down within milliseconds. Containers are the mayflies of the tech world. On the flip side, they can last until an act of God brings them down along with your house.

#### Docker

I messed with Docker years ago but only recently gave it a prime time slot in my regularly scheduled programming.

Docker makes it easier to create, deploy, and run an application in a lightweight and portable Container by packaging it up with it’s dependencies and shipping them out as an image.

I’ve only skimmed the surface of Docker and don’t fully understand how it works under the hood. I’m also anxious to check out a competitor such as [Canonical’s LXD](http://www.ubuntu.org.cn/cloud/lxd) or [CoreOS/Redhat’s Rkt](https://coreos.com/rkt/). All in good time.

#### Docker Images

Docker loads an image containing an OS and the software needed to do a job into a container. In other words, an image contains your applications runtime environment.

Creating an image is rather painless, depending on the complexity of your requirements. You write a set of instructions in YAML saved as a Dockerfile, then run docker build. Our tutorial requirements are simple and can be met with pre-existing images pulled from [Docker Hub](https://hub.docker.com/), a Docker image registry service.

While I can find an image which contains Apache, PHP, and MySQL all together, we’re going to follow [best practices](https://devops.stackexchange.com/questions/447/why-it-is-recommended-to-run-only-one-process-in-a-container) and separate the web server from the database into 2 containers where they will communicate through an internal subnet created by Docker.

#### Persisting Data

Finally, containers are designed to be disposable, with the ability to run as a single instance on a single host, or to be scaled as multiple instances distributed over server clusters. By default, data is written to a containers writable layer and will be disposed of along with the container.

Volumes and Bind Mounts are Dockers two options for persisting data. I can, and maybe will, write an entire post to fully explain them. But to keep it brief I will say Volumes are managed by Docker, isolated from the host, can be mounted into multiple containers, and stored on remote hosts or in a cloud provider.

Bind Mounts are a file or directory on the host machine mounted into a container. They are a good option to share configuration data, source code, and build artifacts during development. In production, your build artifacts are best copied directly into the image, configuration in the environment, and source code unnecessary.

![](https://cdn-images-1.medium.com/max/740/1*W49kEOLhKZTuC9DmRKD6Qg.png)

Volumes are recommended for storing data used and generated by containers. Bind mounts depend on the host machine’s directory structure, hampering container portability.

In this tutorial we will get by with a bind mount.

### Summary

That’s Docker so far as I understand it. I hope you find it beneficial and are encouraged to begin developing with Docker. I invite you to join in on the fun below and follow the step-by-step instructions to get down and dirty with Docker.

### Tutorial

Let’s setup Drupal 6 within containers in Ubuntu. If you are not using Ubuntu don’t fret, the only step you need to change is “Install Docker”. In that case refer to [https://docs.docker.com/install/#supported-platforms](https://docs.docker.com/install/#supported-platforms) for instructions to install Docker on your OS.

If you catch any mistakes or see room for improvement please contact me. Otherwise, wacka wacka.

#### Prerequisites

sudo (or root) — Required to install and run Docker. To run docker commands without sudo or root you must add your user account to the _docker_ group.

#### Table of Contents

1. Install Docker
2. Add user to docker group
3. Start Docker
4. Pull MySQL image
5. Start container
6. Download Drupal 6
7. Pull Apache/PHP image
8. Enable mod\_rewrite
9. Allow Overrides
10. Start container with a bind mount
11. Install Drupal
12. Cleanup

Biminizha’.

#### Install Docker

Open a terminal and ensure your package lists are up to date then install Docker (aka Docker Engine):

```
$ sudo apt update
$ sudo apt install docker.io -y
```

_Output:_

```
\<heaps of output\>
Processing triggers for systemd (237-3ubuntu10.3) ...
```

Docker Engine is comprised of three major components:

- _dockerd_ (Server) — a daemon that is a long-running background process
- _docker_ (Client) — a command line interface
- REST API — specifies interfaces that programs can use to communicate with the daemon

#### Start Docker

Kick-start the aforementioned long-running background process:

```
$ sudo systemctl start docker
```

Optionally, tell _systemd_ to start docker on system boot:

```
$ sudo systemctl enable docker
```

Docker is now installed and ready for use. Check if docker is running:

```
$ systemctl is-active docker
```

_Output:_

```
active
```

#### Pull MySQL image

Now that you have docker running you can pull your first image. Start with [MySQL](https://hub.docker.com/r/mysql/mysql-server/) version 5.6 (without _:5.6_ specified, :_latest_ is implied):

```
$ sudo docker pull mysql:5.6
```

_Output:_

```
5.6: Pulling from library/mysql
802b00ed6f79: Pull complete 
30f19a05b898: Pull complete 
3e43303be5e9: Pull complete 
94b281824ae2: Pull complete 
51eb397095b1: Pull complete 
3f6fe5e46bae: Pull complete 
b5a334ca6427: Pull complete 
115764d35d7a: Pull complete 
719bba2efabc: Pull complete 
284e66788ee1: Pull complete 
0f085ade122c: Pull complete 
Digest: sha256:4c44f46efaff3ebe7cdc7b35a616c77aa003dc5de4b26c80d0ccae1f9db4a372
Status: Downloaded newer image for mysql:5.6
```

### Start MySQL

Start the DB container, options are explained below:

```
$ sudo docker run -d \
--name="drupal-mysql" \
-e MYSQL\_ROOT\_PASSWORD=drupalroot \
-e MYSQL\_DATABASE=drupal6 \
-e MYSQL\_USER=drupal \
-e MYSQL\_PASSWORD=drupal6pass \
mysql:5.6
```

- -d — Start the container as a background process.
- --name —Will be referenced during Drupal install. A random name will be assigned if one isn’t provided.
- -e — Set’s an environment variable. MySQL will be configured with [values passed in](https://hub.docker.com/_/mysql/) by the environment.

_Output (will differ):_

```
de99c912e3fbeb4f113889c145b5fab82787259c21d51962c9186e90c27d2857
```

#### Download Drupal 6

D6 is available for download from the official Drupal site packaged as a gzipped tarball. You can grab it with wget:

```
$ cd ~
$ wget [https://ftp.drupal.org/files/projects/drupal-6.38.tar.gz](https://ftp.drupal.org/files/projects/drupal-6.38.tar.gz)
$ tar -xzf drupal-6.38.tar.gz
```

Verify drupal-6.38 exists in your home directory:

```
$ if test -d ~/drupal-6.38; then echo “It exists”; fi
```

_Output:_

```
It exists
```

#### Pull Apache/PHP image

Now pull a docker image of Ubuntu 14.04 LTS with Apache 2, PHP 5, and Composer from [https://hub.docker.com/r/nimmis/apache-php5/:](https://hub.docker.com/r/nimmis/apache-php5/:)

```
$ sudo docker pull nimmis/apache-php5
```

_Output:_

```
Using default tag: latest
latest: Pulling from nimmis/apache-php5
c2c80a08aa8c: Pull complete 
6ace04d7a4a2: Pull complete 
f03114bcfb25: Pull complete 
99df43987812: Pull complete 
9c646cd4d155: Pull complete 
5c017123b62e: Pull complete 
8f95d9abec41: Pull complete 
c46de42c66c3: Pull complete 
9a19620cecad: Pull complete 
5c62abdf642f: Pull complete 
Digest: sha256:712d35d5cc30e6a911e260e871f08f77d5684edcc50cba21163535714c547ff5
Status: Downloaded newer image for nimmis/apache-php5:latest
```

#### DocumentRoot and Incoming Port

The containerized Apache’s default DocumentRoot is /var/www/html, which we will bind mount to the D6 files in ~/drupal-6.38.

Because I already have Apache on the host I have to bind the container’s port 80 to something else. I’m using 10080 but you can choose almost any other free port.

```
$ sudo docker run -d \
-p 10080:80 \
-v ~/drupal-6.38:/var/www/html \
--name="drupal-app" \
--link="drupal-mysql" \
nimmis/apache-php5
```

_Output:_

```
0398890ab8e0a082f68373c8e7fd088e925f9bac0eca178399b883091919ee77
```

An explanation of what’s between run and nimmis/apache-php5:

- -d — Daemonize, run in background.
- -p 10080:80 — Bind host port 10080 to container port 80.
- -v ~/drupal-6.38:/var/www/html — Bind host directory to container directory.
- — name="drupal-app" — Name the container instance for convenience.
- --link="drupal-mysql" — Link to the MySQL container so Drupal can communicate with the database.

#### Install Drupal

Open [http://localhost:10080](http://localhost:10080) in a browser (_xdg-open is a program that will open a file or URL in the preferred application as set in your OS_):

```
$ xdg-open [http://localhost:10080](http://localhost:10080)
```

Tada! The Drupal 6 installation page should be open in a browser, served from within a set of Docker containers.

To complete the installation use the database name (_drupal6_), username (_drupal_), and password (_drupal6pass_) as set in the _Start MySQL_ step. Under _Advanced Options_, set the _Database host_ to the name of your MySQL container, _drupal-mysql_.

### Cleanup

When you have finished with Drupal 6 shut down the containers and delete them from the host.

Stop the containers:

```
$ sudo docker container stop drupal-app drupal-mysql
```

_Output:_

```
drupal-app
drupal-mysql
```

Remove the containers:

```
$ sudo docker container rm drupal-app drupal-mysql
```

_Output:_

```
drupal-app
drupal-mysql
```

Verify the containers have been deleted:

```
$ sudo docker container ls
```

That’s it, move along. Baamaapii.

### Bonus: _docker_ group

To display a list of groups you belong to is simple:

```
$ group
```

_Output:_

```
roosta adm cdrom sudo dip plugdev lpadmin sambashare
```

Add your user account to the _docker_ group:

```
$ sudo usermod -aG docker $USER
```

You must log out then log back in before it takes effect.