Developing and maintaining a Drupal site with Drupal-VM
I’m still working on this. Apologies for yet incomplete bits.
Introduction
I used Jeff Geerling’s Drupal-VM to create both a local development Drupal server and a live production server very much along the lines of his tutorial which he wrote for Drupal MidCamp in March 2017. So you might like to go there if I have omitted a detail you want to follow.
We use Drupal-VM to keep our Development, Staging, and Live sites’ environments exactly in sync.
-
The operating system is at exactly the same level
-
The required software components are exactly the same
-
The configuration of both operating system and software components are the same.
The following describes our use of Drupal-VM using the refactorvm
branch of our GitHub repo iainhouston/bradford-abbas.uk
The major section Important Drupal-VM configuration files below gives further information about our oparticular use of Drupal-VM so that you can see how I’ve used Drupal-VM to build and maintain our website here at bradford-abbas.uk.
Applicability to other UK Parish Councils
Another Parish Council could fork our GitHub repo and follow the steps below to buid their own website and manage their own Meetings, Agendas, Minutes and other Documents; distribute News Articles; summons Councillors to attend Mettings and so on.
There is very little, like website names, that are peculiar to Bradford Abbas Parish Council. Everything else that follows could be used to build a Parish Council website that conforms to the Transparency Code for Smaller Authorities which came into law in 2014.
Costs
Drupal-VM uses only free, Open Source software. The inescapable costs of our website are:
-
the small monthly cost of the Amazon EC2 web server;
-
the annual renewal of our domain name;
-
the annual renewal of our SSL Certificate;
-
the annual renewal of our data protection (ICO) certificate which we’d need even if we didn’t have a website.
Typical use cases
There are three typical use cases that use steps described in one or more of the major sections below.
-
Most typically, deploying updates to the live server
Deploying updates to the live server after having applied a security update to a Drupal core or contributed module, or an update we’ve made to our Drupal theme:
-
Set up the local development environment. We only need to do this once on a Mac where we haven’t been doing our website’s development work before.
-
Do some development and testing.
-
Deploy the updated and tested system to the live server.
-
-
Less typically, switch live servers.
This is one that I have done recently to upgrade the live server to the a more recent Linux distro and a later PHP verdsion so as to accomodate a more recent Drupal version.
-
Set up a new live prodction server
-
Clone the live server to the local development server
-
Do some development
-
Deploy the updated and tested system to the new live server.
-
-
Theme development: css and html changes
As part of either of the “Do some development” steps above: use the theme’s development toolchain to create a new git-tagged version of
iainhouston/pellucid_monoset
Set up the local development environment
-
Clone this GitHub repo to
~/bradford-abbas.uk -
Add the following alias to your
~/.zshrc(or~/.bashrcas appropriate):
alias cdbadev="cd ~/bradford-abbas.uk && source ./scripts/badev/dev_aliases.sh"
-
$ source ~/.zshrc(or~/.bashrcas appropriate) -
$ cdbadev=>updateLiveCode - Code and Config to Live site cloneLive2Dev - Clone Live Database and Files to Dev site safecex - Safe export of Dev site's configuration endev - Enable development modules in Dev siteWe have written several convenience shell commands to do much of the day-to-day heavy lifting for us. As above, we are reminded of four of them when we switch to our
~/bradford-abbas.ukdirectory.cdbadevalso assigns several key exports and aliases. -
Install the libraries and a working Drupal
composer installwill download all the libraries. These include the Symfony PHP libraries, upon which Drupal is built; Drupal’s core and contributed modules; other non-PHP libraries like our own Ansible rôles and tasks iniainhouston/drupal-vm, and our own Drupal themeiainhouston/pellucid_monosetcomposer installalso places the appropriate Drupal contributed and core modules in the appropriate directories in thewebdirectory which it creates for us (please ensure you don’t start out with~/bradford-abbas/webpresent, orcomposer installwill not create the Drupal site.)You can reassure yourself that the installation has been successful and will shortly, after we have fired up the development VM, respond to
httprequests by the presence of~/bradford-abbas/web/autoload.phpand of the presence of~/bradford-abbas/web/index.php.composer installcreatesweb/autoload.phpso that running Drupal modules have access to the libraries inweb/../vendor/viaweb/../vendor/autoload.phpandvendor/composer/autoload_real.phpwhich can then load any of the PHP classes etc. it discovers in thevendor/packages. -
Verify
webmaster’s access to the Live ServerSatisfy yourself that the
Hostsettings in your~/.ssh/configsettings match the host names inscripts/badev/dev_aliases.shand that you have the correct key pairIdentityFileprovided when the AWS EC2 Server was set up. Do this byssh wpbapcsuccess.Host wpbapc ForwardX11 no User webmaster Hostname bradford-abbas.uk PreferredAuthentications publickey IdentityFile ~/.ssh/BAPC-2.pemFor example,
cdbadevdoesexport LIVE_SSH_ALIAS="wpbapc"and several scripts inscripts/badevrefer to$LIVE_SSH_ALIASThis access is needed in the next step.
-
Fire up the development VM
vagrant upwill also provision the VM if it does not previously exist, otherwise Vagrant will just boot it up and manage the IP Addresses in/etc/hostsand the NFS shared directories in/etc/exports -
Now
vagrant sshand accept the authenticity of the newly-created host / vagrant server. (If you don’t do this, the next step will fail.)exitthe vagrant server to return to your Mac. -
Ensure that the drush aliases for the live and development servers in
./drush/sitesare correct -
Sync the Live Drupal to the Development Drupal
`cloneLive2Dev` clones the live database and the static files (uploaded images, PDFs etc.) to the development Drupal in the VM.
Drush will not copy/clone between to remote servers. We (the host controller Mac) are dumping the live SQL into a newly-named file in `vm/saved_sql/live` for later use if required, and importing it into `@badev`, the development Drupal.
For this reason, too, `cloneLive2Dev` `rsync`s the static files from `wpbapc`'s access in the live server to the controlling host's `/web/sites/default/files/` rather than using `drush core:rsync`. NFS makes these files immediately available to the development server's VM.
- Make changes to the site’s Theme
We have just (June 2020) changed from our own bespoke theme to a si=ubtheme of `drupal/olivero` which is `web/themes/contrib/pellucid_olivero`
We are aiming not to use any styling toolchain (gulp, postcss etc.) to keep things really simple with just straight-ahead CSS.
Deploy the updated and tested system to the new live server.
The static data files (sites/default/files/) and the database on the server are not affected by the first step.
Pushing updated stuff to the live site
updateLiveCode is shorthand for:
DRUPALVM_ENV=prod \
ansible-playbook vendor/iainhouston/drupal-vm/provisioning/playbook.yml \
--inventory-file=vm/inventory \
--tags=drupal \
--extra-vars="config_dir=$(pwd)/vm" \
--skip-tags=test_only \
--become --ask-become-pass --ask-vault-pass
This doesn’t re-provision the live server, it does just those playbook tasks - those with tags: ['drupal'] - required to update the following:
- Drupal core and contributed modules (via
composer.json) - Our SSL key and certificate
- Drupal configuration YAML from most recent local
drush @badev cex(and thussafecex). But note that it doesn't run adrush @balive cim
So you run updateLiveCode to deploy to the live server after any of these have been updated and tested on the local development site.
Development:
Provisioning the development site
I do my development on a Mac but Jeff describes here how its done on a Windows 10 machine.
-
Required software
Our local environment (at the time of writing is shown by using our helper alias
checkVersions:PHP 7.4.0 (cli) (built: Nov 29 2019 16:18:44) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.0, Copyright (c), by Zend Technologies Composer version 1.9.1 2019-11-01 17:20:17 Vagrant 2.2.6 VirtualBox 6.0.14r133895 ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19] ansible 2.9.1 ... NodeJS Version v13.2.0 npm Version 6.13.1 vagrant-auto_network (1.0.3, global) - Version Constraint: > 0 vagrant-hostsupdater (1.1.1.160, global) - Version Constraint: > 0 vagrant-vbguest (0.21.0, global) - Version Constraint: 0.21 Developer Edition of Mozilla Firefox 72.0bErrors ahead?: My experience over several years of using Drupal-VM shows that unexplained provisioning errors can often disappear after you are sure you have upgraded to the latest of each of
ansible;vagrant; andVirtalBox. -
Key environment variable
If you think you’re provisioning a live server rather than a development one, or vice versa, ensure that the
DRUPALVM_ENVenvironment variable is correctly set by issuing vagrant commands in the form:DRUPALVM_ENV=vagrant vagrant upandDRUPALVM_ENV=vagrant vagrant provision. Keep and eye onecho $DRUPALVM_ENV: that caught me out. -
Drush:
Getting
drushright has taken a lot of my bandwidth over various releases. I now take the approach of using a single, locally installeddrushthat is aliased to thevendordirectory on the host machine; uses<project root>/drush/siteslocally for this website’s aliases, and, because NFS has the devlopment server accessing exacly the samedrushbinary for execution in both host and guest machines - i.e. in MacOS host and Linux guest VM - we know we’re at exactly the samedrushrelesase: host (a.k.a.controller); dev server; and live server.
Encrypted secrets
Managing the Production Server’s secrets file
This is where the passwords for Drupal admin, drupal db; and mysql root on the Live Production Server are encoded. (The development server uses plain text values from vagrant.config.yml.)
ansible-vault create vm/prodn_secrets.yml
ansible-vault view vm/prodn_secrets.yml
ansible-vault edit vm/prodn_secrets.yml
Encrypting SSL key and certificate.
ansible-vault encrypt vm/certs/SSL.crt
The Live Production Server
Initialising the AWS EC2 live server
These steps are required before we can run Ansible to automatically provision the live server with all the software we require.
-
Store the one-time-generated security key pair associated the AWS EC2 Server in
~/.ssh/BAPC-2.pem -
On EC2 server: Install Python (and editor).
Ansible needs this to work its provisioning magic. (Install
emacsor your favourite editor). Python most probably will have been installed as part of the Ubuntu Linux distro.The following assumes that we have the AWS EC2 server account’s key pair in
~/.ssh/BAPC-2.pemon the Macssh ubuntu@remote.server.uk -i ~/.ssh/BAPC-2.pem # from local sudo apt install emacs25-nox python # on remote -
Enable
rootlogin on EC2 server.-
Log in using the user automatically created when AWS launched the EC2 server (
ubuntu)ssh ubuntu@remote.server.uk -i ~/.ssh/BAPC-2.pem # from local sudo emacs /root/.ssh/authorized_keys # on remote -
Remove the preamble
remove the preamble before the string
ssh-rsain/root/.ssh/authorized_keys
-
-
On local control machine: Create
vars.ymlCreate
vendor/iainhouston/drupal-vm/examples/prod/bootstrap/vars.ymlper the tutorial creating a new admin account (webmaster) on the server with the password recorded inVault PWhere on the Mac. -
On local control machine: run the ‘init’ playbook.
ansible-playbook -i vm/inventory vendor/iainhouston/drupal-vm/examples/prod/bootstrap/init.yml -e "ansible_ssh_user=root"We should now have created
webmasterand be able tossh webmaster@remote.server.ukand thencesudothings using the password recorded inVault PWhere on the Mac. -
On EC2 server: revert the preamble
revert the preamble before the string
ssh-rsain/root/.ssh/authorized_keysto prevent anyone logging intorootdirectly.
Provisioning the Production server
Additional provisioning rôles
There are several Ansible tasks that are peculiar to our setup and are not already provided by Drupal-VM’s roles and tasks:
# setup DKIM; Place SSL cert etc.
pre_provision_tasks_dir: "/pre_provision_tasks/*"
post_provision_tasks_dir: "/post_provision_tasks/*"
Run the provisioning playbook
DRUPALVM_ENV=prod ansible-playbook \
vendor/iainhouston/drupal-vm/provisioning/playbook.yml \
--become --ask-become-pass \
--ask-vault-pass
--inventory-file=vm/inventory \
--extra-vars="config_dir=$(pwd)/vm" \
--skip-tags=test_only
Note that we don’t use --tags=drupal, because, in this case, we require all the Provisioning tasks to be run.
Ad hoc backups of critical datasets
On the Live Server (webmaster account):
/usr/local/bin/drush -r /var/www/drupal/web sql:dump \
--result-file=../bradford-abbas.uk.sql
/usr/bin/s3cmd sync \
/var/www/drupal/web/sites/default/files/ \
s3://bradford-abbas.uk.files --exclude-from=/var/www/drupal/web/../.s3ignore
/usr/bin/s3cmd put \
/var/www/drupal/bradford-abbas.uk.sql \
s3://bradford-abbas.uk.db
Important Drupal-VM configuration files
These are in the following directories:
-
The
configdirectoryconfig/syncis where the Drupal configuration.ymlfiles are kept undergitversion control. After you have runupdateLiveCodeyou then rundrush @balive cimto import the new configuration into the live site.New configuration settings can occur both as a result of changes you make to Drupal Content Types etc., and changes to updated / newly installed Drupal Corre and Contributed modules.
When you run
safecexthenconfig/syncis replaced by configuration.ymlfiles exported from the development Drupal’s current database into thegitchange managemnt. -
The
drushdirectorydrush/sitescontains the drush alias definitions for@baliveand@badev -
The
scriptsdirectory-
badevWhere the shortcut / convenience commands (see above) are defined. -
composercontains acomposerinitialisation script that will install a basic Drupal site. Very useful. Make sure yourwebdirectory doesn’t exists, though, before you runcomposer install
-
-
The
vmdirectory-
vm/certsWhen a new SSL key / certificate pair are downloaded (via LCN, our registrar) they are encrypted here with
ansible-vault(see below). -
vm/post_provision_tasksandvm/pre_provision_tasksAs expected, Ansible tasks that extend the functionality of
drupal-vmfor our needs. For example: installing and configuring DKIM’s digital ‘signing’ of emails -
vm/templatesjinja2templates for files to be customised by Ansible before boing copied into a server during provisioning.
-
-
The
webdirectoryThis is Drupal’s docroot. Make sure it doesn’t exist before you run
composer installas will be the case first thing after having cloned this repo.Note that the Project root is
.../bradford-abbas.ukwhere you cloied this repo. -
composer.jsonUpdated by all the
composer require ...andcomposer update ...we’ve done over the lifetime of the project. It is used both to establish our development and live production Drupal systems and to deploy updates throughgit.In the
require-devsection we have packages that are not required on the live production server (e.g.drupal/devlandiainhouston/drupal-vm) -
VagrantfileNote that this loads the
Vagrantfileinvendor/iainhouston/drupal-vmbut also sets some important localENVironmen=t variables including some Ansible argumments that you might have overlooked -
vendorThis is where
composerinstalls all the required libraries including the Symfony PHP modules etc. for Drupal, and other non-PHP libraries - includingiainhouston/drupal-vm -
tmpandprivate_filesThese directories are created by Ansible in the project folder - i.e. a level above the Drupal docroot (where the
index.phpsits). Ansible does this in two circumstances.-
On the devlopment server as a side-effect of provisioning with
vagrant uporvagrant provision. -
On the live production server as a side-effect of provisioning with
ansible-playbook(See Run the provisioning playbook)
These two directories are purely for use by a running Drupal system
-