The Gist: (Updated) I share how run WordPress on AWS Fargate and my reasons that supported that decision. This isn’t meant to be a tech heavy discussion but will touch on the technologies involved. UPDATE: added Terraform files used to create this solution
In my earlier post Why I Love The Cloud I write about how cloud tech is empowering and enabling developers to do more on their own when compared to a few years ago. I offered this WordPress website as an example outlining the technology choices and requirements to get the site on the Internet. In this post I’d like to elaborate more on how this was accomplished to illustrate some advantages of the cloud.
First, lets set the stage and briefly discuss the core technologies in this setup then get a taste of the infrastructural services required to make it all work. The WordPress service is comprised of two components: the web server which hosts WordPress and the database server which hosts MySQL. They are utilizing container technology from Docker and running on virtualized servers that are apart of the AWS Fargate offering.
What is a Docker container and what is AWS Fargate? The concept of containers isn’t new. Control groups (or cgroups) and namespaces are precursors to this and are features of the Linux kernel. CGroups are a way to isolate processes and control the amount of resources consumed. Docker and others enhanced the idea by creating a way to bundle packages of libraries and code.
Docker Container is code and all of its dependencies packaged as a unit (i.e., image) which can be run reliably from one environment to another. When run, these images are “containers” that are isolated from each other and reply on the Docker engine, which is available across many operating systems.
Fargate is a service offering from AWS where you can run containers. You are only charged when your container is consuming CPU and memory.
AWS Fargate is a compute environment for containers that removes the need to provision and manage servers; improves security by isolation – running in their own runtime environment and do not share CPU, memory, or network with other tasks. AWS manages the operational aspects of this service. You specify computing resources you need and pay for when they are in use.
One of the main issues you have to take into account with this setup is that containers are considered temporary when running. Also the images they are based on are immutable and cannot be changed. Why is this important? Any data that is created by the container and remains there will be lost if/when the container terminates or fails for any reason. So with Fargate, while you can offload the database to RDS – the WordPress app itself could not outlive its container. An alternative is to run containers on EC2 servers which is totally fine. BUT I know my site is not doing enough traffic to warrant paying for always-on servers.
AWS recently announced network file system support via their Elastic File System (EFS) service offering, which allows you to connect Fargate containers to storage volumes external to the running environment. This announcement prompted me to give this a try.
Here’s how I’m running WordPress on AWS Fargate:
- The WordPress Service is made up of one ECS task, which is comprised of two containers: WordPress (with Apache/PHP on Linux) and MySQL. Images are available for free on Docker Hub.
- The containers are setup with mounts to an external EFS volume. Specifically different access points (or directories) on this volume. WordPress will mount its access point as /var/www/html and MySQL will mount its access point as /var/lib/mysql. Backups of the volume are regularly scheduled via the AWS Backup service.
- This particular setup allows the containers to share the network interface: WordPress can connect to MySQL by specify localhost:3306. You can think of the setup as two processes on a single machine.
- Containers are configured so that WordPress does not start until MySQL
has startedis ready for connections.
- The containers are protected by being in their own private subnet (no internet access). When WordPress needs to reach out to the internet, its requests are routed to a NAT Gateway, which does not allow incoming traffic.
- The load balancer and NAT Gateway are in the public subnet. They connect to the Internet via the Internet Gateway (not shown). These services are fully managed by AWS.
Requests for my static site are directed to the AWS S3 bucket (nope not a server). Requests for the blog are routed to the load balancer, which forwards requests to the private IP of WordPress. The load balancer has the SSL certificate attached (free! read about it here) so requests come in via HTTPS.
The containers do not have public IP addresses or direct access from the internet – no one can get to them. Security Groups further restrict access and have been configured for the service.
What’s cool about this is that I can mount the EFS volume to an EC2 instance and view both container’s files in their respective directories on the volume. This entire configuration was completed with an IaC tool called Terraform. IaC or “Infrastructure as Code” enabled me to specify the components and configuration. The tool executed the “code” invoking APIs made available by AWS.
Why Would Anyone Want to Run WordPress on AWS Fargate?
For me running WordPress on AWS Fargate is about finding the most cost effective setup was my main driver. I do not expect lots of traffic coming into my site hence, I expect to pay next to nothing for the compute costs. I saw this as an opportunity to save a few hundred dollars a year for a shared hosting services and SSL certs. Serverless computing is becoming a thing!
The example 1 pricing example for Fargate [5 ECS Tasks, running for 10 minutes (600 seconds) every day for a month (30 days) where each ECS Task uses 1 vCPU and 2GB memory] comes in at $1.23 a month for compute charges. My setup is one task, .5 CPU with 1GB of memory. Safe to say my compute cost is practically free. As a comparison, a setup with an EC2 instance with a t2.micro configuration (1 CPU with 1GB of memory) compute cost is $8.30/month or around $100/year whether or not there is traffic to the site. The takeaway: know your needs and situation.
- The total setup is not cost free. The NAT Gateway and Load Balancer are “always on” and have per hour rates and rates for the amount of traffic handled on your behalf. At some point, as an exercise for me 🙂 I will look to swap out use of the NAT Gateway for a small EC2 NAT instance which should be cheaper going from about $0.45/hr for the Gateway vs. $.0116/hr for the EC2. Of course, I’ll need to manage the instance myself. Done! see here
- My “Doh!” moment: I had setup an EFS volume via Terraform, but had failed to configure the container mount properly for the MySQL database. As such, while I thought everything was setup correctly (it was running and functional) – it actually defaulted to storing data in the container. And I lost my very first post when I restarted the service! Lesson: double check everything especially when using a 3rd party tool to work with AWS. Hey, did I check that the Backups are running? 😀
- Pay attention to permissions and IDs used in images. I got this error message trying to kick-off the WordPress container with the external EFS volume mount:
tar: Cannot change ownership to uid 33, gid 33: Operation not permittedThe problem is related to trying to change file ownership of files on network based storage. The image variant I chose was based on Debian Linux which uses a default UID of 33 which corresponds to user www-data as the directory owner. The container ran as a different user so the command failed. Running as the intended user solved the problem. But, I then ran into an issue with that user not having permissions to listen for socket connections. Rather than figure out the command(s) to run in the container, I restarted the container with UID 0 (root user) again since WordPress was now already installed. Yes, I need to look at this but the point is to be aware of the particularities of the images you use. You can always build you own image. For MySQL I had similar issues but overcame them by running the container as user “mysql”.
- Health Checks. There is a natural dependency between WordPress and its database. The database must be able to receive connections in order for WordPress to function properly. I mistakenly set the required status of the MySQL container to START, not realizing that the container itself can start but the process may not be ready. So for this to work the MySQL container must be ready (considered HEALTHY) before the WordPress container tries to connect. Fargate uses health checks and will hold the dependent container from starting until the required status is achieved. For the health check itself I supplied the MySQL command to bring up the command line client, connect to the database, and run a simple select that returned a single result of zero – a zero result signals to Fargate that everything is fine.
I’ve added the Terraform files I used to create this solution – it can be improved upon but that’s a task for another time 😉
task-def.tf: holds task and container definitions
alb.tf: holds information for the application load balancer
variables.tf: holds various IDs referenced throughout