CRUD API Express with RDS, ECS and Docker
Node.js, Docker, ECR, ECS, RDS, Postgres in a single Article
Video Version
Do you prefer the Video Version?
In this article, we will see how we can connect an ECS instance, based on an image on ECR, to an RDS Postgres instance.
Prerequisites
- Docker installed on your machine
- AWS account
Definitions
RDS: Relational Database Service. The AWS service for relational databases such as Postgres. (For more on RDS and Postgres, see my previous article.)
ECR: Elastic Container Registry. Stores Docker images directly on AWS (essentially, an alternative to [Docker Hub](Docker Hub Container Image Library | App Containerization)).
ECS: Elastic Container Service. Deploy and run an application based on an image stored on a registry (it works with both Docker Hub and ECR).
Our Steps Today
- Create an RDS Postgres instance
- Test the instance
- Create the ECR repository using the AWS command line interface
- Clone the repository
- Create the Docker image
- Tag the image accordingly to the ECR repository
- Push the image to ECR
- Create the ECS based on the ECR repository, setting env variables
- Final Test
Create the RDS Postgres Instance
Go on the AWS console and search for RDS:
Then click on Create Database:
Let's create a PostgreSQL instance. We’ll use version 12.5-R1 so we can take advantage of AWS’ free tier:
In Settings, input values for the following:
- DB instance identifier (the name)
- Master user
- Master password + Confirm password (choose a reasonably secure password)
For connectivity, you must be sure that the instance is accessible from the outside. Under Public access, select Yes If you have network issues, check your security group’s inbound rules.
Once you’ve finished, click Create database.
Here is a review of our RDS Postgres instance:
Test the Instance
To test if the RDS instance is accessible, we can use the psql
command. You can also test with other command-like tools like pgadmin
or your local application.
In the command below, replace RDS_INSTANCE_IP
with the one you get from the RDS instance summary:
psql --host RDS_INSTANCE_IP --port 5432 --username postgres
Create the ECR Repository Using the Command Line Interface
ECR stands for Elastic Container Registry, and it's the image registry for AWS. Think about it as a place to store and retrieve your Docker images.
In the AWS Console, type ECR
on the search bar and click on Elastic Container Registry:
The UI interface looks like this:
This is a good way to check your existing repositories. But to create one, we’ll use the command-line interface.
Get your credentials using the command:
aws sts get-caller-identity
Then use the credentials and the region you prefer. eplace with the region of your choice, and replace with your AWS account ID (you can get it with the commands).
aws ecr get-login-password --region <REGION> | docker login --username AWS --password-stdin <AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com
Let's check if the repository has been created by checking the AWS Console:
Nice! Now let's clone and work on the repository.
Clone the Repository
Clone the aws-express-template repository:
git clone https://github.com/tinystacks/aws-docker-templates-express.git
Now, CD into the directory on the command line:
cd aws-docker-templates-express
and open the project with your favorite IDE. If you have Visual Studio Code, you can type:
code .
Check App and Create the Docker Image
If you want to test the project locally, you can install the dependencies (optional - requires npm installed locally):
npm i
To build the projects:
npm run build
npm run start
Before we build the image, let's check the file inside the config folder called postgres.ts
.
Here you can define some environment variables to access your database:
PG_HOST
: The address of the database. We’ll use the RDS instance address here later.PG_PORT
: The port of the database. The default one for Postgres is 5432.PG_USER
: The default user of the databasePG_PASSWORD
: The password for the user of the database.PG_DATABASE
: The database we want to access. Note that a database calledpostgres
is the default for a Postgres instance
To build the image with Docker, use this command:
docker build -t crud-express .
The name doesn't really matter here, as we will retag the local image in order to push it to the ECR repository we will create soon.
Tag the Image to the ECR Repository
To tag the local image in order to push it to the ECR repository, you need to copy the image URI. For example, you can copy it from the Amazon Console’s list of your repositories in ECR:
docker tag crud-express <AWS_ECR_REPO_URI>
Push the Image to ECR
Just use the same tag as before to push the image tagged locally to your ECR repository:
docker push <AWS_ECR_REPO_URI>
After this, wait a couple of minutes for the push to complete.
Create and ECS Task from the ECR Repository Image
Now comes the interesting part. Since we have both:
- an RDS Postgres instance with public access
an image on the ECR registry
we can create an ECS instance based on the ECR image, and connect it to the RDS instance using the RDS instance's URI by supplying the
PG_HOST
variable to our application.
In the AWS Console, look for ECS:
Let’s use the Console to configure a custom container:
Choose a container name of your choice. Use the ECR URI as your Docker image:
Set the port to 80:
Now a very important step - set the environment variable as follows:
- Key :
PG_HOST
- Value: Your RDS URI so the ECS app can connect to the RDS instance
Next, click on Update:
On Task definition, you can just click Next:
On Define your service, also click Next:
For the cluster, you can choose a name for your cluster and then click Next:
Then you just have to wait a couple of minutes to let AWS create your resources:
Once it's done, click on the task:
Scroll down and copy the Public IP so we can use with with our favorite API tester:
Final Test
To test our application, we will use Postman. First of all, let's check if the app is up and running. Make a GET request at the endpoint AWS_APP_IP:80/ping
:
Now let's make a couple of inserts into the database. Make a PUT request with the following body (title and content) at the endpoint AWS_APP_IP:80/postgresql-item
:
Let's make another one:
Now, to get all the items, make a GET request at the endpoint AWS_APP_IP:80/postgresql-item
:
To get a single item, make the same request appending the id of the item at the end of the url (note that we are not handling errors properly here - this is for demo purposes):
To update an existing item, you can make a POST request to the endpoint AWS_APP_IP:80/posgresql-item/1
, specifying an id and passing a message body:
Let's check that the values were updated:
You can also delete an existing item, making a DELETE request at the endpoint AWS_APP_IP:80/postgresql-item/ID
(e.g. 2):
And with that we’ve successfully validated connecting an ECS task to a Amazon RDS database!