In my day job I have worked on many Drupal or Laravel sites that were set up in a Docker container, but I had never set it up myself. I was recently asked by my wonderful wife to help her with a new feature on her business’ website that would effectively require a CMS backend to be added to the static site so I decided to pick Drupal back up.
When I was searching online for how to do it a lot of the tutorials I came across told me how to use the Drupal image to install Drupal in the container but it was never persistent. Each time the container was brought down all the updates were lost. I finally found a resource that explained it to me here on YouTube, and decided to write it up for my own future reference.
Requirements
- Docker Desktop
- Terminal
Setting up docker-compose
Create a new directory for the project. Then create a .env
file to hold the database credentials & 2 directories to hold site code: drupal-data
& postgres-data
. The directory structure should now look like this:
- project_name
- drupal-data/
- postgres-data/
- .env
The .env
is a simple file that will hold the database credentials to keep them safe.
# .env
DB_NAME="database_name"
DB_USER="user"
DB_PASSWORD="password"
I also like to create a .env.example
file with the values the site requires in a .env
file but with the sensitive values all censored. That way any time the project is brought to a new system I can copy & paste the file for a quicker start, but this is optional for the Drupal setup.
# .env.example
DB_NAME="<DO_NOT_COMMIT_THIS_VALUE>"
DB_USER="<DO_NOT_COMMIT_THIS_VALUE>"
DB_PASSWORD="<DO_NOT_COMMIT_THIS_VALUE>"
Next, create a docker-compose.yml
file at the root of the directory. The docker-compose.yml
describes the containers that will be built and their contents. Fill out the file with the following code:
version: "3.8"
services:
drupal:
container_name: drupal
image: drupal:latest
ports:
- "8080:80"
volumes:
- ./drupal-data:/opt/drupal
depends_on:
- postgres
restart: always
postgres:
container_name: postgres
image: postgres
environment:
POSTGRES_DB: "${DB_NAME}"
POSTGRES_USER: "${DB_USER}"
POSTGRES_PASSWORD: "${DB_PASSWORD}"
volumes:
- ./postgres-data:/var/lib/postgresql/data
restart: always
In this file lies the secret to the code persistence I was looking for. In both containers under the volume
property I am mapping a local directory on my machine to a directory in the container. The patter is: ”local_machine:container
” so for the Drupal container I am mapping the drupal-data
directory I created to the /opt/drupal
directory in the container.
You can also see I have the Postgres database credentials being loaded in dynamically from the .env
file. This keeps the sensitive credentials out of the git repository and allows for different values on different systems.
Installing Drupal
Once the docker-compose.yml
file is set up, build/start the containers. Once the containers are running connect to the drupal
container and install Drupal using composer.
# Build the containers
docker-compose up -d
# Connect to the 'drupal' container
docker-compose exec drupal bash
# Install Drupal in the correct location
pwd # Should return '/opt/drupal'
composer create-project drupal/recommended-project .
When Drupal is installed in the /opt/drupal
directory in the container the drupal-data
directory will also start to fill with files (Persistence !).
It’s important to make sure that the vendor/
directory and .env
file are both added to the .gitignore
so they are excluded from Git. The core/
directory probably could be ignored as well because it can be downloaded again using Composer.
Next Steps
Now that Drupal is installed in a container with persistence the next step is setting up the site. Whether that’s creating content types, filling out page content, or developing custom modules with custom functionality the changes will now persist when the containers are brought down.
For me this means re-learning everything I had forgotten about Drupal themes and building out content types.