scaling drupal in aws using autoscaling, cloudformation, rds and more

40
Scaling Drupal in the Cloud with AWS Nick Veenhof

Upload: acquia

Post on 15-Jul-2015

483 views

Category:

Engineering


13 download

TRANSCRIPT

Page 1: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Scaling Drupal in the Cloud with AWSNick Veenhof

Page 2: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Who?

+8  Years  in  Drupal

Fairly  heavily  invested  in  Search

+3  Years  at  Acquia

Tech  Lead  @  MollomBelgium

Boston

Barcelona

Belgium

@Nick_vh

Page 3: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Components→Let’s get physical! Well.. Sort of.→ I want you all to regroup in all the components that a

website needs. One row = One Component→ I will be a site visitor, so I want you to start from the front

to the end. What is the first layer?

Page 4: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

3 Layers

Webserver  EC2  Instance

MySQL  RDS

Domain  Route  53

Page 5: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Ephemeralism

Page 6: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Is Theory boring?Describes  the  optimal  environment  and  how  this  relates  to  reality.  A  very  digestible  book    for  designing  distributed  systems.  This  book  exposes  software  patterns  that  every  self-­‐respecting  cloud  infrastructure  engineer    should  know.  http://the-­‐cloud-­‐book.com/

Page 7: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Cap Principle

Limoncelli,  Thomas  A.;  Chalup,  Strata  R.;  Hogan,  Christina  J.  (2014-­‐09-­‐01).  The  Practice  of  Cloud  System  Administration:  Designing  and  Operating  Large  Distributed  Systems,  Volume  2  (p.  21).  Pearson  Education.  Kindle  Edition.  

The  CAP  Principle  CAP  stands  for  consistency,  availability,  and  partition  resistance.  The  CAP  Principle  states  that  it  is  not  possible  to  build  a  distributed  system  that  guarantees  consistency,  availability,  and  resistance  to  partitioning.  Any  one  or  two  can  be  achieved  but  not  all  three  simultaneously.

Page 8: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Ephemeralism

Webserver  EC2  Instance

MySQL  RDS

Domain  Route  53

Page 9: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Horizontal Scaling of Web Servers

Page 10: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Database Scaling

Replica

Primary

Page 11: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Caching

Replica

Primary

Memcache  ElastiCache

Page 12: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Spof Caching

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Page 13: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Spof Caching

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Page 14: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Permanent Storage

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3

Page 15: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Version Control

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3

GitHub

Page 16: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Persistent Storage

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3

GitHub

Page 17: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Reverse Proxy

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3GitHub

Varnish  EC2  Instances

http://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

Page 18: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Reverse Proxy (v2)

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3GitHub

Varnish  EC2  Instances

http://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

Nginx  EC2  Instances

Page 19: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Reverse Proxy (v3)

Webservers  EC2  Instances

MySQL  RDS

Domain  Route  53

Replica

Primary

Memcache  ElastiCache

Backup  Storage  S3GitHub

http://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

Varnish  &  Nginx  Elastic  Beanstalk    Docker  (ECS)

+

Page 20: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more
Page 21: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more
Page 22: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Unexpected Spikes→You could be hosting the next World Cup website→Or under some page load DDOS from a script kiddie→A website that is marketed heavily in the next weeks. But

is fairly idle in the rest of the year→Former slashdot effect (now Reddit)→…

Page 23: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Stacking up

WebServer  StackMySQL  RDS Replica

Primary

Object  Caching  Stack

Backup  Storage  S3GitHub

http://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

+

Database  StackWatch  out  for  Aurora.    

RDS  is  limited  by  Instance  Size

Load  Balancing  +    Page  Caching  Stack

Page 24: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Scaling Up

WebServer  Stack

MySQL  RDS Replica

Primary

Caching  Stack

Backup  Storage  S3

GitHubhttp://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

+

Database  StackWatch  out  for  Aurora.    

RDS  is  limited  by  Instance  Size

Load  Balancing  +    Page  Caching  Stack

Page 25: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Scaling Up

http://www.cloudreach.com/gb-­‐en/2013/01/varnish-­‐autoscaling-­‐love-­‐story/

AWS  AutoScaling  Group

Minimum  2  Maximum  10

Page 26: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AutoScaling Policies→CPUUtilization→ IF CPU(combined) > ’80% for 5+ min’ THEN ‘add

instance’→Custom CloudWatch Metrics→ Infinite possibilities

Page 27: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Cloudformation Components{          "ElasticLoadBalancer":  {                  "Type":  "AWS::ElasticLoadBalancing::LoadBalancer",                    "Properties":  {                          "CrossZone":  "true",                            "AvailabilityZones":  {                                  "Fn::GetAZs":  ""                          },                            "LBCookieStickinessPolicy":  [                                  {                                          "PolicyName":  "CookieBasedPolicy",                                            "CookieExpirationPeriod":  "30"                                  }                          ],                            "Listeners":  [  

Page 28: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Cloudformation Sub Stacks        "CacheStack":  {              "Type":  "AWS::CloudFormation::Stack",              "Properties":  {                  "TemplateURL":  {                      "Fn::Join":  [  "",                          [  "https://s3.amazonaws.com/drupaljam.",  {  "Ref":  "AWS::Region"  },".",  {  "Ref":  "EnvironmentName"  },  "/cloudformation/",  "cache.template"  ]                      ]                  },

Page 29: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Example→Make a Scalable Static Hosted Website that can handle

gradual increase of visitors beyond 2 web servers.→Finance wise we are limited to 5 web servers.→PHP, MySQL, Load Balancer.→No Object Caching or Page Caching required

Page 30: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Parameters→database password→ssh key→ssh IP restrictions→etc…

"Parameters"  :  {  !        "KeyName":  {              "Description"  :  "EC2  KeyPair  to  enable  SSH  access  to  the  instances",              "Default"  :  "drupaljam",              "Type":  "String",              "MinLength":  "1",              "MaxLength":  "255",              "AllowedPattern"  :  "[\\x20-­‐\\x7E]*",              "ConstraintDescription"  :  "can  contain  only  ASCII  characters."          },  !        "InstanceType"  :  {              "Description"  :  "WebServer  EC2  instance  type",              "Type"  :  "String",              "Default"  :  "m3.medium",              "ConstraintDescription"  :  "must  be  a  valid  EC2  instance  type."          },  !        "SiteName":  {              "Default":  "Drupal",              "Description"  :  "Drupal  Web  Site",              "Type":  "String"          },

Page 31: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AWS::ElasticLoadBalancing::LoadBalancer→Define Listening Ports→Define Instance Ports→Define Cookie

Stickiness Policies→Defines HealthCheck

so it can take instances out rotation

"ElasticLoadBalancer"  :  {              "Type"  :  "AWS::ElasticLoadBalancing::LoadBalancer",              "Metadata"  :  {                  "Comment"  :  "Configure  the  Load  Balancer  with  a  simple  health  check  and  cookie-­‐based  stickiness"              },              "Properties"  :  {                  "AvailabilityZones"  :  [  "us-­‐east-­‐1b","us-­‐east-­‐1d"  ],                  "LBCookieStickinessPolicy"  :  [  {                      "PolicyName"  :  "CookieBasedPolicy",                      "CookieExpirationPeriod"  :  "30"                  }  ],                  "Listeners"  :  [  {                      "LoadBalancerPort"  :  "80",                      "InstancePort"  :  "80",                      "Protocol"  :  "HTTP",                      "PolicyNames"  :  [  "CookieBasedPolicy"  ]                  }  ],                  "HealthCheck"  :  {                      "Target"  :  "HTTP:80/",                      "HealthyThreshold"  :  "2",                      "UnhealthyThreshold"  :  "5",                      "Interval"  :  "10",                      "Timeout"  :  "5"                  }              }  

Page 32: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AWS::AutoScaling::AutoScalingGroup→Define Minimum &

Maximum→Define Availability

Zones we can use→Define Configuration to

execute

"WebServerGroup1"  :  {              "Type"  :  "AWS::AutoScaling::AutoScalingGroup",              "Properties"  :  {                  "AvailabilityZones"  :  [  "us-­‐east-­‐1b","us-­‐east-­‐1d"  ],                  "LaunchConfigurationName"  :  {  "Ref"  :  "LaunchConfig1"  },                  "MinSize"  :  "1",                  "MaxSize"  :  "5",                  "DesiredCapacity"  :  {  "Ref"  :  "WebServerCapacity"  },                  "LoadBalancerNames"  :  [  {  "Ref"  :  "ElasticLoadBalancer"  }  ],                  "Tags"  :  [                        {                              "Key"    :  "Name",                              "Value"  :  "Drupaljam  Drupal  Instance",                              "PropagateAtLaunch"  :  “true"                        }                  ]              }

Page 33: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AWS::AutoScaling::LaunchConfiguration→Define Packages (apt/yum)→Define Sources to extract

to folders (Drupal)→Define files→Define commands→Define services to run→Execute Script to initialize

"LaunchConfig1":  {              "Type"  :  "AWS::AutoScaling::LaunchConfiguration",              "Metadata"  :  {                  "AWS::CloudFormation::Init"  :  {                      "config"  :  {                          "packages"  :  {                              "yum"  :  {                                  "httpd"  :  [],                                  "php"  :  [],                                  "php-­‐mysql"  :  [],                                  "php-­‐gd"  :  [],                                  "php-­‐xml"  :  [],                                  "php-­‐mbstring"  :  [],                                  "mysql"  :  [],                                  "gcc"  :  [],                                  "make"  :  [],                                  "libstdc++-­‐devel"  :  [],                                  "gcc-­‐c++"  :  [],                                  "fuse"  :  [],                                  "fuse-­‐devel"  :  [],                                  "libcurl-­‐devel"  :  [],                                  "libxml2-­‐devel"  :  [],                                  "openssl-­‐devel"  :  [],                                  "mailcap"  :  []  !                            }                          },  !                        "sources"  :  {                              "/var/www/html"  :  "http://ftp.drupal.org/files/projects/drupal-­‐7.36.tar.gz",                              "/home/ec2-­‐user"  :  "http://ftp.drupal.org/files/projects/drush-­‐7.x-­‐4.5.tar.gz",                              "/home/ec2-­‐user/s3fs"  :  "http://s3fs.googlecode.com/files/s3fs-­‐1.61.tar.gz"                          },  !                        "files"  :  {                              "/etc/passwd-­‐s3fs"  :  {                                  "content"  :  {  "Fn::Join"  :  ["",  [  {  "Ref"  :  "S3Keys"  },  ":",  {"Fn::GetAtt":  ["S3Keys",  "SecretAccessKey"]},  "\n"  ]]},                                  "mode"  :  "000400",                                  "owner"  :  "root",                                  "group"  :  "root"                              },  !                            "/home/ec2-­‐user/settings.php"  :  {                                  "content"  :  {  "Fn::Join"  :  ["",  [                                      "<?php\n",                                      "\n",                                      "$databases  =  array  (\n",                                      "  'default'  =>\n",                                      "  array  (\n",                                      "  'default'  =>\n",                                      "  array  (\n",                                      "  'database'  =>  '",  {  "Ref"  :  "DBName"  },  "',\n",                                      "  'username'  =>  '",  {  "Ref"  :  "DBUsername"  },  "',\n",                                      "  'password'  =>  '",  {  "Ref"  :  "DBPassword"  },  "',\n",                                      "  'host'  =>  '",  {"Fn::GetAtt"  :  ["MasterDB",  "Endpoint.Address"]},  "',\n",                                      "  'port'  =>  '",  {"Fn::GetAtt"  :  ["MasterDB",  "Endpoint.Port"]},  "',\n",                                      "  'driver'  =>  'mysql',\n",                                      "  'prefix'  =>  'drupal_',\n",                                      "  ),\n",                                      "  ),\n",                                      ");\n",                                      "\n",                                      "$update_free_access  =  FALSE;\n",                                      "\n",                                      "$drupal_hash_salt  =  '0c3R8noNALe3shsioQr5hK1dMHdwRfikLoSfqn0_xpA';\n",                                      "\n",                                      "ini_set('session.gc_probability',  1);\n",                                      "ini_set('session.gc_divisor',  100);\n",                                      "ini_set('session.gc_maxlifetime',  200000);\n",                                      "ini_set('session.cookie_lifetime',  2000000);\n"                                  ]]},                                  "mode"  :  "000444",                                  "owner"  :  "root",                                  "group"  :  "root"                              }                          },  !                        "services"  :  {                              "sysvinit"  :  {                                  "httpd"  :  {  "enabled"  :  "true",  "ensureRunning"  :  "true"  },                                  "sendmail"  :  {  "enabled"  :  "false",  "ensureRunning"  :  "false"  }                              }                          }                      }                  }              },              "Properties":  {                  "ImageId"  :  {  "Fn::FindInMap"  :  [  "AWSRegionArch2AMI",  {  "Ref"  :  "AWS::Region"  },                                                      {  "Fn::FindInMap"  :  [  "AWSInstanceType2Arch",  {  "Ref"  :  "InstanceType"  },  "Arch"  ]  }  ]  },                  "InstanceType"  :  {  "Ref"  :  "InstanceType"  },                  "SecurityGroups"  :  [  {"Ref"  :  "WebServerSecurityGroup"}  ],                  "KeyName"  :  {  "Ref"  :  "KeyName"  },                  "UserData"  :  {  "Fn::Base64"  :  {  "Fn::Join"  :  ["",  [                      "#!/bin/bash  -­‐v\n",                      "yum  update  -­‐y  aws-­‐cfn-­‐bootstrap\n",  !                    "#  Helper  function\n",                      "function  error_exit\n",                      "{\n",                      "  /opt/aws/bin/cfn-­‐signal  -­‐e  1  -­‐r  \"$1\"  '",  {  "Ref"  :  "WaitHandle"  },  "'\n",                      "  exit  1\n",                      "}\n",  !                    "#  Install  Apache  Web  Server,  MySQL  and  Drupal\n",                      "/opt/aws/bin/cfn-­‐init  -­‐s  ",  {  "Ref"  :  "AWS::StackId"  },  "  -­‐r  LaunchConfig1  ",                      "  -­‐-­‐region  ",  {  "Ref"  :  "AWS::Region"  },  "  ||  error_exit  'Failed  to  run  cfn-­‐init'\n",  !                    "#  Install  s3fs\n",                      "cd  /home/ec2-­‐user/s3fs/s3fs-­‐1.61\n",  

Let’s  make  this  bigger  shall  we?

Page 34: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

"LaunchConfig1":  {              "Type"  :  "AWS::AutoScaling::LaunchConfiguration",              "Metadata"  :  {                  "AWS::CloudFormation::Init"  :  {                      "config"  :  {                          "packages"  :  {                              "yum"  :  {                                  "httpd"  :  [],                                  "php"  :  [],                                  "php-­‐mysql"  :  [],                                  "php-­‐gd"  :  [],                                  "php-­‐xml"  :  [],                                  "php-­‐mbstring"  :  [],                                  "mysql"  :  [],                                  "gcc"  :  [],                                  "make"  :  [],                                  "libstdc++-­‐devel"  :  [],                                  "gcc-­‐c++"  :  [],  

                     "sources"  :  {                              "/var/www/html"  :  "http://ftp.drupal.org/files/projects/drupal-­‐7.36.tar.gz",                              "/home/ec2-­‐user"  :  "http://ftp.drupal.org/files/projects/drush-­‐7.x-­‐4.5.tar.gz",                              "/home/ec2-­‐user/s3fs"  :  "http://s3fs.googlecode.com/files/s3fs-­‐1.61.tar.gz"                          },  

                       "files"  :  {                              "/etc/passwd-­‐s3fs"  :  {                                  "content"  :  {  "Fn::Join"  :  ["",  [  {  "Ref"  :  "S3Keys"  },  ":",  {"Fn::GetAtt":  ["S3Keys",  "SecretAccessKey"]},  "\n"  ]]},                                  "mode"  :  "000400",                                  "owner"  :  "root",                                  "group"  :  "root"                              },                              …                      },

Page 35: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

"Properties":  {                  "ImageId"  :  {  "Fn::FindInMap"  :  [  "AWSRegionArch2AMI",  {  "Ref"  :  "AWS::Region"  },                                                      {  "Fn::FindInMap"  :  [  "AWSInstanceType2Arch",  {  "Ref"  :  "InstanceType"  },  "Arch"  ]  }  ]  },                  "InstanceType"  :  {  "Ref"  :  "InstanceType"  },                  "SecurityGroups"  :  [  {"Ref"  :  "WebServerSecurityGroup"}  ],                  "KeyName"  :  {  "Ref"  :  "KeyName"  },                  "UserData"  :  {  "Fn::Base64"  :  {  "Fn::Join"  :  ["",  [                      "#!/bin/bash  -­‐v\n",                      "yum  update  -­‐y  aws-­‐cfn-­‐bootstrap\n”,                    ….  

Page 36: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AWS::RDS::DBInstance→Define size of MySQL

Instance→Define MySQL Version→Define MultiAZ or not

"MasterDB"  :  {              "Type"  :  "AWS::RDS::DBInstance",              "Properties"  :  {                  "DBName"  :  {  "Ref"  :  "DBName"  },                  "AllocatedStorage"  :  {  "Ref"  :  "DBAllocatedStorage"  },                  "DBInstanceClass"  :  {  "Ref"  :  "DBClass"  },                  "Engine"  :  "MySQL",                  "EngineVersion"  :  "5.6",                  "DBInstanceIdentifier"  :  "DrupalJamMasterDB",                  "DBSecurityGroups":  [  {  "Ref":  "DBSecurityGroup"  }  ],                  "MasterUsername"  :  {  "Ref"  :  "DBUsername"  },                  "MasterUserPassword"  :  {  "Ref"  :  "DBPassword"  },                  "MultiAZ"  :  {  "Ref"  :  "MultiAZDatabase"  },                  "Tags"  :  [{  "Key"    :  "Name",  "Value"  :  "Drupaljam  Drupal  Master  Database"  }]              },              "DeletionPolicy"  :  "Snapshot"          },

Page 37: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

AWS::EC2::SecurityGroup→Define Security Levels

between AWS Services→Eg. Only allow traffic

between Load Balancer and Instances on port 80

→Eg. Allow port 22 for the IP range in the inputs

"WebServerSecurityGroup"  :  {              "Type"  :  "AWS::EC2::SecurityGroup",              "Properties"  :  {                  "GroupDescription"  :  "Enable  HTTP  access  via  port  80,  locked  down  to  requests  from  the  load  balancer  only  and  SSH  access",                  "SecurityGroupIngress"  :  [                      {"IpProtocol"  :  "tcp",  "FromPort"  :  "80",  "ToPort"  :  "80",  "SourceSecurityGroupOwnerId"  :  {"Fn::GetAtt"  :  ["ElasticLoadBalancer",  "SourceSecurityGroup.OwnerAlias"]},"SourceSecurityGroupName"  :  {"Fn::GetAtt"  :  ["ElasticLoadBalancer",  "SourceSecurityGroup.GroupName"]}},                      {"IpProtocol"  :  "tcp",  "FromPort"  :  "22",  "ToPort"  :  "22",  "CidrIp"  :  {  "Ref"  :  "SSHLocation"}}                  ]              }          }

Page 38: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

And more…→Make sure to start with VPC→Be Region Agnostic as some are VPC Only→ Internal ELB, Internal IP’s→Private Puppet/Chef Servers→Define Security Model first→Do not create tribal knowledge

Page 39: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more
Page 40: Scaling Drupal in AWS Using AutoScaling, Cloudformation, RDS and more

Thank You