This document covers the steps on setting up this repository on various cloud hosting providers.
Deploying on AWS requires a basic understanding of the following tools and services:
- Docker
- GitHub actions & workflows
- GitHub environments and secrets
- AWS Elastic Container Registry (ECR)
- AWS Elastic Container Service (ECS)
- AWS Virtual Private Cloud (VPC)
- AWS Fargate
- AWS Elastic Load Balancer (ELB)
- AWS Elastic IPs
- AWS Identity and Access Management (IAM)
- AWS Relational Database Service (RDS)
An overview of how the continuous delivery cycle works in Plio with GitHub action and Amazon ECR & ECS.
Follow the steps below to set up the staging environment on AWS.
-
Login to your AWS console.
-
Go to VPC. (skip this step if you've already created a VPC when setting up the frontend repository)
-
Create a new VPC.
-
Name it
plio-staging. -
In IPv4 CIDR block, enter
10.0.0.0/16- this will reserve 256 * 256 IPs within the VPC. -
Click on the create button. You will see the new VPC under the list of VPCs.
-
Check out this AWS guide for more details on VPC.
-
You'll need to attach an Internet Gateway to this VPC.
- Click on
Internet Gatewaysin the VPC Dashboard. - Select
Create internet Gateaway. - Name it as
plio-stagingand save it. - Click on
Attach to a VPCin the next page and select the VPC created above.
- Click on
-
Next, you'll need to attach Subnets to the VPC created above.
- Click on
Subnetsin the VPC Dashboard. - Click on
Create Subnet. - Choose the VPC created above as VPC ID.
- Enter the
Subnet nameasplio-staging-1. - Either choose the
Availability Zoneif you have a preference or leave it to the default - Under
IPv4 CIDR block, add a range of IPv4s that belong to your subnet. If you followed the steps above exactly, you can set this value as10.0.0.0/24. This will reserve the IPs10.0.0.0to10.0.0.255to this Subnet. - If you want to, you can create more subnets using
Add new subnetbut it's not needed going forward. If you do choose to do so, you'll need to choose a different non-overlapping range of IPv4s for theIPv4 CIDR blockoption - for example, you could set it to:10.0.1.0/24to reserve the IPs10.0.1.0to10.0.1.255. - Finally, create the subnet.
- Click on
-
You need to update your
Route Tablesto give make your subnets publicly accessible.- Click on
Route Tablesin the VPC Dashboard - Select the entry corresponding to the VPC you created above.
- Navigate to the
Routestab. - Click on
Edit routes. - Click on
Add route. - Add
0.0.0.0/0as theDestination. - Select
Internet GatewayunderTargetand link to the Internet Gateway you created above. - Click on
Save routes.
- Click on
-
-
Set up the database. Click on
Databaseson the AWS RDS page.- Click on
Create Database. - Use
Standard createthe in database creation method. - Use Postgres12 in the DB engine.
- Under templates, go with
Production. - Name the DB instance identifier as
plio. - Set the master user name and password.
- For DB instance, we can go with Burstable classes to get started with. Select the one having vCPUs & RAM as per your needs.
- Set the alloted storage as per your needs.
- For Availability and Durability, use multi-AZ deployment if you need. Take a note that this may almost double your monthly expense.
- Under VPC settings, select the VPC created in previous step.
- In case you prefer to connect to your database directly from your machine, set the public access to
Yes. - Under additional configuration, set initial database name as
plio_staging. This will create an empty database. - Finally, create the RDS instance by clicking on
Create Databasebutton. - You will see the new RDS instance in the list of RDS instances. Click on your DB instance to see the connectivity settings.
- To connect to RDS from command line, run the following command (this will work if you've set public access to yes):
psql -h your-db-instance-endpoint.aws-region.rds.amazonaws.com -p 5432 -U master_username
- Once you are logged in into the PSQL CLI, you can run all the SQL commands to create a new database, user, grant privileges etc.
- Click on
-
Create a new Elastic IP by going to EC2 dashboard and navigating to the
Elastic IPsection.- Click on
Allocate Elastic IP addressand click onAllocate. - You will see a new IP address in the IPs list. Name it
plio-backend-staging. - This will be used in later steps to give the load balancer a permanent IP address.
- Click on
-
Go to Target groups.
- Create a new target group.
- Choose target type to be
IP addresses. - Name the target group as
plio-backend-staging. - Set the protocol to
TCPand port to80. - Select the
plio-stagingfor the target group VPC. - In the next step, add an IP address in the
IPtext area - the IP address should belong to your VPC - if you followed the steps above exactly, you can use any IP address between10.0.0.0to10.0.255.255. - Proceed to create the target group. You will see the created target group in the list of all target groups.
-
Go to Load Balancers (LBs).
- Create a new load balancer.
- Select
Network Load Balanceroption. We use NLB for easy support of web socket connections. - Name the LB as
plio-backend-staging. - Select the
plio-stagingVPC for the load balancer. - In the subnet mappings, check the first desired zone and use Elastic IP under IPv4 settings for that subnet.
- Under listeners and routing, select the target group
plio-backend-stagingfor TCP port 80. - Proceed to create the load balancer. You will see the created load balancer in the list of all load balancers.
- Enable access logs for your load balancer (optional, recommended for production)
- Go to your S3 dashboard and create a new bucket. Name it as
plio-nlb-logs. - Enable server-side encryption with Amazon S3-Managed Encryption Keys (SSE-S3).
- All public access to be blocked. Click on
Createbutton. - After creating the bucket, edit the bucket policy from
Permissionstab and add the following. Make sure to edit the bucket name below if you have named it different. This policy is to allow bucket put objects permissions to the load balancer logger.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AWSLogDeliveryWrite", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::plio-nlb-logs/*" }, { "Sid": "AWSLogDeliveryAclCheck", "Effect": "Allow", "Principal": { "Service": "delivery.logs.amazonaws.com" }, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::plio-nlb-logs" } ] }- Go back to the load balancer dashboard and select your load balancer.
- Select the load balancer from the list and click on
Edit Attributesfrom theActionsdropdown. - Enable
Access logsoption. - Enter the S3 location you created in previous step. If you want to use same bucket for multiple load balancer access logs, add a sub-directory after S3 bucket name in this step. For example:
plio-nlb-logs/plio-backend-staging.
- Go to your S3 dashboard and create a new bucket. Name it as
-
Go to ECR and create a new repository named
plio-backend-stagingand set the settings as per your needs. -
Now go to ECS and create a new task definition
- Select Fargate and name the task definition as
plio-backend-staging. - Set the task role as
ecsTaskExecutionRole. - Set the task memory and task CPU based on your needs. Good defaults to use are: 2 GB for memory and 0.5 vCPU.
- Create a new container with name
plio-backend-staging. - In the image field, you can just type in
image_arn. This is not a valid entry and just a placeholder for now as it'll be replaced by the actual image ARN once the GitHub workflow triggers. - Enter port
80in the port mapping field. - Use the
.env.examplefile to set all the required environment variables for your container in theEnvironment Variablessection. - Leave the variables
REDIS_HOSTNAMEandREDIS_PORTas empty for now. We'll fill them up later. - Save the container definition and the task definition.
- You will see the new task definition within the list of all task definitions.
- Select Fargate and name the task definition as
-
Under ECS, go to
Clustersand create a new cluster with the nameplio-staging-cluster. (skip this step if you've already created a Cluster when setting up the frontend repository)- Select
Networking only. We will go with serverless deployment so that we don't worry about managing our own server instances. - Don't create a new VPC for your cluster. We'll use the VPC created in previous step in the next step of creating a service.
- Click on the create button.
- You will see the new cluster within the list of clusters.
- Select
-
Get into
plio-staging-clusterand create a new service.- Set launch type to Fargate. We'll use serverless deployments for Plio.
- Name the service as
plio-backend-staging. - Under task definition, select
plio-backend-stagingand use latest revision. - Set the number of tasks to be one.
- Service type to be
REPLICA. - Minimum healthy percentage should be 100 and maximum percent to be 200. Minimum healthy percentage defines the percentage of tasks that should be running at all times. Maximum percent defines how many additional tasks the service can create in parallel to running tasks, before killing the running tasks.
- Deployment type to be
rolling update. - Keep other values as default.
- Use the Cluster VPC and the subnet that you configured previously with Elastic IP.
- Set Auto-assign public IP to
ENABLED. Otherwise, it makes the task accessible only through VPC and not public. - Under load balancing, select the
Network Load Balancingoption and select theplio-backend-stagingload balancer. - Inside
Container to Load Balancer, click onAdd to load balancer optionand selectplio-backend-stagingin the target group. - For auto-scaling, go with
Do not adjust the service's desired countfor staging. - Review and create the service.
-
Create a
rediscluster on AWS Elasticache.- Go to the ElastiCache dashboard. Select the region and click on
Createbutton. - Select
Redisas your Cluster engine. - Select
Cluster mode disabled. More details on cluster mode here. - Choose
Amazon Cloudas your location. - Set the name of your cluster as
plio-redis-staging. - Choose the latest
Engine version compatibility. - Enter
6379as thePort. - No need to change anything for
Parameter Group. - Choose your
Node Type. Plio usescache.t2.micro. More details here. - For
Number of replicas, enter0. Note: Each replica node will carry it's own cost. More on pricing here and here - For high availability, select the
Multi AZcheckbox. Take a note that this may almost double your monthly expense. More details here. - Select
Advanced Redis settingsand fill in the details as mentioned below.- For
Subnet group, create a new group. - Add the subnets that were created above.
- For
VPC ID, add the VPC that was created above. - For
Availability zone(s), chooseNo preference. More details here. - For
Security groupschoose the default security group.
- For
- Click the
Createbutton. - Proceed when the cluster's status becomes
available. Next we'll grant access to the cluster. - Go to the AWS EC2 console here.
- In the navigation pane, under
Network & Security, chooseSecurity Groups. - Choose the
defaultsecurity group for your VPC. - Choose the
Inboundtab, and then do the following:- Choose
Editand selectAdd Rule. - In the
Typecolumn, chooseCustom TCP rule. - In the
Port rangebox, type6379. - In the
Sourcebox, chooseAnywhere. - Click
Save.
- Choose
- Find the endpoints of your redis instance using this and copy them somewhere for later use.
- Enable access logs for your redis instance (optional, recommended for production)
- Switch to the Redis listing screen and click on your redis instance
- Switch to
Logstab. - Click on
Enable slow logbutton. - Select log format as
Text(orJSONif you prefer that). - Select destination type as
CloudWatch Logs. - Set Log destination as
Create newand enter then name of the log group that should be created. For example:/redis/plio-staging. - Click on save and you should see the log status as "enabling". Wait for some time and it should turn to "active".
- Click on
log destinationlink to access the log stream for the redis instance.
- Go to the ElastiCache dashboard. Select the region and click on
-
Connect the redis instance to the
plio-backend-stagingservice that was created above.- Go to the ECS dashboard and select
plio-staging-cluster. - Select the
plio-backend-stagingservice. - Select the
Taskstab. - Select the running task definition in the
Task Definitioncolumn. - Click
Create new revisionbutton on the top and select the existing container with the name:plio-backend-staging. - In the new window, scroll down to
Environment Variablessection. - Update the
REDIS_HOSTNAMEandREDIS_PORTkeys that were copied before. - Click the
Updatebutton to update the environment variables. - Click the
Createbutton to create a new revision of the task definition. - Navigate back to the service
plio-backend-staging. - Click
Updateon top right. - Update the revision of the newly created task definition and wait for it to get initiated.
- After the new revision starts running, stop the older revision.
- Go to the ECS dashboard and select
-
Next, go to your GitHub repository and create a new environment from the settings tab.
- Name the environment as
Staging. - Make sure you have added the following GitHub secrets on repository level. If not, add these as your environment secrets.
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_REGION
- AWS_STORAGE_BUCKET_NAME
- Name the environment as
-
We are using Github Actions to trigger deployments. You can find the workflow defined in
.github/workflows/deploy_to_ecs_staging.yml. It defines a target branch such that a deployment is initiated whenever a change is pushed to the target branch. -
Once done, push some changes to the target branch so that the GitHub workflow
deploy_to_ecs_staging.ymlgets triggered.
Setting up a production environment on AWS is almost the same as staging. Additionally, take care of the following things:
- Rename all services as
plio-backend-productionor a similar naming convention. - Change all the environment variables to the corresponding values for the production environment.
- We chose to use the same RDS instance for production and staging, but a separate user and database for each environment to optimize for cost.
- Once the RDS instance is created after following the step above, create the production DB in the same instance.
- Connect to your RDS instance
psql -h your-db-instance-endpoint.aws-region.rds.amazonaws.com -p 5432 -U master_username
- Ensure that you are in the
psqlshell - now you are connected to your RDS instance. - Create a new database using the
psqlshellpostgres=> CREATE DATABASE plio_production; - Create a new user
postgres=> CREATE USER postgres_prod WITH PASSWORD 'YOUR_PASSWORD'; - Grant the newly created user all the privileges to the production DB
postgres=> GRANT ALL PRIVILEGES ON DATABASE plio_production TO postgres_prod;
- Go with auto-scaling option when creating a new service from ECS.
- When creating a service or when updating it, navigate to the service auto-scaling section.
- Select
Configure Service Auto Scaling to adjust your service's desired count. - Set minimum number of tasks to
1. This is the minimum count of running tasks when scale-in operation happen. - Set desired number of tasks to
1. This may come pre-populated if you had set it before. - Set maximum number of tasks to
2or more based on your desired need. This is the maximum count of total running tasks in case of scale-out operation. - In IAM role for Service Auto Scaling, select
AWSServiceRoleForApplicationAutoScaling_ECSService. - Click on
Add scaling policy. - Select policy type to
Target tracking. - Set policy name to
plio-backend-production-autoscaling-cpu. - In the ECS service metric, select the option for average CPU utilization.
- Target value should be
60(or as per your requirement). This is the threshold value when the service will trigger a new event and perform scale-out operation. - Scale-out & Scale-in cooldown period to be
300seconds. Disable scale-into remain unchecked.- Save the scaling policy.
- Create or update the service name.
- Use k6.io or other load testing tool to check if auto-scaling is working fine or not. You can lower down the target threshold for testing purposes.
