As Quoin reimagines our website, we are also reimagining the infrastructure on which it runs. Our original website uses two Amazon Elastic Compute Cloud (EC2) server instances - one each for the development and production environments, along with storage services and attendant Identity and Access Management (IAM) roles and policies. While this collection of services is functional, it is more than strictly necessary to run a containerized website. In the interest of greater efficiency, enabled by the latest technologies, we are therefore transitioning to AWS Fargate, which allows containerized applications to run without maintaining an underlying server instance.
State of Fargate
Fargate is a launch type within Amazon Elastic Container Service (ECS) that runs containerized applications without requiring maintenance of an underlying operating system or other supporting infrastructure. The arrangement of Fargate tasks follows many of the conventions that are used during local development through docker-compose, although the Amazon documentation often gives links to the Docker Remote API and the corresponding options to the 'docker run' command.
We initially planned to use a Cloudformation template to automate the deployment of all components needed to run the containerized website. However, as some necessary features are not yet supported by Cloudformation, we created an automated deployment strategy using the AWS boto3 Python SDK to circumvent Cloudformation’s limitations. This simplified deployment was a welcome improvement from a more manual approach that used the AWS Command Line Interface (CLI). Logging data from the containers using AWS Cloudwatch was similarly simple to integrate to the Fargate deployment.
The main feature to which we at Quoin are looking forward is the ability to use Cloudformation to create Elastic File System (EFS) access points. But as the Fargate launch type is a recent addition to ECS, some interconnections to other AWS technologies have not yet been added. Fortunately, this should only be a temporary inconvenience. Amazon announced the ability to use EFS with Fargate on April 8, 2020, and an issue in the Cloudformation GitHub repository has been made for the creation of EFS access points through Cloudformation.
We will use a two step deployment until we can unify the process creating the EFS access points for the Fargate tasks with the deployment of the tasks themselves. The first step of our deployment uses Cloudformation to create the necessary file systems, IAM roles and policies, and Fargate tasks and services that do not rely upon EFS for persistent storage. The second step then uses a Python script with boto3 to create the access points for the file systems, the Fargate tasks using the access points, and the Fargate services corresponding to the tasks.
An unexpected benefit has been the simplified Cloudwatch logging afforded by ECS with Fargate. We created a log group in the Cloudformation template and then used that log group within the parameters for creation of the tasks through boto3 with a dedicated stream prefix for each of the tasks. The log group then appears in the AWS on-line console, and the output from each container is found using the stream prefix.
Our experience so far with the Fargate launch type has been positive. We have learned more of the functionality available from the boto3 SDK and simplified the setup of logging from our containers. The deployment process for the access points, tasks, and services is now a single command to run the Python script. Above all else, the transition to Fargate has granted us freedom from concern about the steps required to configure a supporting server instance.
Different Deployment Approaches
Details of Previous Deployment
Our infrastructure for running the original website was created and deployed with Cloudformation and configured with Ansible. The Cloudformation template creates the EC2 instance with the Debian Buster AMI available in the deployment region. The Cloudformation template also creates components such as an IAM role for interacting with the S3 buckets for data backups and a security group for the EC2 instance. Components analogous to these are also created in the new Cloudformation template. The Ansible configuration steps that were required for the EC2 instance, however, have so far been avoided through our new method. These configuration steps included setting up the EBS file system, creating the directories needed for Docker, installing Docker, setting up the environment files for the containers, pulling the Docker images from ECR, and finally building and starting the containers. It is noteworthy that this process does allow one to log in to the instance and examine the state of the running container using the 'docker exec' command, which the move to Fargate prohibits. We have not yet felt any negative impacts from this, and we believe that freedom from configuring the instance outweighs the absence of this ability.
Fargate Deployment Iterations
- We used Cloudformation initially, which allowed the creation of the AWS components necessary to run a node.js container with a Gentics Mesh content management system (CMS) container and a reverse proxy container. At this point none of these tasks used persistent storage, and we were unaware that using EFS access points was not possible through Cloudformation. As discussed previously, many of the components defined in this original Cloudformation remain part of the Cloudformation deployment, including the EFS instances, IAM roles and policies, and the node.js Fargate task and service. This initial investigation also introduced ECS and Fargate concepts and taught us how to translate from docker-compose files used for local development to the parameters expected by ECS.
- The next task was adding persistent storage. This caused the transition to the AWS CLI for creation of the EFS access points and Fargate tasks and services. This iteration required some manual steps for copying the physical IDs for components such as the file systems and security groups into JSON templates for creating the tasks and services.
- An automated process was then needed to simplify the deployment. Quoin is using the boto3 SDK in other projects, and this was an opportunity to explore its use for creating AWS resources. The multi-step AWS CLI process was simplified to a single Python script that created the EFS access points, used them for mounting volumes within the Fargate tasks, and referenced the task definitions in their corresponding Fargate services.
Developers can work with local docker images for the reverse proxy, CMS, and website. When they are ready to see them running remotely, they can push the images to ECR and restart the necessary Fargate services to pull the new image. The Cloudformation deployment is currently stable, but future additions will be deployed by a single command using the AWS CLI. The creation of the EFS access points, Fargate tasks, and Fargate services is similarly simple thanks to the new Python based deployment. If it is necessary to tear down the Fargate services, tasks, and optionally the EFS access points, then that can also be accomplished by passing arguments to the same Python script that is used for deployment.
There are a few tasks remaining before the new infrastructure is finished. We are planning to help developers move faster and replicate the remote environment more closely by splitting the development processes into two phases:
The first phase will allow node.js to run outside of docker, but interact with the containerized reverse proxy and CMS. This is a quality of life improvement, as the developers will no longer need to wait for a Docker image in order to see a change made to the website.
The second phase will containerize the website and run the containerized versions of all of the project components. In this way the developers can check that the containerized components are communicating properly and more closely mimic the remote environment.
The current infrastructure is using S3 buckets for backup and Cloudwatch alarms to alert when things are not going as planned, and we plan to duplicate those features for the new infrastructure. We also plan to investigate the addition of automated steps within the remote containers to verify their ability to communicate with one another prior to running their main activities. Fargate supports container dependencies within a task, but our containers do not share a task as we are currently profiling the resource usage of the individual containers. We may either consolidate the containers into fewer tasks or create these automated steps to verify container communication. We are also planning to simplify the process of restarting the Fargate services when new images are available in ECR.
The deployment process for Quoin's new website is continuing to use Cloudformation to create the necessary AWS components. So far with the transition to Fargate, we have not needed Ansible configuration steps to run the containerized components for the site. We have also learned to use more functionality of the boto3 SDK, and we are using it to deploy the ECS Fargate tasks and services that will run our new website. We no longer need to configure and maintain an underlying server instance in order to run these containerized components, and bringing in the latest changes to the docker images is as simple as restarting the related Fargate services. Our next steps are to configure Cloudwatch alarms and backups to S3, as well as determine how we would like to verify inter-container dependencies and communication. We also hope to unify the deployment through Cloudformation when creation of EFS access points is added, but in the meantime our reimagined deployment strategy shows great promise. By using the latest technologies, Quoin’s website will be able to go serverless, thus simplifying the process of configuration and optimizing functionality.