How to run a multi-tenant WordPress platform on Google Kubernetes Engine

As a service provider running WordPress sites, it is all about density, density, density

WordPress is said to run 28% of all websites on the Internet. That is a phenomenal installed base of some 75 million sites. While some of these are massive sites like TechCrunch or The New Yorker, the vast majority of WordPress sites are much smaller.

That means as a WordPress hoster, your business probably follows the 80-20 rule. 80% of your revenue comes from 20% of your sites. Or said another way, 80% of your sites only account for 20% of your traffic.

That means that you need to think about your business in two ways:

  1. You need to provide a reliable service to a large number of low-traffic sites while minimizing infrastructure costs since your margins come in large part by placing more sites on the same physical infrastructure.
  2. You need to provide a white-glove, highly performant and reliable experience to a small number of sites that make up the bulk of your revenue.

At the same time, you need a migration path for some sites to move from low-volume to high-volume plan, without disrupting the customer or your own internal operations teams.

 

..“Our clusters are highly dense, meaning we run a lot of containers per host. On AWS, we use huge instances. The recommendation from Kubernetes is 100 pods per VM. Already, we’re running 200-300 pods per host. Also, since most of the apps that we run are stateful, we can easily have 200-300 volumes per host as well. And we’re working to push these limits even further. Because of these densities enabled by Kubernetes and Portworx, we’re easily saving 60-90% on our compute costs. Portworx itself was between 30-50% cheaper than any other storage solution we tested.”

 

.. If you categorically knew which 20% of your customers would account for 80% of your traffic at all times, solving the noisy neighbor problem would be a one-time migration. But, because traffic patterns change over time, this is a hard problem to solve. Portworx does a few critical things to help.

First, in addition to using Kubernetes to limit pod resources like Memory and CPU, you can use Portworx to automatically place different workloads on different storage hardware for different classes of service. For instance, you might sell your customers a premium “performance” plan if they are expecting heavy usage and they are performance sensitive. Alternatively, cost-conscious customers might opt for a “budget” plan that offers reliability but doesn’t guarantee blazing fast performance. On the backend, these plans can be mapped to Portworx “storage classes” that automatically place high-end plans on SSDs and low-end plans on HHDs.

 

.. Often a hosting customer will call their service provider the day before they are going to be on a national TV and say “I really need my site to work tomorrow.” This often leads to a lot of scrambling around and manual tuning, but with PX-Motion, moving the customer to an environment with more resources is as easy as kubectl apply -f wp-migration.yaml.

The above described moving one heavy load site off a multi-tenant cluster. This is often the best option if you have some advance warning before a large traffic spike. However, in the middle of a large traffic event, it is often better to move low traffic sites away from the heavy traffic site, instead of vice versa. This is also possible with PX-Motion.

Projects on AWS: Build a WordPress Website

Deploy and host a production-ready WordPress website on AWS

In this project, you will learn how to deploy and host WordPress, an open-source blogging tool and content management system (CMS) based on PHP and MySQL. You will implement an architecture to host WordPress for a production workload with minimal management responsibilities required from you. To accomplish this, you will use AWS Elastic Beanstalk and Amazon Relational Database Service (RDS). Once you upload the WordPress files, Elastic Beanstalk automatically handles the deployment, from capacity provisioning, load balancing, auto-scaling to application health monitoring. Amazon RDS provides cost-efficient and resizable capacity, while managing time-consuming database administration tasks for you.

.. The total cost of building a WordPress website will vary depending on your usage and the instance types you select for the web server and database instance. Using the default configuration recommended in this guide, it will typically cost $450/month to host the WordPress site. This cost reflects the minimum resources recommended for a production ready WordPress workload, with only one active web server and a separate Amazon RDS MySQL database instance. The total cost may increase if you use Auto Scaling to increase the number of web server instances in the event of increased traffic to your WordPress site (approximately $75/month for each additional web server assuming that the web server is active for the entire month). To see a breakdown of the services used and their associated costs, see Services Used and Costs.

Multiple WordPress Sites on Docker

See How Containers Help Deploy Web Applications

Moving from a hosting account to a virtual or dedicated server? With add-on domains in cPanel, you could host a virtually unlimited number of sites on your account. A cloud compute instance, such as one from AWS, provides you with a single IP address. As you might know, only one web server can bind to port 80 at a time – so how do you host multiple websites on your own Linux box?

The amount of CPU and RAM on your own server is more than the shared pool of resources normally on a hosting account. If your websites are not extremely high traffic (less than 5,000 visitors/month), why let the excess resources go to waste? An instance with 2 to 4 GB of RAM could easily host multiple WordPress sites.

You can run multiple WordPress websites using a single MySQL database server and virtual hosts configuration in Apache, but nowadays, there’s an easier, more “cloud native” way to achieve the same result: Docker. Docker is a container runtime that gives each application its own user space, complete with process tree and file system, on a single Linux machine.

Reasons to Use Docker to Containerize Traditional Apps

  • Easy to deploy – With Docker, you pull app images directly from a repository with all the dependencies they need built in. In general, each container is responsible for a single service, hence the saying “micro-services architecture.” In the past, a single “monolithic” app would have many components that you would individually need to download the runtimes for.
  • Portable – If any of your containers outgrow the physical infrastructure it lives on, you can use the commands docker commit (create a new image of the container with your additions to the layered file system), docker export (download a tar archive of the container) and docker save (download a tar archive of the attached volumes) to back it up. With a scheduling and orchestration tool such as Docker Swarm or Kubernetes, you can even scale up a service across a Docker cluster with a single command.
  • Secure – Docker containers are isolated from one another, making it difficult for an attacker to gain access to other services from a single compromised application. Unless you are running a container with the –privilegedflag, a container has very limited permissions on the host system, protecting the kernel from a malicious attack.

How to Add a Button to The Gutenberg Editor

Since the documentation is still quite poor (as I write this post), I’m going to explain how to add a custom button to the text blocks of the block editor, so you don’t waste your time and have an easier time than me.

You’ll find all the plugin code that adds a button to the editor in this GitHub repository. Although it’s quite simple, I’m going to explain in more detail the most important parts of this project.

The <span>registerFormatType</span> function is specific to the WordPress core and is the one that allows you to add a new format type, together with the button that triggers the action. You pass a name (<span>'nelio/button'</span>) and a JavaScript object with arguments as parameters. Among those arguments, you have the <span>edit</span>method, which is the one that returns a React Element, which in our case will be the button we want to put in the block.

This button is a RichTextToolbarButton, which is nothing more than a React component of the Gutenberg editor itself that you can find defined here. This component needs an icon (which is an SVG file with Nelio’s logo, in this case), the title of the button, and a function that will be executed when the button is clicked. This function ends up calling the doTheJob function, where the selected text is retrieved and printed in the browser’s console. That’s the place where you can add any JavaScript code you want to handle that selected text.

In the icon attribute of RichTextToolbarButton you can put a string with the name of a WordPress Dashicon instead of the SVG. For the SVG to work, keep in mind that we use the svg-react-loader package that converts SVG files into React elements, which is what this React components need.