Terraforming a Laravel application using AWS ECS Fargate – Part 1

February 02, 2023

Introduction

Terraform is an open source infrastructure as code(IaC) software tool. We will be using Terraform for creating AWS infrastructure. We can collaborate effectively when we configure the infrastructure using code and commit to our version control systems. We can also execute reviews/suggest new approaches for configuring certain tasks. Additionally, we can spin up new environments(like staging, production etc.) with ease when we use Terraform IaC.

LEMP(stands for Linux, NGINX, MySQL(or MariaDB) and PHP) is a ubiquitous tech stack used for developing and deploying web applications. I prefer NGINX over Apache due to its better performance and its underlying mechanism in handling/processing HTTP(S) requests. LEMP stack is open source, easily customizable/installable, and suits basic/complex web applications. We can run a simple PHP application in the LEMP stack or replace it with a framework like Laravel so that we don’t have to reinvent the wheel. Laravel aids in faster development of web applications.

This series of articles will provide an overview of setting up a LEMP(Laravel) application on AWS Fargate using Terraform and Docker. It will detail the steps needed to configure and deploy them to AWS.

A word of caution. Please note that the following article is not an attempt to dictate the best way to configure the LEMP stack. There are different ways to achieve the same result. AWS infrastructure and Terraform works best for our requirements, YMMV.

Converting Laravel application into Docker containers

Laravel is a batteries-included web application framework that can handle low to a huge influx of users. The configuration/installation of Laravel framework on servers is pretty straightforward. All code/data reside on the same machine, making it easy for deployment (or) thereby removing all the complexities. The challenges and tricky parts pop up while setting up the application to run in a Dockerized environment that utilizes different infrastructure for each service. This challenge is mainly attributed to the monolithic design of Laravel. Building Docker images that are fit for each purpose requires informed decisions and clever scripting techniques. We will build a single image that can be run behind a web server, use it for processing queued jobs and execute scheduled commands.

I mentioned earlier that Laravel framework design is monolithic. This essentially means that web applications, queue workers and schedulers all share the same codebase. Deploying a Laravel application can be easily accomplished when the web application, queue worker and the scheduler is run on a single server. You need to think differently when you run the application in containers – one service in one container i.e. you would require

  1. one container for explicitly running your web application,
  2. another for handling the queue workers,
  3. and the last container for the scheduler.

These containers cannot speak directly to each other as they are run in isolated environments. Hence, the trick is to make sure that the containers use a common codebase and a common medium for communication.

A container should run only one process in it. Several blog posts suggest otherwise when it comes to running LEMP applications i.e. integrate PHP and NGINX or PHP and Apache in a single container. I am personally against this approach. Containers provide many benefits:

  1. The single process isolation makes sure that other processes can’t interfere. The system resources like CPU, RAM etc. are fully available/dedicated for the container.
  2. It’s easier to scale a single container containing only one process.
  3. Components of a container can be upgraded without affecting other containers.
  4. The log collection process will be easier if we run one process in a container. If multiple processes/services are running on the same container, we would need to run another application to segregate logs from the standard out.

We will be using NGINX and PHP-FPM for deploying Laravel web application in AWS Fargate. The whole infrastructure will be provisioned using Terraform. I have only outlined the core functionality/infrastructure needed to run your application. Please make informed decisions depending on your needs.

What services will be used by the application?

  1. AWS Fargate for running our applications.
  2. Amazon RDS for storing persistent data.
  3. Amazon S3 as the object storage.
  4. Amazon Elasticache as the in memory store.
  5. Amazon CloudWatch for all the logging requirements.
  6. Application Load Balancer will route application HTTP requests to the web application.
  7. Docker Hub to host container images.

Containers

Containers package the code and its dependencies together into a single entity. This aids in accelerated development, testing and deployment. Containers make it easy in porting the application to different operating systems. Containers have lower operating costs and utilize resources more efficiently than legacy monolithic applications. LiteBreeze’s goto container management platform is Docker.

Why ECS Fargate?

AWS Fargate’s advantage is the ability to run containers without the overhead of managing servers or clusters. Fargate abstracts the underlying infrastructure, allowing DevOps to only specify the container image, RAM and CPU requirements to run the application.

Terraform

It’s straightforward to launch/setup an Amazon EC2 instance for hosting our web applications. However, the complexity increases when we want to deploy our application in a separate virtual private cloud, load balance it across multiple servers in multiple availability zones. Terraform makes it easy to configure complicated infrastructure. Please have a look at Terragrunt if you require a tool to manage multiple infrastructure environments.

What will we achieve?

  1. The Laravel application will be running in a custom and isolated VPC.
  2. The application will automatically scale up and down depending on the resource utilization.
  3. The application will store persistent data in RDS, utilize S3 as the object storage and process queued jobs using Elasticache Redis.
  4. All the application logs will be processed and stored in CloudWatch.
  5. We will use Terraform and Docker to complete the whole task in a programmatic manner.

Architecture diagram

aws-ecs-fargate-architecture-diagram

Prerequisites

  1. This post will assume that you have basic knowledge of AWS and Terraform.
  2. We will be using a Mac machine for deploying the applications.
  3. Terraform version manager for managing different versions.
  4. Docker for creating/managing containers.
  5. VS code or any other editor for setting up Laravel/Terraform codes.
  6. AWS CLI for infrastructure setup. Create an IAM user with administrative privileges. I would suggest that you fine grain the access depending on your security policy. Please refer to this link for installation instructions. Configure a named profile(link) once the CLI has been installed. I have used litebreeze.

Setup terraform library

Multiple Terraform versions are being used in LiteBreeze at any given point. Hence I prefer tfenv for handling different versions of Terraform. Install tfenv in your development machine as per their documentation.

Create a folder and initialize a Git repo. Create a file called .terraform-version inside the folder. Fill the file with the following content:

1.2.6

Execute the following command to install Terraform v1.2.6

tfenv install

Create the AWS cloud provider file provider.tf and add the following content:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.25"
    }
  }
}

provider "aws" {
  profile = "litebreeze"
  region  = var.aws_region
}

Execute the following command for Terraform to install the cloud providers mentioned in the above file. This needs to be only run for the first time.

terraform init

Commit and push the changes to the repository. All the codes related to the above section are available in this GitHub link.

Posts in this series

Part 1 – Getting started with Terraform
Part 2 – Creating the VPC and ALB
Part 3 – Backing services
Part 4 – Configuring the LEMP stack in Docker
Part 5 – ECS

Leave a Reply

Your email address will not be published. Required fields are marked *