Update: we have fixed yaml files and updated the tutorial to make it easier to deploy Drupal. We will be deploying Drupal version 8.

Drupal is quite a popular CMS with a big community. It is especially popular among large enterprises and for complex websites. In fact, some of the most visited sites in the world like NBC, The Economist, Cisco, RedHat or Tesla use Drupal as their corporate website CMS.

In this article I will explain how to easily deploy a working instance of Drupal and MySQL on Kubernetes. You will notice that it will take you more time to read this tutorial than to deploy the instance. It’s the magic of Kubernetes!

Prerequisites

We will assume that you have an up and running Kubernetes cluster and that kubectl is already installed in your workstation with the right credentials to execute commands in your cluster. Additionally, we will assume that you have a deployed volume provisioner.

Preparing the data persistence infrastructure

Since Kubernetes containers are not data-persistent, it is necessary to use volumes in order to preserve the data. Otherwise, all the changes written to the database or to any directory will be lost after the container restarts.

In Kubernetes it is recommended to use the PersistentVolume object to retain the data. A PersistentVolume is a representation of persistent storage. It supports many underlying technologies and storage services: NFS, Cinder, Gluster, Ceph, AWS EBS, Google Persistent Disk,…

It is possible to create a PersistentVolume either statically or dynamically. In this article we chose a dynamically-created PersistentVolume since it is easier to manage.

The way to do that is to create a PersistentVolumeClaim. Create drupal-persistentvolumeclaim.yaml as follows:

---

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: drupal-pvc

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 5Gi ---

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: drupal-pvc-mysql

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 5Gi

In this case we request two volumes of 5GB each that will be provided automatically through a persistent volume. The first will be used for the website files, and the second one for the database.

Run the command:

kubectl apply -f drupal-persistentvolumeclaim.yaml

After a few seconds, check that your volumes have been provided. If everything is fine, you should see that the PersistentVolumes has been provisioned and the PersistentVolumeClaims have been bound to it.

kubectl get pvc

Deploying a MySQL instance

To deploy the MySQL instance we will use a Deployment and a Service. Note that we run MySQL from root. When you run it in production, use custom credentials. It is also a good practice to keep MySQL password in a secret, not in the yaml.

Create drupal-mysql.yaml (don’t forget to change the root_password) :

---

apiVersion: v1

kind: Service

metadata:

name: drupal-mysql-service

spec:

ports:

-

name: mysql

port: 3306

protocol: TCP

selector:

app: drupal-mysql ---

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

name: drupal-mysql

spec:

replicas: 1

template:

metadata:

labels:

app: drupal-mysql

spec:

containers:

-

env:

-

name: MYSQL_ROOT_PASSWORD

value: root_password

-

name: MYSQL_DATABASE

value: drupal-database

image: "mysql:5.7"

name: cont-drupal-mysql

ports:

-

containerPort: 3306

name: mysql

protocol: TCP

volumeMounts:

-

mountPath: /var/lib/mysql

name: vol-drupal

subPath: dbdata

volumes:

-

name: vol-drupal

persistentVolumeClaim:

claimName: drupal-pvc-mysql

Deploy MySQL with the following command:

kubectl apply -f drupal-mysql.yaml

Then check that the pod is running:

kubectl get pods

You may have to wait some time before the pod is up and running.

Deploying Drupal

The Deployment will be based on a container with a Drupal image from Docker Hub repository. In addition, we will also use a temporary container (InitContainer) whose mission will be to pre-populate the persistent storage with the data used by Drupal. Create drupal.yaml as follows:

---

apiVersion: v1

kind: Service

metadata:

name: drupal-service

spec:

ports:

-

name: http

port: 80

protocol: TCP

selector:

app: drupal

type: LoadBalancer

---

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

labels:

app: drupal

name: drupal

spec:

replicas: 1

template:

metadata:

labels:

app: drupal

spec:

initContainers:

-

name: init-sites-volume

image: drupal:8.6

command: ['/bin/bash', '-c']

args: ['cp -r /var/www/html/sites/ /data/; chown www-data:www-data /data/ -R']

volumeMounts:

- mountPath: /data

name: vol-drupal

containers:

-

image: drupal:8.6

name: drupal

ports:

-

containerPort: 80

volumeMounts:

- mountPath: /var/www/html/modules

name: vol-drupal

subPath: modules

- mountPath: /var/www/html/profiles

name: vol-drupal

subPath: profiles

- mountPath: /var/www/html/sites

name: vol-drupal

subPath: sites

- mountPath: /var/www/html/themes

name: vol-drupal

subPath: themes

volumes:

-

name: vol-drupal

persistentVolumeClaim:

claimName: drupal-pvc

Notice that this time the Service type has been set to LoadBalancer. The reason is that it is this service that will be exposed to the external world. The statement indicates to the cloud provider that it should provision a load balancer with an external IP address and assign it to this service.

Let’s deploy it:

kubectl apply -f drupal.yaml

Wait 2 minutes and then run the command below to get the IP address Kubernetes has assigned to your service:

kubectl get svc

In this case we got the IP address 35.195.253.65 and port 31321.

Installing Drupal

Now that the infrastructure has been deployed, let’s install Drupal. You have just to navigate to the IP address and port you got in the previous step OR if you do not use cloud provider’s load balancer and have an external IP for your machine, navigate to external_IP:port.

Follow the installation instructions from the wizard. Use the database credentials you configured earlier in the MySQL deployment.

For example, in our case, here is the data that should be specified on the Database configuration screen:

Database name: drupal-database , same as MYSQL_DATABASE environment variable in the MySQL Deployment

, same as MYSQL_DATABASE environment variable in the MySQL Deployment Database password: your_password, same as MYSQL_PASSWORD environment variable in the MySQL Deployment

Host: drupal-mysql-service , same as the MySQL Service name

, same as the MySQL Service name Port: 3306 , same as the MySQL Service port

And that’s it! You have a working Drupal instance now, deployed in less than 10 minutes. Congratulations!

Feel free to ask any questions, I’ll be glad to help! Don’t forget to follow us on Twitter and join our Telegram chat to stay tuned!

You might also want to check our Containerum project on GitHub. We need you feedback to make it stronger — you can submit an issue, or just support the project by giving it a ⭐. Your support really matters to us!