AWS CSA Assoc. [2018] [A.Cloud.Guru] [Udemy] '10 The Real World - Creating a fault tolerant Word Press Site' =============================================================== Fault-tolerant WordPress Site Both Assets and Code stored in S3 buckets, and Posts stored in MySQL, so can terminate instances and nothing is lost. |-------------- VPC (Region 1) ------------------| |----------- WebDMZ SG -------|--- RDS SG -----| Route53 <=> ELB <=> ASG (EC2-1 + EC2-2) <=> MySQL (Prod) | MySQL (Multi-AZ) | CloudFront <=> S3 (Media Assets) S3 (Wordpress Code) ... do all the usual stuff, then MySQL ... # MySQL @ RDS > Create Database > MySQL (check-box) > Next Production MySQL (check-box; for Multi-AZ Deployment) > Next > Specify DB details DB instance class: t2.micro (smallest allowed) Multi-AZ deployment: "Create replica in different zone" (check-box) Storage type: Provisioned IOPS: 1000 Allocated storage: 100 GiB (default) Estimated monthly costs: DB Instance 24.82 USD Storage 25.00 USD Provisioned IOPS 200.00 USD ---------- Total 249.82 USD Multi-AZ deployment: No (check-box) Storage type: General Purpose (SSD) Allocated storage: 20 GiB (default) Estimated monthly costs: DB Instance 12.41 USD Storage 2.30 USD --------- Total 14.71 USD DB instance identifier: (any string) Master Username: Master password: > Next Configure advanced settings - Network & Security Public accessibility: No VPC security groups: "Choose existing VPC security groups" (check-box) > "RDS" (created earlier) ... default @ all others ... - Database options - Encryption - Backup - Monitoring - Log exports - Maintenance > Launch DB Instance # Route53 Hosted Zones > (select domain name) > "Create Record Set" > Name: (www) ... .DOMAINNAME > Type: A - IPv4 address > Alias: yes (if sans 'www'; a.k.a., zone apex a.k.a., naked domain name) > Alias Target: (ELB endpoint, i.e., ELB DNS-Name, else S3 bucket-name, else ...) > Routing Policy: Simple|Weighted|Latency|Failover|Geolocation # EC2 @ EC2 > Instances > Launch Instance > Choose an Amazon Machine Image (AMI) Quick Start (tab) Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type - ami-0ff8a91507f77f867 > Choose an Instance Type t2.micro > Configure Instance Details Number of Instances: 1 Purchasing option: (default unchecked; 'Request Spot instance') Network: (default VPC) Subnet: No preference (default subnet) Auto-assign Public IP: (default;'Use subnet setting') IAM role: 'S3-Admin-Access' (created earlier) Advanced Details > User data #!/bin/bash yum update -y yum install httpd php php-mysql stress -y cd /etc/httpd/conf cp httpd.conf httpdconfbackup.conf rm -rf httpd.conf wget https://s3-eu-west-1.amazonaws.com/acloudguru-wp/httpd.conf cd /var/www/html echo "healthy" > healthy.html wget https://wordpress.org/latest.tar.gz tar -xzf latest.tar.gz cp -r wordpress/* /var/www/html/ rm -rf wordpress rm -rf latest.tar.gz chmod -R 755 wp-content chown -R apache:apache wp-content service httpd start chkconfig httpd on > Next > Tags Name: 'NAT' > Next > Add Storage > Next > Configure Security Group Select an existing security group: (select Public subnet, e.g., WebDMZ) > Review and Launch > Launch # ELB (ALB; App Load Balancer) @ EC2 > LOAD BALANCING > Target Groups > Health checks > Edit Healthy threshold: 2 Unhealthy threshold: 2 Timeout: 5 Interval: 6 > Targets (tab) > Edit (Registered Instancs) (add EC2 Instances to the load balancer) # Wordpress Setup Browse to IP of EC2 to see Wordpress-installed splash screen "Let's go!" (button) Enter database info ... Database Host: (get MySQL endpoint from RDS console) > Submit Copy/paste the PHP code to 'wp-config.php' @ running EC2 instance # Wordpress code copy to S3 ssh ec2-user@EC2_IP_ADDR -i ~/.ssh/aws-ec2-1.pem sudo su aws s3 cp --recursive /var/www/html s3://CODE_BUCKET_NAME # ... 1,000+ objects (php files) # Includes main dir ... /var/www/html/wp-content # Wordpress Login to Wordpress admin, @ URL: DOMAINNAME/wp-admin/ @ WP Admin console > Media - Upload an image file, upon which WP creates ... /var/www/html/wp-content/uploads/YEAR/MONTH/ # dir(s) > Post - add the image file; Update (button); Permalink (click on link) ... opens post-page in new browser tab; see origin is EC2 (not CloudFront) # How to AUTOMATE the process of UPLOADING such NEW CONTENT to CloudFront, and ensuring users are redirected to CloudFront: - 'URL Rewrites'; enabled @ creation of the associated AWS CloudFront distribution; here @ EC2 instance per '.htaccess' file - copy/paste/edit, or whatever, the '.htaccess' file to its Apache-server-expected location vim '/var/www/html/.htaccess' " Options +FollowSymlinks RewriteEngine on rewriterule ^wp-content/uploads/(.*)$ http://CF_DISTRO_PREFIX.cloudfront.net/$1 [r=301,nc] # BEGIN WordPress # END WordPress " - restart web server service httpd restart # restart Apache Server - One-time synch ... aws s3 synch --delete /var/www/html/wp-content/uploads s3://MEDIA_BUCKET_NAME TEST: click on any image @ WP site; observe response URL; origin should be CloudFront - Auto synch per chron utility vim /etc/chrontab " */5 * * * * root aws s3 synch --delete /var/www/html/wp-content/uploads s3://MEDIA_BUCKET_NAME */5 * * * * root aws s3 synch --delete /var/www/html/wp-content s3://CODE_BUCKET_NAME " service chrond restart # restart chron service # AMIs Architect two sets of server Route53 <=> ALB <=> ASG (WP-Prod) <=> MySQL (Prod) |=> ELB <=> ASG (WP-Admin) <=| Admin: write.DOMAIN_NAME One instance (EC2-1) Prod: DOMAIN_NAME Cluster of clone/slave instances - URLs at RDS thru WP Admin page need to be corrected, for WP-Admin domain name; - chron of Prod/clones should DOWNLOAD from S3 (not upload) 1. WP-Admin-AMI; for a singlular instance for admin; content creation, etc; behind an (classic) ELB, or Elastic IP as A-Record target, so static 'write.DOMAIN_NAME' 2. WP-Prod-AMI; for cluster of clones/replicants to copy new code and content from the admin server instance, and respond to user requests Configure both, and then save as AMIs. # Autoscaling Group EC2 > AUTOSCALING > Create Auto Scaling Group > Create Launch Configuration (button) > My AMI > WP-Prod-AMI > Create Auto Scaling Group ... # stress test ssh ... stress --cpu 100 # 100 threads