Automating the Deployment of a Highly Available Hosting Environment in WordPress
By: Jay Almers | Senior Cloud Solutions Architect
Recently, TekStream was engaged by a customer to develop an automated method of building out a highly available hosting environment that could serve multiple WordPress websites. The solution should be implemented with Infrastructure as Code (IaC) for simplicity of management and disaster recovery purposes. Additionally, the customer requested a method for the creation and maintenance of WordPress websites on this hosting environment. If you read our blog post about automating the process of gathering and evaluating data in your AWS accounts, you know that we are fans of utilizing automation whenever possible to perform repetitive tasks. After our initial discovery sessions, it was apparent that this project was the perfect candidate for automation using CloudFormation Stacks for provisioning the infrastructure and Ansible for the configuration and management of software.
WordPress is an open-source Content Management System (CMS) that is written in PHP and uses a MySQL database for the storage of content and settings. In order for us to build out the necessary infrastructure to support these WordPress sites, we needed to ensure all the software’s requirements were satisfied.
A team consultation with the customer drove the decision to implement a LAMP stack for this project based on their own familiarity and skill set. “LAMP” is an acronym that is commonly used to refer to the combination of technologies for the creation and delivery of web-based applications, in this case, Linux, Apache, MySQL, and PHP. The Word Press sites would be served on a cluster of EC2 instances running Amazon Linux, Apache 2.4, and PHP 7.4. The database was served by a cluster of Amazon Aurora MySQL instances.
With our list of requirements defined, the TekStream team began developing our Infrastructure as Code “stack” to provision all the backing environment. Using the CloudFormation interface, our customer inputs values for various parameters that the system uses when building out the infrastructure such as desired IP address ranges, the primary fully qualified domain name (FQDN) that will be used for the Cloud Front distribution, number of EC2 instances to provision, and the instance class size for the database cluster to name a few. Execution of this stack results in a new Virtual Private Cloud (VPC) containing multiple EC2 instances in private subnets spanning several Availability Zones (AZ). The EC2 instances are load balanced by an Application Load Balancer (ALB), fronted by a Cloud Front distribution which caches the sites and delivers them from a global network of edge locations and takes advantage of shared persistent storage mounts provided by EFS. Additionally, a cluster of RDS instances that is configured for fault tolerance and automatic failover, provide our environment with a highly available database system. If provisioned manually, all components of this system would take a significant amount of time and effort to configure and implement. Without Infrastructure as Code and CloudFormation, this 15-minute process could take hours to complete with potentially varying results.
Now that our environment has been successfully provisioned, we can now move on to the next part of this project. Ansible is an open-source product of Red Hat that is used for automating the provisioning, configuration, and deployment of software and systems. Ansible is a phenomenal utility that is capable of automating processes and procedures on a single device such as a Cisco router to a fleet of thousands of servers. For this project, we are using Ansible to establish an SSH connection to the instances in our EC2 cluster and then executing a series of commands on our behalf. Our EC2 instances, or “hosts”, are defined in our Ansible configuration as an “inventory”. The group of instructions that tell Ansible what to do, and how to do it, is called a “playbook”. The idea is that any time the customer needs to create a new WordPress website, they will run this playbook and all the tedium and error-prone configuration is handled for them. When the playbook is first run, the user is prompted for customization of the configured parameters such as site title, URL, administrative username, etc. After all parameters have been provided, either by accepting the default values or by entering overriding information, the playbook begins iterating through each configured host in the inventory. First, Ansible connects to the EC2 instance with SSH and verifies the existence of specific packages and ensures they are up to date using the Operating System’s native package manager. Next, a local VirtualHost configuration template is populated with the appropriate details provided by the customized parameters when the playbook was first executed. This customized template is then stored on the persistent EFS storage as an Apache configuration file. Ansible then creates the directory defined in the configuration file as the DocumentRoot on the persistent EFS storage, where the WordPress core files will be downloaded and stored. It then executes several commands using the utility WP-CLI to configure and install the WordPress site with the customized parameters collected at runtime. Since each EC2 instance in our cluster is configured to look in our shared storage mounts for VirtualHost configuration files and site DocumentRoot directories, Ansible only needs to install and configure our sites on a single host. However, Apache needs to be restarted on each host to take advantage of any changes to configuration that may have occurred. The final step in this process, connects to each remaining host in the inventory and restarts Apache. When the whole process is complete, the user is then provided a summary of the tasks that were run as well as the administrative information needed to log into the WordPress admin dashboard.
If you would like more information on automation and how you may be able to leverage it to make your life a little easier, contact TekStream today!