The DrupalStand project is an opinionated local development environment built around the concept of simplicity, transparency, expandability, and an exceptionally low barrier to entry. Built on docker, the DrupalStand project should function identically on all* host systems capable of running docker images.
Cloning this repository will give you a stock Drupal development site running in docker containers. GNU Make commands assist in setup, management, and cleanup. Additional commands can be easily added into the system to satisfy independent project needs.
Files are synced locally allowing you to do local development work using the tools and functionality you and your developers are most comfortable with. A single codebase houses all of the code needed to replicate an entire Drupal environment identically on multiple machines with no configuration needed.
While focused on development tasks, the project also offers some production deployment tools to ease the transition of a local codebase into a production ready deployment. These tools prepare specially formulated containers with production in mind and export them into standalone images that can be deployed into orchestration environments or spun up as standalone servers.
- MacOS, Linux, or Windows
- Docker (https://www.docker.com/)
On systems that don't ship with docker-compose (Linux), it should also be installed.
- GNU Make (https://www.gnu.org/software/make/)
Windows support can be achieved with WSL or WSL2 natively in this repository. We recommend WSL2 due to the excellent speed and support using
make
commands to manage Docker natively.
- Python3
Docker for Windows (https://www.docker.com/products/overview) will detect and use WSL2. Hypervisor is required for WSL while it is not for WSL2. For now, Windows 10 version 2004 and above are the only versions that have WSL2 available. Updates for Windows are being rolled out over the coming months, but to get it now, run the Update Assistant (see https://support.microsoft.com/en-us/help/3159635/windows-10-update-assistant)
For native-like speeds, add your code to a folder under the WSL2 OS you have set up. You may experience significant slowdown if you do not set up your project this way due to the fact that filesystem mounts in WSL2 are implemented as NFS. (see microsoft/WSL#4197 (comment))
- Install WSL (https://docs.microsoft.com/en-us/windows/wsl/install-win10)
- Run Docker for Windows (https://docs.docker.com/docker-for-windows/install/)
- Get the Linux distro you want (Debian in my case) from Windows Store.
- If using WSL1,
- Use
docker-compose
for now to start and stop the project. You may need to read through the Makefile to find out what all is needed to run in order for the project to work correctly.
- Use
- If using WSL2,
- Clone the repo from within WSL (e.g. Debian) but do NOT use the
/mnt/
folders. (microsoft/WSL#4197) - Configure your IDE as normal, but open the source under your
\\wsl$\
directory within Windows.
- Clone the repo from within WSL (e.g. Debian) but do NOT use the
- Run the native
make
commands per normal in the following section of this document.
Do you have PHPStorm support?
PHPStorm will work fine out of box with xdebug and detect paths automatically, but in order to get PHP interpretation (and thus error detection), PHPStorm has support for Docker containers.
To enable it, open this project and then hit File > Settings > Languages & Frameworks > PHP
. Under this dialog, add a "CLI Interpreter" (...
button, then +
button on the next dialog) - Docker will be an option, and it will automatically pull the available Docker containers. Select the one marked drupal-dev-docker-php
.
PHPStorm wants to open the Windows Command Prompt instead of WSL.
You can select WSL to run instead of the default DOS prompt. Open this project and then hit File > Tools > Terminal
and under Application settings
, enter C:\Windows\System32\wsl.exe
as the Shell path
.
PHPStorm's terminal opens the home directory,
$
Attempting to use a drive letter mapping will not work correctly. Open the project in PHPStorm using the path at \\wsl$\
Once Docker is installed, the environment can be brought right up:
make init
This command could take a long time if this is the first time you're running it. Multiple versions of this environment on the same machine (or repeat builds) will utilize image caching to build faster subsequent times.
The init command runs through almost all of the available individual commands and will result in an environment ready to work with. The environment can be accessed via https://localhost:8443. MySQL and memcached are also accessible on their default ports (3306 and 11211, respectively).
The Makefile contains many additional commands that can be individually executed to perform certain actions on a case by case basis:
make [command]
help
Show available commands in the make file along with descriptions.init-drupal
Meta command to executedrupal-install config-init config-import clear-cache
.update
Meta command to executedocker-stop composer-install docker-rebuild config-import clear-cache
. Use this command after a git pull has been performed to ensure that infrastructure and configuration match the repository. This will destroy any uncommitted Drupal configuration.safe-update
Meta command to executedocker-stop composer-install docker-rebuild clear-cache
. Use this command after a git pull has been performed to ensure that infrastructure matches the repository. This will not overwrite Drupal configuration.docker-rebuild
Rebuilds the docker containers from build files.docker-status
Prints the status of docker.docker-start
Brings up the docker environment and displays status.docker-stop
Brings down the docker environment.docker-restart
Meta command to rundocker-stop
anddocker-start
.composer-install
Runs composer install against root composer.json.composer-upgrade
Runs composer upgrade against root composer.json. This will upgrade all files tracked by composer. Use with caution. To only upgrade Drupal core, usedrupal-upgrade
.drupal-upgrade
Updates Drupal core.drupal-install
Executes a drush based site install.config-init
Sets UUID of the system config to the UUID of the newly created Drupal site. This is necessary to bring configuration data between environments without bringing the database along at the same time. Configuration should be in ./config.config-import
Imports the configuration data into Drupal. This will fail ifconfig-init
has not been run first. Configuration should be in ./config.config-export
Exports config out of Drupal into ./config.config-validate
Verifies config before import.config-refresh
Meta command to executeconfig-init config-import
.clear-cache
Executes a drush based cache rebuild.destroy
Brings down the docker environment, removes the database, and deletes Drupal's files. Depending on configuration, this command may need to be executed as root.rebuild
Meta command to executedestroy init
. Depending on configuration, this command may need to be executed as root.lint
Tests custom modules and themes against PHP Parallel Lint.sniff
Tests custom modules and themes against Drupal coding standards and best practices using PHP CodeSniffer.code-test
Meta command to executelint sniff
.code-fix
Automatically fixes some errors identified viacode-test
utilizing functionality built into PHP CodeSniffer via PHP Code Beautifier and Fixer.fix-permissions
Sets appropriate permissions in the working directory ensuring that the current user is able to edit files.shell
Opens a shell in the specified container as root.
- Docker-compose is building the environment with off the shelf components. The official images from the PHP, MySQL, and memcache teams are used. Some modifications are made to the base images to enable things such as out of the box SSL encryption and XDebug configuration.
- Data for databases will be maintained through docker reboots as long as the "database"
volume is not deleted manually or with the "-v" option on
docker-compose down
. - This repository does track a composer.lock file meaning that versions of software
installed are the ones that match the lock file. Currently this repository tracks
the base installation provided by the drupal/recommended-project
with Drupal 9.0.1. You can upgrade with
make drupal-upgrade
or wait until this repository is updated. Certain files such as those provided by the Drupal scaffolding project may be subject to manipulation and may or may not upgrade cleanly. The default location for the hosted content in this project was moved from the default of/web
to/webroot
to make this directory's purpose more clear. - The Drupal site installed by default is configured with the "minimal" profile
which has absolutely zero configuration out of the box. This environment, however,
ships with a small amount of configuration that sets up blocks and themes similar to
a "standard" Drupal installation. If you want to start with less (which might be
preferable if a project is planning on building an entire theme from scratch), delete
all of the configuration files found in
/config
. If you do not import config, the site will be setup with the "Stark" theme. The installation profile used can be set in the Makefile under thedrupal-install
target, however, if you use any configuration, it's recommended that you leave it "minimal" to avoid conflicts in the future. - This repository uses a local.settings.php development file. It is included automatically if the file exists. If this code base is used in production, ensure that there is a deployment process in place to remove this file before going live. This could be an outright removal or it could be something like a switch to determine your environment.
Custom implementations for drush and the Drupal Console have been created to allow
communication with these tools inside the running instances. You can execute commands
using bin/drush
and bin/drupal
. These commands are special scripts that work
with the drush
and drupal
installed by Composer but from the inside of your docker
container so that they can access your environments running resources.
Additional scripts exist in the event that you want to use XDebug with drush or Drupal
Console. To execute these, place breakpoints in your local code and run your commands
with bin/drush-debug
or bin/drupal-debug
. Some additional configuration in your IDE
or debugging environment may be required.
Similar to the drush and Drupal scripts, this project provides a custom implementation
of Composer that can be executed with bin/composer
. This is done to eliminate the
need for a local Composer (and further PHP) install as well as to ensure that the same
versions is used consistently between environments.
If installed and configured, a local Composer installation could continue to be used
to manage the environment, but any files created by bin/composer
(including the original
system initialization), will be permission locked and might require running
make fix-permissions
to rectify the problem.
Lastly, this project ships with bin/tool
and bin/host-tool
. These are scripts that
exist to forward your input commands into docker space. Explicitly, bin/tool
executes
any command passed to it on the running PHP container. bin/host-tool
executes commands
passed to it in a new container that has the entire project folder mounted into it.
The former is useful for debugging a live environment, the latter for manipulation while
an environment is offline. In practice, neither of these will be directly used very often
by developers.
In order to bring a site developed in this project to production, the entire code base can be cloned down to the production server. Ensure the following steps are met:
- Point the web server (apache, nginx, etc) to
webroot
in your project- This directory contains Drupal and everything the web server needs -- do not serve the entire project directory!
- Set environment variables or modify settings.php for the database
- Environment variables required to work are
MYSQL_DATABASE
,MYSQL_USER
,MYSQL_PASSWORD
, andDRUPAL_MYSQL_HOST
- Environment variables required to work are
- If necessary, remove settings.local.php
- It is recommended that additional, programmatic logic is setup to ensure this is removed automatically -- leaving this file in your production environment is a liability at worst and a performance hit at minimum
If your production environment is based on docker, you can prepare an image of the current codebase:
make export-prod
In the process that follows the running of the command, docker will create new images based on a similar base to the development images with a few exceptions:
- Composer-managed files such as vendor, core, and modules will be pulled in from a sterile environment. This is to ensure that no hacking of these libraries accidentally makes it into the environment. Permanent hacks to libraries managed by Composer should be managed using Composer Patches.
- Composer installs without development dependencies. It is essential that Drupal's configuration is expecting this. If modules, such as Devel, are tracked as a Composer development dependency, Drupal will throw errors about not being able to find the Devel files if it still expects, because of configuration, for the module to be there. The Configuration Split module is excellent for this purpose.
- Debugging tools such as XDebug are not available
Tarball images for each of the PHP, Web, and Database containers will be saved into the root of the project directory. These images can be deployed using standard orchestration layers or manually if the environment is configured for it.
This environment contains most tools needed to perform day-to-day development activities, but some steps and make targets might be vague. These are some of the common use cases and how the environment can be used to satisfy them.
To begin work, clone the repository. Once the repository is cloned and the prerequisites are met (Composer and docker installed locally), a single command can be used to initialize the environment:
make init
The environment will go through many steps and should leave you with a working Drupal installation. You should be able to access the site at https://localhost:8443.
If an environment becomes unstable, or you wish to start again with a fresh environment straight from your code base, consider destroying the environment. A destroy will erase all content in your local site, so be sure there are no configuration items or content assets you wish to preserve.
make destroy
A more advanced target, clean
, will run a destroy
plus remove any created
or cached docker images. This effectively reverts your environment to a pre-development
environment state.
If you wish to do a destroy and an initialization in the same command, a command exists to merge these steps together:
make rebuild
This will perform the actions of make destoy
followed by make init
.
Environments can be stopped and frozen for later use. This can be useful if resources need to be opened up. Stopping an environment will not destroy any of the content or configuration in the environment.
make docker-stop
In a similar fashion, the environment can be restarted:
make docker-start
Once the environment has started, the site should again be reachable. These commands will be rarely used in day-to-day development.
Composer is used to manage all PHP packages tracked by the environment. It is
used for libraries as well as other PHP packages. By default, installed Composer
packages install to the /vendor
directory. Special packages (such as Drupal
modules) may be installed to different directories.
This is an example adding PHP Code Sniffer to your environment.
bin/composer require squizlabs/php_codesniffer
git add composer.json composer.lock
git commit -m "Added PHP_CodeSniffer to environment."
Note that the files downloaded by Composer and placed in /vendor
are not
tracked in your SCM and shouldn't be added manually. The composer.json and composer.lock
files contain enough information for other environments to obtain the exact same code the
next time their environments are built.
Composer is also used to install Drupal modules, themes, profiles, and
libraries. The end directory for these packages varies depending on the type
of package being required, however, like the /vendor
directory, these
directories are ignored in git and should not be added to your SCM.
This is an example adding Webform to your environment and activating it.
bin/composer require drupal/webform
bin/drush en webform
make config-export
git add composer.json composer.lock config/core.extension.yml
git commit -m "Added Drupal Webform to environment."
These steps are similar to a normal Composer package, but the environment needs to be aware that Drupal has a module to enable. After it's installed, it is enabled using drush. After it has been enabled, Drupal's configuration is exported. In this example, there was no configuration of the module after the installation, but be mindful that there might be additional configuration files to add after a module has been enabled. Lastly, this configuration, along with the composer.json and composer.lock files, are added to the code management.
If a custom module or theme is needed, the Drupal Console will help facilitate creating the boilerplate for these items. The manual for Drupal Console can be helpful during these steps. The console can also be used to create boilerplate for existing modules and plugins.
This is an example creating a module called "Example Module":
bin/drupal generate:module --module "Example Module"
- The Drupal Console will confirm a few bits of information
git add web/modules/custom/example_module
git commit -m "Created a new module, Example Module"
The code that comes out of this generation will be owned by the root user which
often means it will not be editable. Consider running the make fix-permissions
command after creation to rectify this and edit locally.
Drupal ships with an extensive configuration tracking interface known as
CMI. Configuration for almost everything can be
exported and is tracked in flat yaml files stored in /config
. The environment
will automatically import these configuration files during a make init
or
make update
target.
It is important to validate that the configuration exported is the configuration that you were expecting to export:
make config-validate
This command will list out all of the configuration files inside the /config
directory that are different than configuration in Drupal. If the configuration
that is listed reflects the changes you have made, then it is safe to export the
configuration and commit the results.
This is an example changing the theme of the site:
bin/drush config-set system.theme default bartik
make config-validate
- Ensure that the output of this contains only related configuration.
make config-export
git add /config
git commit -m "Set Bartik theme as default."
In this example, the configuration modified was done from drush, but almost all configuration done in the interface will also be tracked this way. Keep the configuration commits simple and often. Be mindful the quantity of files can become very large very quickly.
Note that all configuration that does not match what is in the /config
directory will be exported. This does not mean that all of it needs to be
committed. In the example above, the /config
directory is blanket added to git
but this might not always be the case. Take care to only commit what is
necessary to the work at hand.
The cleanest and most effective way to modify configuration for the site is to commit each configuration change as it is performed:
- Make a single change (or related set of changes) to Drupal
- Validate and export configuration
- Add and commit exported configuration to SCM
- Repeat for other changes
When working with a team, upstream code will often be newer than local code. In order to keep the environment up to date, there are a few commands to facilitate this depending on the situation and the current state of the environment.
If an environment has no uncommitted configuration or code changes in it, the
make update
command should be used:
git status
- Ensure the environment is clean
git pull
make update
This command will update the infrastructure, install/update packages, and reset Drupal's configuration to the configuration tracked in code.
If an environment has uncommitted work in it, caution should be taken when
updating to ensure there are no conflicts. The make safe-update
command exists
for this purpose:
git pull
make safe-update
This command will update the infrastructure and install/update packages, but will not touch Drupal's configuration. This will help preserve any work currently being done in the environment.
When possible, update during a state of clean development. Between the two
commands, make update
should be used much more often.
Some tests require the use of a browser, real or headless. This environment has Behat installed as a dependency and runs Selenium with drivers for Chrome and Firefox preconfigured. These browsers are run in a self-contained docker environment.
Feature yaml files can be placed in tests/behat/features. These features can
be run with make behat
. By default, the Firefox browser is used. If Chrome
is preferred, call the handler script with the option: bin/behat -p chrome
.
For debugging purposes, the processes around bring the testing environment up, running the tests, and finally bringing the environment down are isolated into separate make targets:
make behat-start
make behat-run
make behat-stop
While the environment is running, it can be accessed via a VNC connection:
- Firefox (localhost:5900)
- Chrome (localhost:5901)
The password to the VNC environment is "secret".
The environment runs in two different fashions concurrently: locally and in Docker containers. Due to the nature of Docker containers, most items created inside these containers are owned by the user running the services inside the container. This user is usually root.
While this is good for ensuring very little has to be done inside the container, it adds a challenge to modifying files that often sync between the container and the local environment. These could be files such as settings.php or files touched by drush or Drupal Console.
Permission errors will typically be encountered during two different common operations:
- Editing files that were created inside the container
- Checking out code (changing branches or resetting files)
If permission errors are ever encountered, they can be rectified by running a single command:
make fix-permissions
If the environment contains a large amount of files, this command could take a while, but when it's done, there should be no more problems.
The project has a shell which provides all the required host dependencies.
To use the provided shell run nix develop
.
If using direnv (https://direnv.net/) you can run the shell automatically in
this directory with direnv allow
- Integrate the option for other Docker-based containers to assist with specific tasks such as ElasticSearch.