Flask CRUD API on AWS
Published: 2021-11-29 15:55:06

In this article, we’ll deploy the Flask application we created in the previous article on AWS, using:

- Amazon RDS (Relational Database Service)
- Amazon ECR (Elastic Container Registry)
- Amazon ECS (Elastic Container Service)

Video Version:

[![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638194576828/xmNmpgP7u.png)](https://youtu.be/8rj5LzMPvQw)

## Steps 

- Create RDS instance of Postgres
- Test the RDS instance
- Clone and build the TinyStacks GitHub repository
- Create ECR repository
- Tag the Docker image and push it to the ECR repository
- Deploy to ECS using the ECR image
- Test with Postman (and TablePlus)


### Create RDS Instance

Go to the [AWS Management Console](https://console.aws.amazon.com)onsole and search for RDS: 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611055822/LrRO0ZA_Y.png)

Click on **Create Database**.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611100171/NIz5VTYo5.png)

From the list of available options, select:

- Standard
- Postgres version 12.5
- Free Tier (If you’re a new customer or haven’t used RDS before, you can get up to 750 hours of usage free)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611176264/oAVRsgzol.png)

Choose a name for the instance (basically the name of the database), the master username (postgres), and the password (postgres). Confirm the password. (Make sure to use a more secure password in a production environment!)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611254326/GBsBXyuI9.png)

You can leave the rest as it is, except for **Connectivity**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611433986/4gjKH4YML.png)

We’ll set this up soon. 

You can leave the rest as it is. Just double-check that the estimated monthly cost shows "Free Tier" (assuming you still have Free Tier credits). . Note that the cost of RDS instances may vary over time. 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637611674929/qIcp6PLBz.png)

Then click **Create Database**:

While you wait, click on the database name and on the security group.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637612088779/OGtxnm-zx.png)

Click on the security group id, then on **Edit Inbound rules**. This will let us test our database with an external tool. If you want, you can skip this step. If you do, be sure that both the RDS instance and your app are in the same security group.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637612316878/rFQ0__1ee.png)

Now, add another inbound rule and make the RDS instance accessible:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637612521151/u1vJdcwdg.png)

Now we are ready to test the RDS instance.

### Test the RDS instance

To test the RDS instance, we will use [TablePlus](https://tableplus.com/), but you can use any tool you want. Alternative tools include:

- [pgadmin](https://www.pgadmin.org/)
- [psql](https://www.postgresql.org/docs/13/app-psql.html)

Create a new PostgreSQL connection:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637612696683/JX2zFxDU0.png)

Fill in all the information  required to connect:

- host: (the endpoint of the RDS instance)
- port: 5432
- username: postgres
- password: postgres
- database: postgres

You can disable SSL mode. (But make sure to leave SSL enabled when working in a production environment!)

Click **Test Connection**. If you see a `connection is ok` message, you’re good to go. The database is empty for now. 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637612863833/hGVGtflNX.png)

### Clone the repository, change branch, and build the Docker image

Clone [the aws-docker-templates-flask repository](https://github.com/tinystacks/aws-docker-templates-flask) from Tinystacks: 

```
git clone https://github.com/tinystacks/aws-docker-templates-flask.git
```

Step into the directory

```
cd aws-docker-templates-flask
```

Now, switch your GitHub branch. You can check all the branches with the command `git branch -a`.

```
git checkout flask-local-postgres
```

Then open this folder with your favorite IDE. IF you have Visual Studio code, you can type:

```
code .
```
Open a terminal and, in the folder where the `docker-compose.yml` file is located, type:

```
docker compose build
```

### ECR

Login into your AWS CLI, using your `<AWS_ACCOUNT_ID>` and `<REGION>`:

```
aws ecr get-login-password --region <REGION> | docker login --username AWS --password-stdin <AWS_ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com
```

Create a new ECR repository using the prompt. Use your `<REGION>`:

```
aws ecr create-repository --repository-name flask-app --region <REGION>
```

Then you can check the Amazon Console registries on ECR:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614165719/bZPVFaPI9.png)

If you click on the repository name, you won’t see any images. That’s what we expect (for now).

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614205244/PpO7VKlMl.png)

### Tag and push the Docker image on ECR

You can use the value `<IMAGE_TAG>` to create an image with the tag `latest`.

```
docker tag pythonapp <IMAGE_TAG>
```

Now push the image to the ECR repository: 

```
docker push <IMAGE_TAG>
```

And check the image on the ECR repository:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614585135/K0_cg8FPS.png)


### ECS

Now, let's deploy our service using Amazon Elastic Container Service (ECS). 

Search for `ecs` on the AWS Management Console:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614745786/zZHtl7pRN.png)

Click on **Get Started**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614777189/eDBvXsSz7.png)

Click on Custom and then click **Configure**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614826259/OU7gsk3Zuu.png)

This will let us configure the container task we want to run in our cluster.

Choose:

- Container name: any you want
- Image: the `<IMAGE_TAG>` (latest)
- Port: 80

Next, in **Advanced Configuration** add an environment variable as defined in the `docker-compose.yml` file:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615006835/j4hXd9uac.png)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637614984806/HvL0zmyke.png)

For the values here, use:

- Key: `<DATABASE_URL>`
- Value: `postgresql://postgres:postgres@<RDS_INSTANCE_IP>:5432/postgres`

Remember to replace the database entry with the `<RDS_INSTANCE_IP>` for your instance. You can find your `<RDS_INSTANCE_IP>` on TablePlus or RDS.

Leave the rest as it is and click **Update**.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615311632/7oS6lOqGg.png)

On **Task definition**, click **Next**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615357327/9X_x_a2H4.png)

Likewise, on **Service**, click **Next**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615388152/rhCuyJGNO.png)

On **Cluster configuration**, define a name for your cluster and click **Next**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615622461/B0GxtD0cZ.png)

You’re all set! !Click **Create**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615658246/xjObFj7d2.png)

Creation will take a couple of minutes. Once all the check marks have turned green, click **View Service**:
 
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637615874107/B8gHmWHvE.png)

Click on the task and copy its **Public IP**. We will need that to test our application.

### Test With Postman and Tableplus

First, let’s get all the items. If we get an empty list [], it means that the table has been created and we are getting no items. That’s what we expect, since we just created the table with no data.

GET Request at the endpoint: `/items`

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616027229/DQTCJKE-P.png)

To create a new item, make a POST request at the endpoint `/items`:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616148992/cJUdmhyOv.png)

Let's create 2 more items:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616178954/55LgCea7S.png)


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616194776/mhQJ0j6UU.png)

To get a single item, make a GET request, appending the `id` of the item we want to retrieve at the end of the `/items` path. For example `/items/2` retrieves the item with id = 2.
(Don't mind the body in this request, that was from the last post request.)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616336239/6AlhJaPMF.png)

To update an existing item, make a PUT request. Specify the id of the item we want to modify in the url and the new item in the body of the request:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616457092/yOhbHfDtg.png)

If we try to GET the item 2 again, we’ll receive the updated item:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616498327/l11Eu9GUT.png)

Finally, to delete an existing item - for example, the item with id = 3 - we can make a DELETE quest at the path `/items/3`:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616558361/lhFOsY5Sc.png)

If we try to get all the items again, we only get two:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616651335/f-S4dg5Y1.png)

A final test using TablePlus:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1637616688018/LNpKSpQwP.png)

GitHub Repository (branch: flask-local-postgres): [https://github.com/tinystacks/aws-docker-templates-flask.git](https://github.com/tinystacks/aws-docker-templates-flask)

TinyStacks powers teams to build faster without abstractions or menial DevOps tasks.
Check [TinyStacks](https://www.tinystacks.com/)

Video Version:
[![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1638194576828/xmNmpgP7u.png)](https://youtu.be/8rj5LzMPvQw)