Automating Drupal Deployments on AWS EC2 with CodeDeploy

In our previous blog post we discussed the Codedeploy Deployment Automation. Codedeploy deploys using s3 or github. In this blog post, we will be focussing on deploying Drupal application where the code will be downloaded from S3 bucket.

Prerequisites

Service Role

Create a codedeploy service role that will be granted to Codedeploy

IAM Instance Profile

EC2 instances needs to be launched with proper permissions to access the files from s3 bucket.

Create Role.
Select role type: Amazon EC2
Attach EC2 full access
Set the inline policy as below

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

Settingup Autoscaling Environment

Create launch configuration
Choose the AMI
Choose the instance type
Supply a name and attach an IAM profile
In Advanced Details, give script to install codedeploy agent in Userdata. For more details on installing agent, refer to our previous blogpost Deployment Automation Using Code Deploy
Specify size
Create a security group
Review and create Launch Configuration for AutoScaling Group and then Create AutoScaling Group.
Specify scaling policies for high and low CPU utilization
Review and create the group

Achieving High Availability

For a highly available setup, create an elastic load balancer.
Select a security group for your load balancer in next screen and configure health checks.
Go to Autoscaling group console and attach the ELB to the autoscaling group.

Building Deployment Revision

To build a deployment revision for s3, you need to create a compressed archived file with your application code and an AppSpec file.
The sample appspec.yml which we used in this deployment is as below:

version: 0.0  
os: linux  
files:  
  - source: /
    destination: /var/www/html/drupal
hooks:  
  BeforeInstall:
    - location: .scripts/remove_files.sh
      timeout: 300
      runas: root
    - location: .scripts/install_dependencies.sh
      timeout: 300
      runas: root
  AfterInstall:
    - location: .scripts/change_permissions.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: .scripts/start_server.sh
      timeout: 300
      runas: root
  ApplicationStop:
    - location: .scripts/stop_server.sh
      timeout: 300
      runas: root

The Hooks scripts will run at specific deployment lifecycle events during the deployment. The content of the scripts are as follows:

  • Remove_files.sh (Removing all the files (if available) in /var/www/html/)
#!/bin/bash
rm -rf /var/www/html/*  
rm -rf /var/www/html/.scripts  
rm -rf /var/www/html/.htaccess  
  • Install_dependencies.sh
#!/bin/bash
yum install -y nginx  
yum install -y php55-fpm  
yum install -y php55-gd  
yum install -y php55-mbstring  
  • change_permissions.sh
#!/bin/bash
chmod -R 755 /var/www/html/drupal  
chmod -R 777 /var/www/html/drupal/sites/*  
  • start_server.sh
#!/bin/bash
service nginx start  
service php-fpm-5.5 start  
  • stop_server.sh
#!/bin/bash
isExistApp=`pgrep nginx`  
if [[ -n  \$isExistApp ]]; then  
   service nginx stop
fi  
isExistApp=`pgrep php-fpm-5.5`  
if [[ -n  \$isExistApp ]]; then  
    service php-fpm-5.5 stop
fi  

Create a compressed archive file which will contain the application code, these scripts and also an appspec file. Upload it to your s3 bucket.

Deployment Through CodeDeploy

A CodeDeploy application identify deployment targets (EC2 instances) on which a particular revision is applied while creating a deployment group.

Create Application

Give a suitable name to your codedeploy application and a name to your deployment group on which you will be deploying your application. Provide autoscaling group name in tags, basis on which deployment targets are identified.
Select your desired deployment configuration which will determine how the application will be deployed to your instances. There are three possible configuration options:

  • CodeDeployDefault.AllAtOnce
  • CodeDeployDefault.HalfAtOnce
  • CodeDeployDefault.OnceAtOnce

Select codedeploy service role which we created

Create New Deployment Once application is created, it’s time to create a new deployment which will deploy the revision to deployment targets.
For S3 revision type, we provided the path of our application archive file. Also, we have only one server till now launched with our autoscaling group. So we are giving deployment configuration CodeDeployDefault.OneAtATime.
That’s it. Deployment process will get started. It will go from Created to In Progress to Succeeded.

Configuring Drupal

After deploying the application to the autoscaling group, we have the content of application to be served in the server launched with autoscaling group. So, now we have nginx web server running on the server. We need to create a virtual host file for our drupal application.
* Log into the server. * Run command: vim /etc/php.ini * Uncomment cgi.fix_pathinfo=0 and change the value from 1 to 0. * vim /etc/nginx/conf.d/drupal.conf

server {  
listen 80;  
server_name 127.0.0.1;  
location / {  
    root /var/www/html/drupal;
    index index.php index.html index.htm; 
    if (-f $request_filename) {
    expires 30d;
    break;
    }
    if (!-e $request_filename) {
    rewrite ^(.+)$ /install.php?q=$1 last;
    }
} 
location ~ .php$ {  
    fastcgi_pass   localhost:9000;  #port where FastCGI processes were spawned
    fastcgi_index  index.php;
    fastcgi_param SCRIPT_FILENAME   
    /var/www/html/drupal$fastcgi_script_name; #same path as above
    fastcgi_param PATH_INFO $fastcgi_script_name;  
    include /etc/nginx/fastcgi_params;  
}
}

Restart nginx and make an image out of this server
Copy Launch Configuration
Edit AMI. Select the one which you created in previous step
Keep other settings as it is and create this launch configuration.
Review and create the launch configuration. Update this launch configuration in auto scaling group so that new instances will get launched with updated image.

Redeploying application with different configuration

In the previous step, we were having only one server. In this step, we are trying to launch multiple number of instances and deploying the revision with different deployment configuration.

Change the number of instances to 4 in the autoscaling group.
Deploy a new revision
Select Application, Deployment group and Tags. Give s3 path to your application. Select deployment configuration CodeDeployDefault.HalfAtATime which will deploy the application revision upto half of the instances at a time.
Deploy Now
Now, hit the IP of any of the server among the four. Drupal Install page will appear.
Proceed with installation and on the next screen you will get something like:
Log into the server. Copy the default settings php file to settings.php and change the permissions of that file.

cp -r ../sites/default/default.settings.php ../sites/default/settings.php  
chmod 755 -R ../sites/default/settings.php  

Give database credentials at next page.
And your drupal application has been set up now.

Storing Static Content on S3

One of the issues you will run into, with a loadbalanced drupal environment is the static content. Using Gluster or NFS is one way to share the content among all servers and keep it updated, but on AWS, s3 is a more elegant solution.

Amazon S3 module of drupal allows the local file system to be replaced with Amazon S3 i.e. the static media can be stored in a S3 bucket. The prerequisites are below:

Amazon S3 require Composer Manager Module to be installed already. We have installed drush (a command line interface for drupal) to install composer manager. Follow the below steps to install drush:

$ wget --quiet -O - http://ftp.drupal.org/files/projects/drush-7.x-5.9.tar.gz | sudo tar -zxf - -C /usr/local/share
$ sudo ln -s /usr/local/share/drush/drush /usr/local/bin/drush
$ drush --version

Download Composer Manager zip file and extract it to modules. Follow below commands to install composer manager module:

$ wget https://ftp.drupal.org/files/projects/composer_manager-7.x-1.8.zip
$ unzip composer_manager-7.x-1.8.zip -d /var/www/html/drupal/modules
$ cd /var/www/html/drupal/modules/composer-manager/
$ drush composer-manager install

Installing S3 Module

Download the Amazon S3 module for drupal and extract it to /var/www/html/drupal/modules.

$ wget https://ftp.drupal.org/files/projects/amazons3-7.x-2.0.zip
$ unzip amazons3-7.x-2.0.zip -d /var/www/html/drupal/modules

Also, Amazon S3 requires few dependencies to be installed. So, next step is to increase the memory size in /etc/php.ini and update composer-manager to automatically install all required dependencies by Amazon S3. Execute the below commands:
Next, Enable the modules. Hit the IP in browser and go to modules and enable both modules (Composer Manager and Amazon S3).
Add the below line in settings.php:

$conf['composer_manager_file_dir'] = '/var/www/html/drupal/sites/all/';

Now, configure the modules to store the static media in a S3 bucket. Go to Configuration. Click Amazon S3.
Enter Access Key, Secret Key and a bucket name where the media will get stored.
Also, configure file system to select Amazon S3 to store and download the content and give other file system paths as shown in below screenshot:
Save this configuration. Also, go to structure.
Click Content Types. Manage fields for article.
Edit settings for image.
In Image field settings block, Select Amazon S3.
Now, try adding some static media content.
Check the S3 bucket which you specified in the Configurations. The image will be available there.

Thats about it. I hope you find it useful.

Happy CodeDeploying! :)

Priyanka Sharma

Priyanka is Senior Cloud and DevOps Engineer. She can churn out CloudFormation templates at a moment's notice and play with Chef/Ansible. Dancing, music, badminton and word games are her hobbies

comments powered by Disqus