Mostrando las entradas con la etiqueta aws. Mostrar todas las entradas

Bare minimum scalable WordPress

In the past weeks I had a side project to work on. Basically it is to run a WordPress website with the minimum amount of compute resources over low traffic time such as midnight and also be able to scale up once we get an increase of traffic. So at the end this increases the scalability and reliability of the WordPress site.

To reduce the AWS utilization on the elasticloadbalancers (ELB) and the RDS database I've put a memcached in the computing EC2 instances and CloudFlare as the CDN for the static content.

The general architecture is as follows:
AWS Scalable WordPress architecture

First question I had about this to deliver the best performance possible with the minimum amount of resources was to select which AWS region to use. While looking at the traffic data, most of the traffic can be delivered with the lowest latency possible using Oregon (us-west-2).
Second step was to start provisioning the public and private subnets. This is because we don't want to expose anything but only the load balancer that is allocated inside the public subnet.
Then a little consideration about migrating the mariadb database. Both source and destination databases must be running the same version.

After the dump and import on RDS, next step was to move the wordpress files to the destination AWS storage. I chose EFS with bursting performance as the baseline, since I just want to see the overall performance with the lowest settings possible. For this I've provisioned also the EFS filesystem into two availability zones and then copied everything over with the help of a EC2 instance.

Also an important note is that I had to adjust the wp-config.php file to use the WP_HOME and WP_SITEURL to use the load balancer DNS name. Adjust the database settings and then do a cleanup and reconfiguration of the w3tc plugin.

With this EC2 instance up and running. I've took a snapshot from the EC2 instance to use that as the base AMI for the launch configuration so no need for configuration management needed when launching a new compute resource in the auto scaling group.

And what about putting everything on stress to simulate some traffic load? Well My option was to generate http requests using httperf trying to reach an amount of 3 requests per second and start doing adjustments from that point as the scaling policies.

$ httperf --server theloadbalancer.someavailabilityzone.elb.amazonaws.com --num-conn 1500 --num-cal 1 --rate 3 --timeout 5 --port 443 --ssl

The performance results with a t3a.micro instance:

  • Total: connections 1500 requests 1500 replies 1500 test-duration 504.425 s
  • Connection rate: 3.0 conn/s (336.3 ms/conn, <=12 concurrent connections)
  • Reply status: 1xx=0 2xx=1500 3xx=0 4xx=0 5xx=0
The w3tc WordPress plugin works pretty fine in relation with the database. There's little activity on the connections and the read/write IOPS.

RDS 12h monitoring window
AWS Resources:
  • RDS
  • EC2
  • EFS
  • Elastic Load Balancers
The tools:
  • Terraform
  • Shell
  • Ansible

The helper resources:
So far, I was speaking closely with Aldo Rivadeneira while solving some technical questions and asking for some recommendations for the architecture and overall solution. Thanks for your help buddy.


Correct fail2ban filter for sshd on Amazon Linux

Fail2ban does not catch the regular expression for Invalid or Illegal ssh logins on Amazon Linux. So far the fix goes like this:

Not matching regex:
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$

Matching regex:
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>.*\s*$

Enjoy

s3 backend for terraform

Si al usar terraform piensan utilizar el s3 backend para sus terraform state files. Aquí les tengo un consejo: No utilicen una variable para especificar el bucket name en su backend description.

terraform {
    backend "s3" {
        bucket = "${var.s3bucket}"
        key    = "some/key/path/terraform.tfstate"
        region = "eu-central-1"
    }
}

terraform {
    backend "s3" {
        bucket = "s3-backend-bucket"
        key    = "some/key/path/terraform.tfstate"
        region = "eu-central-1"
    }
}

Se ahorrarán unos minutos de su vida intentando figurarse por que falla el provisionamiento.

AWS lambda functions and internal reusable containers

Some time has happened from the last post, but today I have some information that is not relevant to anyone and that's the main purpose of this blog.

Okay this is the deal. I was following one of the amazon web services posts on how-to-receive-alerts-when-specific-apis-are-called-by-using-aws-cloudtrail-amazon-sns-and-aws-lambda. Translated into "my grandmother" language: being alerted when some AWS events are happening.

The flow on how the services work together is shown on this diagram:

Diagram showing how the AWS services from this blog post work together

But why am I writing about this? Well I've faced an issue while building this setup, actually opened a support case with amazon and since I'm not an expert with AWS lambda, they clarified to me some of the lambda nature that cause my function not to work properly.

The expectation: Receive an email once an event happened on AWS coming from route53 each time a bucket object was created
The issue: The email was sent only for the first time the lambda function was invoked, but it didn't send an email on second time and any other subsecuent time
The problem: AWS Lambda reuse their containers to run the code, and the environment variables as well. The cloudtrail.js code use a FILTER_CONFIG global variable, and the logic of the code says that it will run some code if FILTER_CONFIG is empty. But since this global variable is kept on the container, none of the following code is being executed.
The solution: Set the FILTER_CONFIG as empty just at the beginning of the init function. 

After doing this change the lambda function worked just like a charm.