** IF YOU PROVISION THIS ARCHITECTURE THIS WILL COST MONEY!!! THIS WILL TAKE YOU OUT OF THE FREE TIER!!! I'VE TRIED MY BEST TO KEEP COSTS LOW BY USING THE SMALLEST INSTANCE CLASSES ALLOWED AND THE CHEAPEST CONFIGURATIONS. HOWEVER THERE WILL STILL BE COSTS ASSOCIATED. YOU'VE BEEN WARNED!!!!! **
This was a project I did for a prospective client to highlight the advantages of AWS EKS over the use of ECS to improve their deployment process. I also wanted to demonstrate how Ansible and Terraform could work in tandem for provisiong, configuation management, and security compliance. Most of all, I wanted to do all of this with as close to a "Production" level architecture as I could provision without spending the few coins I have AND the provisioning had to be automated.
The project is based on the AWS Whitepaper "Best Practices for WordPress on AWS" which you can download as a PDF here:
AWS Whitepaper: Best Practices for WordPress
Here's the original reference diagram from the whitepaper:
I decided to modify the whitepaper architecture by adding an extra AZ, replacing EC2 instances with an EKS cluster, removing the Bastion Host (LOL) and adding extra functionality with helm charts for ExternalDNS, the AWS Load Balancer Controller, the External Secrets Operator for Kubernetes, and Bitnami's Wordpress for Kubernetes. Here's my version:
Additional services leveraged not included in the whitepaper:
- AWS Certificate Manager (ACM)
- AWS Secrets Manager (AWSSM)
- Intermediate level knowledge of:
- AWS (especially IAM Roles for Service Accounts (IRSA))
- Kubernetes
- Novice level experience working with Wordpress.
- Administror level access to an AWS account and a user that has permissions to provision all services in AWS. Whatever user you use for Terraform should be sufficient.
- A domain in Route 53 that you control with a public zone.
- A FREE certificate created with the ACM for your domain (It's FREE).
- Python ≥ 3.10
- pip and the following python libraries:
- boto3
- pyyaml
- kubernetes
- ansible-core ≥ 2.17
- terraform ≥ 1.9.3
- helm ≥ 3.16.1
- eksctl ≥ 0.189.0
- awscli ≥ v2
- kubectl ≥ 1.30.5
- k9s ≥ 0.30.4 (optional: only if you have experience using it to manage Kubernetes clusters)
Feel free to use my Ubuntu based image that contains all the packages and libraries needed. I've also added my Dockerfile for you to create your own conatiner if you desire.
docker run -it mjsmoov97/wp-project-runenv:latest
git clone git@github.com:mjamalg/wp-project.git
- In vpc-terraform
- providers.tf:
- Change to your desired region
- Add your preferred AWS authentication information to the AWS provider definition.
- providers.tf:
- In eks-ansible
- roles/bitnami-wordpress-install/
- defaults/main.yml:
- Change "cert_domain" to your CERTIFICATE domain name.
- Change "hostname" to whatever you want your wordpress domain to be. It could be your .com or a subdomain. It's your party!
- templates/bitnami-wp-values.j2:
- You can change the wordpress admin default username and password in this file.
- defaults/main.yml:
- roles/eks-addon-config/
- files/external-dns-sa-config.yml:
- Chage the external-dns image version to the latest if desired. v0.15.0 was the latest at the time of publishing. You can find the latest version here: ExternalDNS
- Change the "-domain-filter" value to your domain name.
- Change the Deployment "spec.template.spec.containers.env.name.value" to your desired region.
- defaults/main.yml:
- Change "cert_manager_helm_chart_version" to the desired version. 1.15.3 was the latest at the time of publishing. You can find the lastest version here: cert-manager
- files/external-dns-sa-config.yml:
- roles/bitnami-wordpress-install/
Run the following commands in the vpc-terraform directory:
terraform init && terraform apply -auto-approve
After Terraform is finished provisiong you should have the following resources and services:
- A VPC Resource map that looks similar to this:
- A List of Security groups that look similar to this:
- An Aurora DB cluster using db.t3.medium instances:
- An EFS file system and 2 Access points:
- A 3 node Elasticache/Memcache cluster using cache.t3.micro instances
- A secret in Secrets Manager containing the Aurora DB password
- The folowing users creted in IAM:
- external-secrets with an attached policy called "ESOSecretsManagerPolicy"
- wpcdn with the AWS managed CloudFrontFullAccess policy attached
Run the following commands in the eks-ansible directory to deploy EKS:
ansible-playbook eksctl-config-file-create.yml
eksctl create cluster -f eksctl-config-files/eksctl-config.yml
After EKS is deployed, verify it's running and that you have access to it by running the following commands:
kubectl get nodes
kubectl get namespaces
Run the following command in the eks-ansible directory
ansible-playbook wp-eks-install.yml
The playbook has installed the AWS Load Balancer Controller, the External Secrets Operator (allows access to the Secrets Manager secret as a kubernetes secret), cert-manager, ExternalDNS (synchronizes exposed Kubernetes Services and Ingresses with Route 53) and Bitnami Wordpress for Kubernetes. There are a few things you should see:
Route 53
- A TXT entry created by ExternalDNS
- An A record (with and additional CNAME if you specified a subdomain for your hostname) created by ExternalDNS with an alias pointing to an ALB created by the AWS Load Balancer Controllers
ALB
- There will be 2 load balancers created by the AWS Load Balancer Controller based on the ingress rules in the eks-ansible/roles/bitnami-wordpress-install/files/bitnami-wp-values.yml chart. An application load balancer and a network load balancer.
EKS
After verifying the pods are running check the pod log to make sure apache has started and the pods are accepting connectins from the Wordpress service:
kubectl logs [enter a pod listed from the previous command] -n wordpress
Depending on DNS, your TTL's, or how long it takes for the load balancers status to change to "Active", it may take between 10 minutes and even 2 hours before you'll be able to see the default WP page when you go to your browser:
A full tutorial on how to use and configure Wordpress is beyond the scope of this project. However I will add a couple of pointers for you to help you get started.
- Wordpress uses the W3 Total Cache plugin for Memcached and CDN configuration. The plugin will not work with AWS Elasticache out of the box. A way forward may be found here:
- Here's a link to an excellent tutorial on how to configure the plugin to work with CloudFront. The wpcdn user has been created for you to do this. The Access Key and Secret Access Key for the user will be located in eks-ansible/roles/bitnami-wordpress-install/files/wpcdn-user-credentials.json provided you ran the wp-eks-install.yml playbook successfully.
This gracefully removes the entry made in the Route 53 host zone by ExternalDNS. If you know anything about DNS you know this comes under MUST DO!
helm uninstall my-release --namespace wordpress
Run the following command in the eks-ansible directory:
eksctl delete cluster -f eksctl-config-files/eksctl-config.yml
Run the following command the vpc-terraform directory:
terraform destory -auto-approve