THIS ARTICLE IS OUTDATED: please see new article “New deployment method — CI/CD via third-party CI”

In this article I will demonstrate how to organize CI workflow for your Drupal 8 website with Docker. We will use Jenkins as our CI/CD tool and docker4drupal containers for test environment.

This article will consist of two parts. In the first part we will install Jenkins and set up our build. During the build we will spin up testing environment with docker4drupal containers and run a few test suites (both unit and functional) from Drupal core.

In the second part, we will prepare the deployment tarball (archive with the code) and upload it to AWS S3. Then we deploy a new docker-based environment for Drupal and deliver there our tarball.

Installation and configuration

First let’s install Jenkins. I will install it on a AWS EC2 node with Debian 8.

Install Jenkins



sudo sh -c ‘echo deb

sudo apt-get update

sudo apt-get upgrade

sudo apt-get install sudo curl git jenkins wget -q -O — https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -sudo sh -c ‘echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list’sudo apt-get updatesudo apt-get upgradesudo apt-get install sudo curl git jenkins

2. Generate SSH key for Jenkins user

sudo -H -u jenkins ssh-keygen -t rsa -b 4096

sudo -H -u jenkins cat ~/.ssh/id_rsa.pub

3. Allow sudo for jenkins

echo ‘jenkins ALL= NOPASSWD: ALL’ > /etc/sudoers.d/jenkins

4. Install Docker engine



echo “deb

apt-get update

apt-get install docker-engine apt-key adv — keyserver hkp://p80.pool.sks-keyservers.net:80 — recv-keys 58118E89F3A912897C070ADBF76221572C52609Decho “deb https://apt.dockerproject.org/repo debian-jessie main” > /etc/apt/sources.list.d/docker.listapt-get updateapt-get install docker-engine

5. Allow jenkins deal with Docker.

adduser jenkins docker

6. Install Docker Compose.



pip install docker-compose curl -sS https://bootstrap.pypa.io/get-pip.py | pythonpip install docker-compose

7. Install AWS Cli (we will use AWS S3 for delivery)

pip install awscli

8. Restart Jenkins service

service jenkins restart

9. Get your jenkins admin password here

cat /var/lib/jenkins/secrets/initialAdminPassword

10. Open your Jenkins installation (localhost:8080). Install suggested plugins:

11. Install additional plugins “Environment Injector Plugin” and “AnsiColor”

Continuous Integration

We need to grant Jenkins access to our git repository. We generated an SSH key before, so we just select the appropriate option

2. Now add this SSH key to your Git repository. You can find it here.

cat /var/lib/jenkins/.ssh/id_rsa.pub

3. Create a new Freestyle Project (job) in Jenkins and add your git repository

4. Add the following docker-compose.yml file to your repository, it’s a simplified version of docker4drupal:

version: "2"



services:

mariadb:

image: wodby/drupal-mariadb

environment:

MYSQL_RANDOM_ROOT_PASSWORD: 1

MYSQL_DATABASE: drupal

MYSQL_USER: drupal

MYSQL_PASSWORD: drupal



nginx:

image: wodby/drupal-nginx

environment:

NGINX_UPSTREAM_NAME: php

DRUPAL_VERSION: 8

volumes_from:

- php



php:

image: wodby/drupal-php:7.0

depends_on:

- mariadb

environment:

SIMPLETEST_BASE_URL: http://nginx

SIMPLETEST_DB: mysql://drupal:drupal@mariadb/drupal

volumes:

- ./:/var/www/html

docker-compose.yml file defines a set of services/containers for our test environment. Besides PHP we need MariaDB and Nginx containers because we will run functional tests and they require a database and a web server. For the same reason we add two variables for Simpletest in PHP container.

As you can see we don’t expose any public ports and have no volume for the database. We don’t need it because our environment will be used only for tests during the build.

Build Setup

Add the following files to our repository which will be used for our build.

build.sh:

#!/bin/bash



set -eo pipefail



# Install merge plugin.

docker run --rm \

-v "$HOME/.composer":/composer \

-v "$PWD":/app \

composer/composer:alpine update -n



# Install all requirements.

docker run --rm \

-v "$HOME/.composer":/composer \

-v "$PWD":/app \

composer/composer:alpine update -n

This script will run a docker containers with composer to fetch Drupal’s dependencies.

tests.sh

#!/bin/bash



sudo chown -R 82:82 .



docker-compose up -d mariadb

docker-compose up -d nginx



docker-compose run --user 82 php vendor/bin/phpunit -c core core/tests/Drupal/Tests/Core/Password/PasswordHashingTest.php

docker-compose run --user 82 php vendor/bin/phpunit -c core core/tests/Drupal/KernelTests/Component/Utility/SafeMarkupKernelTest.php

docker-compose run --user 82 php vendor/bin/phpunit -c core core/tests/Drupal/FunctionalTests/Breadcrumb/Breadcrumb404Test.php



sudo chown -R jenkins:jenkins .



docker-compose down --remove-orphans

First, we change ownership to user 82, it’s a www-data user id inside of the php/nginx containers. Then we spin up mariadb and nginx services defined in our docker-compose.yml file. And finally we launch 4 test suites (unit and functional) from Drupal’s core.

Now we just need to add build steps that will execute these scripts.

Running the Build

We now have everything we need. Let’s run the build. We’ll see the following output:

As you can all tests are passed. This means we can now go the second part where we deliver our build.

Part 2: Continuous Delivery