How to easily deploy a Drupal 8 instance on Kubernetes

Containerum
Containerum
Published in
5 min readDec 25, 2018

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.

Createdrupal-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
  • Database password: your_password, same as MYSQL_PASSWORD environment variable in the MySQL Deployment
  • Host: drupal-mysql-service, 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!

Containerum is your source of knowledge on Kubernetes and Docker.

--

--

Containerum
Containerum

Containerum Platform for managing applications in Kubernetes.