AWS Storage Blog

Running WordPress on Amazon EKS with Amazon EFS Intelligent-tiering

A large percentage of websites today rely on Content Management Systems (CMS) which provide content creators, who may have little to no experience in web development, with the ability to easily publish their content to a website for distribution to their end users. By far, the most popular CMS platform today is WordPress.

More developers are moving to containerized services for portability and ease of deployment of their applications, and WordPress as a CMS platform is no exception. At the same time, organizations are looking for ways to reduce the overall cost of their cloud services. Over time, as data ages, the frequency at which older content is accessed diminishes, which means the number of requests for a particular webpage, blog post, image or video is also reduced.

Amazon Elastic File System (Amazon EFS) offers EFS Intelligent-tiering which enables file data to be automatically moved to lower-cost storage classes as files are less frequently accessed. EFS Intelligent-tiering delivers automatic cost savings for workloads with changing access patterns by placing your file data in the appropriate storage class, at the right time, based on file access patterns.

Leveraging Amazon EFS as a fully managed, auto-scaling file system will allow your CMS data to grow and shrink on demand without having to manage capacity or performance. Additionally, with the new cost optimization features of Intelligent-tiering, EFS will provide enhanced value by delivering optimized capacity, performance and cost to your WordPress deployment.

In this blog, I show you how to quickly deploy a containerized instance of WordPress using the Amazon Elastic Kubernetes Service (EKS) with persistent file storage leveraging EFS with Intelligent-tiering enabled for cost optimization.

Solution architecture

This is a high level diagram of the architecture you will be building, leveraging the AWS services referenced in this post. The diagram depicts the AWS services that comprise a WordPress solution running Amazon EKS on Amazon EC2 instances. The storage layer uses Amazon EFS with both Standard and Infrequent Access storage classes, and Intelligent-tiering enabled. Mount points exist in two AWS Availability Zones (AZs), and an AWS Elastic Load Balancer is used to access the WordPress website from the internet.

WordPress on Amazon EKS with Amazon EFS Intelligent-tiering

Setup

The setup includes creating your EKS cluster and your EFS file system with mount points and access points. Once your AWS infrastructure is created, you will deploy two containers (Pods) that comprise your WordPress website deployment.

Step 1: Create a Kubernetes Cluster with EKS

First you will set up a  Kubernetes cluster on EKS. You can use the eksctl command to do this as it will save a lot of time getting your EKS cluster configured using AWS CloudFormation.

In order to use eksctl you will need to have kubectl and eksctl installed and running locally on your computer. For more information, read the EKS documentation.

Let’s configure your EKS cluster using eksctl.

Using your preferred SSH client, select your AWS account using the following command:

aws configure

Type in your credentials from your EC2 Private Key in your AWS account. For more information on how to get these credentials, and read Amazon EC2 key pairs and Linux instances.

NOTE: for this blog we will be using us-east-1 as the AWS Region for the purpose of demonstration. If you prefer to use a different Region, be sure to use that Region throughout these steps in your own AWS account.

use us-east-1 Region

Create your Kubernetes cluster with the following commands:

eksctl create cluster \
--name eks-wp \
--region us-east-1 \
--zones us-east-1a,us-east-1b \
--managed 

You can watch the progress of the deployment in your AWS console in CloudFormation > Stacks

CloudFormation>Stacks

Once complete, you can view your EKS cluster in the AWS console in Elastic Kubernetes Service > ClustersEKS console Clusters imageNow use the kubectl to view the compute nodes from Kubernetes! (For information about kubectl read the documentation.)

Use the following command to log into your EKS Kubernetes cluster:

aws eks --region us-east-1 update-kubeconfig --name eks-wp

Once logged in, run this command to view your compute nodes:

kubectl get nodes

The node names and status of the Kubernetes compute nodes will be displayed:

Kubernetes node names and status

Now you will create a kustomization.yaml file to allow you to use a secret password for your MySQL and WordPress Pods and enable you to both create and delete your deployment with a single command in kubectl!

First create a new directory where the configuration files will be stored on your local machine.

mkdir eks-wp
cd eks-wp

In your terminal, paste the following and enter.

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
  literals:
  - password=WordPass
resources:  
  - mysql-deployment.yaml  
  - wordpress-deployment.yaml  
EOF

Next, create a deployment file for MySQL that will be used to deploy your MySQL Pod in EKS. Copy and paste the following into your terminal and enter.

cat <<EOF >./mysql-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
EOF

Step 2: Create an EFS file system with Intelligent-tiering

For the WordPress deployment we will use EFS for persistent storage of the WordPress images. In order to do this, you will need to create an EFS file system first.

Create a security group for the Amazon EFS mount target, which requires the VPC ID for the VPC created by eksctl for your cluster.

aws ec2 create-security-group \
--region us-east-1 \
--group-name efs-mount-sg \
--description "Amazon EFS for EKS, SG for mount target" \
--vpc-id(i.e. vpc-00ab3ddf9e831f016)

Next you will need to authorize the inbound access to the security group for the Amazon EFS mount target (efs-mount-sg) to allow inbound traffic to the NFS port (2049) from the VPC CIDR block using the following command using the security group ID outputted from the previous step.

aws ec2 authorize-security-group-ingress \
--group-id (i.e. sg-0169ed1789bf1d872) \
--region us-east-1 \
--protocol tcp \
--port 2049 \
--cidr 192.168.0.0/16

Next, create an encrypted Amazon EFS file system from the console. Navigate to the EFS console and select Create file system. Name your file system WP-FS-INT and select the VPC that corresponds to your EKS cluster. For availability, select Regional, as we want to take advantage of Multi-AZ availability. (Make sure the file system is created in us-east-1 or whichever AWS Region you have selected for your EKS cluster.)

Note: Selecting Customize will reveal that Intelligent-tiering is already selected as the default setting under Lifecycle Management. This will ensure that the infrequently accessed content will be archived to EFS Standard-Infrequent access storage class after 30 days of non-access.

Next you will add the efs-mount-sg security group to each Mount target in your VPC and select Next > Next> Create

Create file system in EFS console

mount targets in EFS console

The last step in finalizing the EFS file system for use with your Kubernetes cluster is to use Amazon EFS Access points. To create an Access point, navigate to Access points on the left side menu and Create access point. Select your file system ID and other parameters as follows. To learn more about working with EFS Access Points read the documentation.

Root directory path: /wordpress

Posix User ID: 1000

Posix Group ID: 1000

Root Owner user ID: 1000

Root group ID: 1000

POSIX permissions: 777

Select Create access point

Deploy the Amazon EFS CSI driver to your Amazon EKS cluster

For the WordPress deployment we will use EFS for persistent storage of the WordPress images by leveraging the CSI driver for EFS.

For more information, you can read about the CSI drivers for EKS.

To deploy the Amazon EFS CSI driver, run the following command. Note: Helm is required for this installation. If you do not already have helm installed, learn about it and download it.

helm repo add aws-efs-csi-driver https://kubernetes-sigs.github.io/aws-efs-csi-driver/
helm repo update
helm upgrade --install aws-efs-csi-driver --namespace kube-system aws-efs-csi-driver/aws-efs-csi-driver

Now you will create the wordpress-deployment.yaml file.

Important! Paste your EFS file system ID and Access point fsap. (i.e. fs-5367904b::fsap-07e317d37bcbfb140) into the YAML file where volumeHandle is specified.

EFS access points in console

cat <<EOF >./wordpress-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: wordpress-efs-pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: efs-sc
  csi:
    driver: efs.csi.aws.com
    volumeHandle: "Your EFS file system ID and Access point fsap:
    (i.e. fs-5367904b::fsap-07e317d37bcbfb140)"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-efs-pvc
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 5Gi
---
apiVersion: apps/v1 
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:php7.1-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wordpress-efs-pvc
EOF

Notice you are using a persistent volume claim for storage in both the WordPress and MySQL deployments to take advantage of AWS persistent storage. This will insure that the website remains stateful and you will not lose data if the Pod crashes or is recreated. For more detailed information on persistent storage for containers, read about storage classes here. Keep in mind that the Amazon EBS CSI driver (which we are using for the MySQL deployment) is automatically installed with eksctl and the Amazon Elastic Block Store (EBS) Storage Class is created in Kubernetes for you!

Now deploy both containers to EKS with the following command:

kubectl apply -k .

You can monitor the deployment with the command:

kubectl get pods --watch

(Select CTL C to exit watch)

Once the containers have successfully been created and the Pods show as  “Running” in Kubernetes, you can get the DNS name of the ELB LoadBalancer by typing the following command:

kubectl get svc wordpress

Note: You may need to wait a few minutes for the EC2 compute instances to register with the newly created LoadBalancer before your site will be accessible.

To ensure the AWS Elastic Load Balancer is in service, go to the EC2 console and select Load Balancers to see the DNS name of the Load Balancer from the console. (This will be the same DNS name you get from the command you just ran.)

Wait for the status to display InService for both EC2 instances and then copy the DNS name into your web browser.

AWS Elastic Load Balancer console

Step 3: WordPress “5-minute install”

The WordPress “5-minute install” should now be ready to configure, completing the deployment process.

Wordpress image

Congratulations! You’ve now deployed your stateful WordPress site to AWS on EKS!

Clean up your environment

To clean up your environment, follow these steps:

1.) Delete the Kubernetes Deployments, Services and Pods:

kubectl delete -k .

2.) Delete the file system: Navigate to EFS, select and delete your WP-FS file system.

3.) Delete file system security group

 aws ec2 delete-security-group \
--group-id (i.e. sg-0169ed1789bf1d872) \
--region us-east-1

4.) Lastly, use eksctl to delete your EKS cluster and all of its dependencies via CloudFormation

eksctl delete cluster eks-wp

Conclusion

Amazon EFS is a simple, serverless, set-and-forget, elastic file system that allows your CMS data to grow and shrink automatically as you add and remove files. It enables you to persist and share data, with zero management required. Additionally, EFS Intelligent-tiering delivers automatic cost savings by placing your file data in the appropriate storage class, at the right time, based on file access patterns to your WordPress deployment.

In this blog, I showed you how to create an Amazon EKS cluster, attach an Amazon EFS file system with Intelligent-tiering enabled, and deploy WordPress. Deploying WordPress on Amazon EKS can dramatically improve the scalability and manageability of your CMS website. By pairing the durability, flexibility and cost savings of EFS Intelligent-tiering with your EKS deployment, you can achieve the goal of creating both a cost-optimized and performance-optimized solution for WordPress that is simple to manage and highly scalable.

Thanks for reading this blog post. If you have any comments or questions, share them in the comments section.

Eric Heinrichs

Eric Heinrichs

Eric Heinrichs is a Solutions Architect at AWS specializing in storage solutions that run in the cloud. Eric is committed to helping customers find new ways to leverage cloud solutions to realize new value for their customers and in their businesses. He has spent close to two decades helping customers build out their infrastructures using enterprise storage solutions and is now passionate about helping them adapt and modernize those infrastructures by leveraging the power of the cloud.