Running Drupal 7 on AWS - part 2

Update 2016/07/11: AWS has released EFS, which is a better choice for our Drupal 7 setup than using S3. Check this blog post for a newer stack that replaces S3 with EFS.

This blog post continues with an actual code example for the blog post about Running Drupal 7 on AWS - part 1. It provides a full CloudFormation setup to get a full Drupal 7 stack running on AWS.

This is the stack we are creating (click the image for a larger version):

Drupal 7 stack on AWS

All the code referenced here is available in this Github repository:

AWS CloudFormation

When you are creating large software stacks, creating it by hand is not an option anymore as that takes too long to setup and is too prone to errors. For this reason AWS has created AWS CloudFormation, their infrastructure-as-a-code service. Check the video on that page for a short introduction.

Sidenote: AWS currently has its own container service called Elastic Container Service (ECS), which we could use since our Drupal 7 site comes in a Docker container. We are however doing it the old school way and will manage our own EC2 instances.

Creating our Drupal 7 stack with CloudFormation

Creating the stack from the drupal7.json file is quite simple:

  • Go to the CloudFormation page on your AWS account
  • Create a new stack, give it a name and select the drupal7.json file
  • Review some of the settings you can change, they should be pretty straight-forward
  • Create the stack and after about 10-15 minutes everything should be up and running

When the stack has been created you will get a value in the Outputs for the WebsiteURL parameter, which is the hostname of the Elastic Load Balancer. The last step to add here would be to create a Route 53 ALIAS record to this name to map it to your real website url.

Surfing to the url will give you an error though, as we have a valid settings file but an empty database. You can either copy your own database now to the RDS server (see the Q&A section how to do that) or simply browse to /install.php and install a fresh copy of Drupal.

Structure of the stack

The biggest piece is the Launch Configuration resource “LaunchConfigurationForDrupalWebServer”. This contains the setup scrip that will be used on the web servers. It installs Docker, generates a Drupal settings.php and builds a new Drupal container that contains this settings.php file.

All the rest is pretty straight-forward AWS stuff: a VPC with 2 subnets, NAT instances for the private subnets, Internet Gateways for the public subnets, a MySQL DB, a memcached instance and an EC2 setup with LC, ASG and ELB.

Some Q&A

How do you ssh into this instance now?

You can’t. You will need to create a bastion (relay) host in a public subnet and assing it a public ip. The web servers run inside the private subnet, which has no direct connection possible from the outside (because of the subnet routing table not using an Internet Gateway). You then ssh to the bastion and then ssh to the instances in the private subnet (or configure ssh forwarding in your local ssh config).

How can I copy my existing database to the RDS db?

Use the bastion host to set up an ssh tunnel. SequelPro for Mac can do this. Or just ssh to the bastion and cat your SQL file to the RDS MySQL instance using the hostname, username and password.

How do I get the logs from the Docker containers in a central location?

Use an rsyslog server in your docker-compose.yml file, like Papertrail:

  build: .
    - "80:80"
  log_driver: syslog
    syslog-address: hostname:port
    tag: "drupal"

I can’t seem to send emails, do I need to configure an SMTP server?

Yes. You should configure Amazon Simple Email Service (SES) in Drupal in your settings.php file. You can script this in the Launch Configuration too as you build the settings.php there.

But what about drush in this setup?

Drush is not used here. We don’t want to install it inside the Dockerfile to keep the container as clean as possible. So simple use curl and ADD to download Drupal modules and themes.

In an actual Drupal production site you would also not use the base FROM: drupal:7-apache in your Dockerfile. You would use your own Drupal docker image that contains your full Drupal stack (core, modules, themes, config…) and just overwrite the settings.php file in the Launch Configuration (like already is being done right now).

Todo list

There are still a few things missing for this CloudFormation stack:

  • Use 2 CloudFront distributions:
    • One for the S3 static content
    • One for the ELB so anonymous users also get a cached page
  • Add Papertrail logging to the Docker containers
  • Use more CloudWatch metrics for the Auto Scaling Group adjusments
  • Configure SES so Drupal can send emails

I might add those in the future, but right now these are left as an exercise for you to implement.

Problems with this stack

There are still some problems with running this setup on AWS though:

  • CSS and JS aggregation does not work with the s3fs module
  • Question: Is the session fixation on the ELB the right way to go?

This stack is still a theoretic one, I don’t really use this in production. I’m sure there will be more problems showing up when you actually start using it for a production setup, feel free to use the comments section to point them out and I’ll see if I can find a decent solution for the.

Further reading

While writing this blog post I did a lot of research on writing CloudFormation stacks, and as it usually goes, I found a lot of better examples than the ones I was writing. So, looking back now on my blog post, most of the code of my CF templates comes from the official AWS examples below, so make sure to check them out too. They have a lot of examples for some common stacks, with or without Multi-AZ support, and you can pretty much copy/paste entire stacks as a starting point for your own stacks.

comments powered by Disqus