Breaking a Monolithic Node.js Application into Microservices
Published: 2024-01-16 10:16:34

 
![](https://i.imgur.com/aacyBbv.png)  


After completing this lab, you should be able to:
- Migrate a monolithic Node.js application to run in a Docker container
- Refactor a Node.js application from a monolithic design to a microservices architecture
- Deploy a containerized Node.js microservices application to Amazon ECS. 
### Task 1: Preparing the Development Environment
- Create cloud9 environment. AWS Cloud9 is a cloud-based integrated development environment (IDE) that you can use to write, run, and debug code on a browser. It comes pre-packaged with essential tools for popular programming languages, and provides access to the AWS Command Line Interface (AWS CLI) in a terminal session tab.  
![[Pasted image 20240111082546.png]]
- In the **AWS Management Console** browser tab, expand **All services**, and then select **Developer Tools > Cloud9**.
- In the **Cloud9-IDE** card, choose **Open IDE**  
    The IDE opens in a new browser tab and displays several tabs, including a **Welcome** tab.
- In the bottom pane of the IDE, enter the following command in the terminal tab
```bash
curl -s https://aws-tc-largeobjects.s3.us-west-2.amazonaws.com/CUR-TF-200-ACACAD-2-91555/16-lab-mod13-guided-1-ECS/s3/lab-files-ms-node-js.tar.gz | tar -zxv
```

This command retrieves a compressed archive file that contains the lab files. It also extracts the file contents in the AWS Cloud9 **~/environment** folder. The command output should like the following example:  
![[Pasted image 20240111083015.png]]  
The downloaded and extracted files are visible in the **Environment** window (in the left pane).  
You can see the following folders:
- **1-no-container** – Contains the files that are related to the _monolithic_ implementation of the application. This implementation is intended to run directly on a Node.js server.
- **2-containerized-monolith** – Contains the files that are related to the _monolithic_ implementation of the application. This implementation is intended to run in a containerized Docker environment orchestrated by Amazon ECS.
- **3-containerized-microservices** – Contains the files that are related to the _microservices_ implementation of the application. This implementation is intended to run in a containerized Docker environment orchestrated by Amazon ECS.

Keep the AWS Cloud9 IDE tab opened throughout this lab, because you will use it frequently.
### Task 2: Running the Application on a Basic Node.js Server
The base Node.js application is a monolithic service that was designed to run directly on a server, without a container.  
In this task, you deploy the application to the Node.js server that is installed on the instance running your AWS Cloud9 environment.  
You then test the application by using the AWS CLI terminal to invoke its RESTful API methods.  
The deployment architecture and request flow are illustrated in the following diagram.  
![[Pasted image 20240111083313.png]]

**Note**: The monolithic implementation of the application uses the Node.js _cluster_ functionality to spawn one worker process per CPU core.  
The processes share a single port, and are invoked in a round-robin way by the load balancer that is built into Node.js. This feature increases scalability on servers that have multiple CPU cores.

In this task, you will:
- Install the Node.js modules required by the application
- Review the application design and code
- Run the application

#### Task 2.1: Installing the Required Node.js Modules
The message board application uses two modules from the Node.js _koa_ framework in its implementation: _koa_ and _koa-router_. _Koa.js_ is a widely used Node.js web application framework that facilitates building asynchronous server-side JavaScript applications.

In the terminal tab, enter the following commands to install the _koa_ and _koa-router_ modules:
```shell
cd ~/environment/1-no-container

npm install koa

npm install koa-router
```
The modules are downloaded and installed in the **1-no-container/node_modules** folder of the AWS Cloud9 **~/environment** folder. You can ignore the notice, warnings, and update messages in the output.
#### Task 2.2: Reviewing the Application Design and Code
The components that implement the monolithic message board application are in the **1-no-container** folder. Review them to gain an understanding of the application design and code.

- In the **Environment** window on the left, expand the **1-no-container** folder. The components of the application include:
    - **node_modules** folder – This folder was created when you installed the required JavaScript modules in the previous subtask. It contains their source code.
    - **db.json** – A JavaScript Object Notation (JSON) object that simulates the message board database. It contains attributes that represent _users_, _threads_, and _posts_, with corresponding sample values.
    - **index.js** – JavaScript program that is the application's entry point.
    - **package.json** – A JSON object that describes the application, its entry point, and its dependencies.
    - **package-lock.json** – A JSON object that was automatically generated when you installed the required JavaScript modules in the **node_modules** folder. It is used by the installation utility, _npm_, to track the modifications that are made to the folder.
    - **server.js** – JavaScript program that defines the application's RESTful API methods, and implements their respective handlers.
- Examine the _package.json_ object. In the **Environment** window, open **package.json** an editor tab by double-clicking it. Notice the following attributes of the JSON object:
    - **Lines 2 through 5** – The _dependencies_ attribute defines the JavaScript module dependencies for the application.  
      Note that the _koa_ and _koa-router_ modules that you installed in the previous subtask are listed here.
    - **Lines 6 through 8** – The _scripts_ attribute declares the _index.js_ program as the entry point to the application.  
      ![[Pasted image 20240111085740.png]]
- Examine the **db.json** object. In the **Environment** window, open **db.json** in an editor tab by double-clicking it. Notice the following attributes of the JSON object:
    - **Lines 2 through 27** – These lines define a _users_ attribute that represents the registered users of the message board. The attribute value is a list of _four_ sample users with the following names: _Marcerline Singer_, _Finn Alberts_, _Paul Barium_, and _Jake Storm_.  
        ![[Pasted image 20240111085822.png]]
    - **Lines 29 through 45** – These lines define a _threads_ attribute that represents the current active threads on the message board. The attribute value is a list of _three_ sample threads with the following titles:  
		![[Pasted image 20240111085959.png]]
        - _Did you see the Brazil game?_
        - _New French bakery opening in the neighborhood tomorrow_
        - _In search of a new guitar_
        - **Lines 47 through 78** – These lines define a _posts_ attribute that represents the posted messages on the active threads. The attribute value is a list of _six_ sample message posts.  
          ![[Pasted image 20240111090023.png]]
1. Review the code for _index.js_. In the **Environment** window, open **index.js** in an editor tab by double-clicking it. Notice the following information:
    - **Lines 1 through 3** – These lines import the JavaScript modules that the program requires, specifically: _cluster_, _http_, and _os_.
    - **Line 3** – This line uses the _os_ module to ask about the number of CPU cores that are available on the server.
    - **Lines 5 through 15** – These lines are run the first time the program is invoked (when the application is started). They create a _Leader_ thread for the cluster and one _worker_ thread for each CPU core that is available on the server.
    - **Lines 16 through 19** – These lines handle each request to the application by invoking the _server.js_ program in the current _worker_ thread.  
      ![[Pasted image 20240111090107.png]]
2. Lastly, review the code for _server.js_. In the **Environment** window, open **server.js** in an editor tab by double-clicking it. Use the comments that are provided in the code to facilitate your understanding of the logic. In particular, notice the following information:
    - **Line 3** – This line imports _db.json_, the JSON object that simulates the database.
    - **Lines 6 through 11** – These lines define a generator function that runs for every request. Its purpose is to print a line that contains the _HTTP method_, _resource path URL_, and _elapsed time_ for each request that is processed.
    - **Lines 13 through 47** – These lines define the application's RESTful API methods and their implementation. Specifically, the application can respond to the following RESTful calls.
        - `GET /api/users`: Returns the collection of _users_ in the database
        - `GET /api/users/:userId`: Returns the information for the _user_ that is identified by _:userId_
        - `GET /api/threads`: Returns the collection of _threads_ in the database
        - `GET /api/threads/:threadId`: Returns the information for the _thread_ that is identified by _:threadId_
        - `GET /api/posts/in-thread/:threadId`: Returns the collection of _post messages_ for the _thread_ that is identified by _:threadId_
        - `GET /api/posts/by-user/:userId`: Returns the collection of _post messages_ for the _user_ that is identified by _:userId_
        - `GET /api/`: Returns the message _API ready to receive requests_
        - `GET /`: Returns the message _Ready to receive requests_
    - **Line 52** – This line defines the _port number_ where the application listens for requests
#### Task 2.3: Running the Application
In this subtask, you will start the Node.js server and run the message board application. Then, you will test some of its RESTful API methods.  
In the terminal tab, start Node.js and the application by entering the following command:
```shell
npm start
```

Once the server is started and the application's entry point, index.js, is run. The first time that index.js is invoked, it creates two cluster threads—Leader and Worker—to process requests.

Next, you will leave the current terminal session active and open a second terminal tab to test the application's RESTful API.  
	In the bottom pane, open a new terminal tab by choosing **(+)** and selecting **New Terminal**. You now have two terminals where you can enter commands.  
In the **right terminal tab**, retrieve the `/api/users` resource by entering the following command:
```shell
curl localhost:3000/api/users
```
The RESTful invocation returns a JSON object that contains the list of _users_ in the message board database.  
![[Pasted image 20240111094123.png]]

Select the **left terminal tab**. You see an output message from server.js that it processed a GET method request on the resource, which is identified by the path `/api/users`. The request took _2_ milliseconds to process.  
![[Pasted image 20240111094352.png]]

Retrieve the information for only the _fourth_ user in database. In the **right terminal tab**, enter the following command:  
``curl localhost:3000/api/users/4``  
A JSON object that contains all the threads in the database is returned  
![[Pasted image 20240111094737.png]]

Next, retrieve all the _threads_ that are currently in the database. In the **right terminal tab**, enter the following command:  
``curl localhost:3000/api/threads``  
![[Pasted image 20240111095230.png]]

Lastly, retrieve all the _posts_ for the _first_ thread in the database. In the **right terminal tab**, enter the following command:  
``curl localhost:3000/api/posts/in-thread/1``  
A JSON object that contains all the threads in the database is returned

Lastly, retrieve all the _posts_ for the _first_ thread in the database. In the **right terminal tab**, enter the following command:  
``curl localhost:3000/api/posts/in-thread/1``

Stop the Node.js server. In the **left terminal tab**, press **CTRL+C** to terminate the server process.  
You have validated that the application responds properly to GET requests. In the next task, you will containerize the application.

### Task 3: Containerizing the Monolith for Amazon ECS

Containers wrap application code in a unit of deployment, which captures a snapshot of the code and its dependencies. They can help ensure that applications deploy quickly, reliably, and consistently, regardless of the deployment environment.

In this task, you will build a container image for the monolithic message board application and push it to Amazon Elastic Container Registry (Amazon ECR). This step prepares the application for deployment to Amazon ECS.

Specifically, you will perform the following steps:
- Prepare the application for Docker containerization
- Provision a repository
- Build and push the Docker image to the repository

#### Task 3.1: Preparing the Application for Docker Containerization
To put the message board application into a Docker container, the following changes must be made to the application:
- Remove the use of the Node.js _cluster_ feature and convert the application to a single-process design.  
  With Docker containers, the goal is to run a single process per container, instead of a cluster of processes.
- Create a _Dockerfile_ for the application. This file is basically a build script that contains instructions about how to build a _container image_ for the application.
	
A container-ready version of the application is provided to you in the **2-containerized-monolith** folder of your AWS Cloud9 environment.  
Take a few minutes to review the files and understand the changes that were made to prepare the application for containerization.

In the **Environment** window on the left, expand the **2-containerized-monolith** folder, and open the **package.json** in an editor tab by double-clicking it.
	
In **Line 7**, notice that the entry point into the application was changed from _index.js_ to _server.js_.  
The _index.js_ file is no longer in the application folder.  
The _index.js_ file contained the initialization logic for the Node.js _cluster_ feature, and you will no longer use that feature.
	
In the **Environment** window, expand the **2-containerized-monolith** folder, and open the **server.js** file in an editor tab by double-clicking it.  
The only difference from the non-containerized version is the addition of **Line 54**, which prints the message _Worker started_ when the application is first started.
	
In the **Environment** window, expand the **2-containerized-monolith** folder, and open the **Dockerfile** in an editor tab by double-clicking it.

This file contains the instructions about how to build the container image for the application.

![[Pasted image 20240113110142.png]]  
Notice the following information:
- **Line 1** – The base image where the container image will be built. Here, it is _alpine-node_, which is a Node.js image.
- **Line 3** – This line sets the working directory of the file system on the image to _/srv_.
- **Line 4** – This line adds the contents of the **2-containerized-monolith** folder (the application folder) to the current working directory of the image's file system (which is set in the previous line).
- **Line 5** – This line invokes the _npm install_ command to install all the application's library dependencies that were declared in the _package.json_ file.
- **Line 7** – This line informs Docker that the container listens on port 3000 when it runs.
- **Line 8** – This line asks Docker to run the command _node server.js_, which starts the application when the image is started.

Now that you understand how the container image for the application will be built, you will next examine where to put the image after it is built.
#### Task 3.2: Provisioning a Repository
Docker container images are intended to be stored in a repository for sharing, version control, and easier management purposes. _Amazon ECR_ makes it easy for developers to store, manage, and deploy Docker container images.  
In addition, Amazon ECR is integrated with Amazon ECS, which enables Amazon ECS to pull container images directly for production deployments.

In this subtask, you will create a repository in Amazon ECR to house the Docker container image for the message board application.

In the **Your environments** browser tab, choose **Services**, and then select **Container > Elastic Container Registry**.
    
The Amazon ECR console opens.
    
In **Create a repository**, choose **Get Started**.
    
In the **Repository name** box, enter `mb-repo`.
    
Choose **Create repository**.
    
A message at the top of the page indicates that the repository was successfully created.
    
**Note:** _Do not close the window that shows the message._ You will use it in the next subtask.

#### Task 3.3: Building and Pushing the Docker Image
You are now ready to build the container image for the application and push it to the Amazon ECR repository that you created.

One useful feature of the Amazon ECR console is that it provides ready-to-use command templates for building and pushing an image to the new repository. You use these provided AWS CLI commands in the next steps.

Before you can successfully run the next steps, you must upgrade the AWS CLI. To do this, go to the **AWS Cloud9 IDE** browser tab, and in the **left terminal tab**, enter the following commands:
```shell
pip3 install awscli --upgrade --user
export PATH=$HOME/.local/bin:$PATH
```
Go back to the **Amazon ECR** console browser tab, and in the message window at the top of the page, choose **View push commands**.
    
The **Push commands for mb-repo** pop-up window opens. This window lists four AWS CLI commands that are customized for the _mb-repo_, and they are purposely built to:
    
- Authenticate your Docker client to your Amazon ECR registry
    - Build your Docker image
    - Tag your Docker image
    - Push your Docker image to the repository

The pop-up window offers two versions of the commands: one for _macOS/linux_, and one for _Microsoft Windows_.

Make sure that the **macOS/Linux** tab is selected, because you will run these commands in your AWS Cloud9 environment.  
First, you will copy and run the command to log in your Docker client to your registry.
	
In the pop-up window, locate the _first_ command and then copy the command to the clipboard by choosing the **Copy** icon.

The command looks like the following example:
```
$ aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 01234567890.dkr.ecr.us-east-1.amazonaws.com/mb-repo
```

![[Pasted image 20240113111016.png]]  
If the command runs successfully, it returns the message _Login Succeeded_. You can ignore the displayed warnings.  
Next, you will build the Docker image for your application.  
**Note**: When a specific terminal tab is not mentioned in an instruction step, use the _left_ terminal tab.
	
In the terminal tab, change the directory to the **2-containerized-monolith** folder by entering the following command:  
	``cd ~/environment/2-containerized-monolith``
	
Switch to the **Amazon ECR** console browser tab.
    
In the **Push commands for mb-repo** window, locate the _second_ command and copy the command by choosing the **Copy** icon.
    
The command looks like the following example:  
``docker build -t mb-repo .``

Switch to the **AWS Cloud9 IDE** browser tab.  
In the terminal tab, paste the copied command and run it by pressing ENTER:  
![[Pasted image 20240113111259.png]]  
The _build_ command produces multiples lines of output as it runs the instructions that are in the application's _Dockerfile_.  
When it is finished, you see the messages _Successfully built nnnnnnnnnn_ and _Successfully tagged mb-repo:latest_.

Next, you will tag the image with the repository URI so that it can be pushed the repository.

Switch to the **Amazon ECR** console browser tab.
    
In the **Push commands for mb-repo** window, locate the _third_ command and choose the **Copy** icon.
    
The command looks like the following example:  
``docker tag mb-repo:latest 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-repo:latest``  
![[Pasted image 20240113111610.png]]  
The command does not return anything if it completed successfully.
    
Finally, you will push the container image to the application's repository.
    
Switch to the **Amazon ECR** console browser tab.
    
In the **Push commands for mb-repo** window, locate the _fourth_ command and copy it.
    
The command looks like the following example:  
``docker push 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-repo:latest``

Switch to the **AWS Cloud9 IDE** browser tab.  
In the terminal tab, paste and run the copied command:  
	![[Pasted image 20240113111751.png]]  
The command outputs several messages as each layer of the image is pushed to the repository.  
Next, you will verify that the image was successfully uploaded.
    
Switch to the **Amazon ECR** console browser tab.  
Close the **Push commands for mb-repo** window.  
 In the **Repositories** list, choose **mb-repo**.  
In the **Images** list, you should see the container image that you pushed, which you can identify by the _latest_ tag.  
![[Pasted image 20240113111958.png]]  
Record the _Image URI_. In the **Images** list, locate the **Image URI** of the _latest_ version of the image, and choose the **Copy** icon. Paste the value in a text editor. You will use it in a subsequent step.

You have successfully created a container image for the message board application, and you have also pushed it to an Amazon ECR repository.
### Task 4: Deploying the Monolith to Amazon ECS

In this task, you deploy the containerized monolithic application to an Amazon ECS runtime environment. Specifically, you use Amazon ECS to create a managed cluster of Amazon Elastic Compute Cloud (Amazon EC2) instances. You will deploy your application container image to this cluster. The cluster is configured as the target group of an Application Load Balancer, which will provide failover and scalability.

The following diagram shows the deployment architecture of the containerized monolithic application. It also displays the resources that you will create in this task.  
![[Pasted image 20240111122506.png]]  
The steps that you perform in this task are:
- Create an Amazon ECS cluster.
- Create a task definition for the application container image.
- Create the Application Load Balancer.
- Deploy the monolithic application as an ECS Service.
- Test the containerized monolithic application.

>[!caution]  
>Before you create an Amazon ECS cluster CREATE a separate VPC and Subnet (with the IP block supplied) under the VPC service.Then return to the ECS window and follow the instructions

#### Task 4.1: Creating an Amazon ECS Cluster
An Amazon ECS cluster is a logical grouping of EC2 instances where you can run tasks or services that represent your containerized application.

In this subtask, you will create an ECS cluster by using the Amazon ECS console. The console's cluster creation wizard enables you to create all the infrastructure components that are needed to create the ECS cluster environment. These components include the virtual private cloud (VPC), subnets, security groups, internet gateway, and AWS Identity and Access Management (IAM) roles.

Go back to the **AWS Management Console** browser tab, choose **Services**, and then select **Containers > Elastic Container Service**.
    
In the navigation pane, choose **Amazon ECS > Clusters**.
    
**Important**: Verify that the new ECS experience toggle button is set to off. The instructions below assume you are using the older ECS experience.
    
In the **Clusters** page, choose **Create Cluster**.
    
In the **Select cluster template** page, select the **EC2 Linux + Networking** card.
    
Choose **Next step**.  
In the **Configure cluster** wizard, configure the following settings.  
	- **Cluster name**: `mb-ecs-cluster`  
    - **Provisioning Model**: _On-Demand Instance_  
    - **EC2 instance type**: _t2.micro_  
    - **Number of instances**: `2`  
    - **VPC**: _Create a new VPC_  
    - **CIDR block**: `10.32.0.0/16`  
    - **Subnet 1**: `10.32.0.0/24`  
    - **Subnet 2**: `10.32.1.0/24`  
    - **Security group**: _Create a new security group_  
    - **Security group inbound rules**: Leave it at the default setting, which allows inbound traffic from all IP addresses on port 80.
    
**Note**: The message in the **Container instance IAM role** section states that you are granting permissions to Amazon ECS to create and use the **ecsInstanceRole**. This role authorizes the EC2 instances in the cluster to invoke Amazon ECS actions.
    
Choose **Create**.
    
The **Launch Status** page opens, and shows the tasks that the wizard performs.  
Wait until all tasks have a check mark, which indicates that they are complete.  
	
The resources that the wizard creates are listed in the **Cluster Resources** section.

Choose **View Cluster**.
    
The details page for the _mb-ecs-cluster_ opens. The **Status** field shows a value of _ACTIVE_.
    
Choose the **ECS Instances** tab.
    
The two EC2 instances for the cluster (which the wizard created) are listed.
    
**Note**: It might take a few minutes for the two EC2 instances to show in the list. If you do not see both instances, choose **Refresh**.  
[image]

Choose the **Tasks** tab.  
No tasks are deployed to the cluster yet. You will create one next.

#### Task 4.2: Creating a Task Definition for the Application Container Image
A task definition is a list of configuration settings for how to run a Docker container on Amazon ECS.  
It tells Amazon ECS various kinds of information, such as:
- What container image to run
- How much CPU and memory the container needs
- What ports the container listens to traffic on  
In this subtask, you will create a task definition for the container image of the message board application.

In the navigation pane of the **Amazon ECS** console browser tab, choose **Task Definitions**.  
Choose **Create new Task Definition**.  
In the **Select launch type compatibility** page, choose the **EC2** card.  
Choose **Next step**.  
The **Configure task and container definitions** page opens.  
In the **Task Definition Name** box, enter `mb-task`.  
Scroll down to **Container Definitions** and choose **Add container**.  
The **Add container** window opens.

Configure the following settings.
- **Container name**: `mb-container`
- **Image**: Paste the **Image URI** of the application container image, which you copied to a text editor in a previous step.
- **Memory Limits**: Select _Hard limit_ and enter `256`. (This setting defines the maximum amount of memory that the container is allowed to use.)
- **Port mappings > Container port**: `3000` (This setting specifies the port where the container receives requests. You do not need to enter a value in **Host port**.)  
The **Add container** window should look similar to the following example:  
[image]

Choose **Add**.  
Scroll down and choose **Create**. You can ignore any warnings.  
A message displays, indicating that the task definition was successfully created. Notice that the definition is automatically assigned the version number of _1_.  
[image]  
You now have a task definition that tells Amazon ECS how to deploy your application container across the cluster.
#### Task 4.3: Creating the Application Load Balancer

Next, you will create the Application Load Balancer that distributes incoming requests to the EC2 instances that run in the ECS cluster. This load balancer resides in the same VPC and uses the same security group as the ECS cluster.

In the **Amazon ECS** console browser tab, choose **Services**, and then select **Compute > EC2**.
    
In the navigation pane, scroll down and select **Load Balancers**.
    
Choose **Create load balancer**.  
The **Select load balancer type** page opens.  
In the **Application Load Balancer** card, choose **Create**.  
The Application Load Balancer creation wizard opens.
    
1. Configure the following settings:
    - **Load balancer name**: `mb-load-balancer`
    - **VPC**: Select the _Amazon ECS cluster VPC ID_. This ID be similar to _vpc-nnnnnnnnnn (10.32.0.0/16)_
    - **Mappings**: Select the first two Availability Zones in the list
        - **Security groups**:
	        - Clear _default_.
	        - Select _EC2ContainerService-mb-ecs-cluster-EcsSecurityGroup_. (This is the security group of your ECS cluster.)
	- **Listener HTTP:80**
	    - Select **Create target group**: _New target group_ (You want the wizard to create a new target group for the load balancer.)  
	        The target group configuration screen opens in a new browser tab.
	        - **Target group type**: Instances
	        - **Target group name**: `mb-load-balancer-target-group`
	        - Leave the protocol settings at their default values of _HTTP_ and _80_. The application expects to be accessed through RESTful HTTP requests.
	        - VPC: Amazon ECS cluster VPC
	        - Expand **Advanced health check settings** and enter the following settings.
	            - **Healthy threshold**: `2` (This setting tells the load balancer that the target is considered healthy if it receives two consecutive successful health checks from it.)
	            - **Timeout**: `5`
                - **Interval**: `6` (This setting increases the frequency of health checks to once every 6 seconds.)
            - Choose **Create target group**.       
    - Return to the _Load balancers_ browser tab
    - Under Listener HTTP:80, refresh the target groups list. Select the **mb-load-balancer-target-group** you just created.
    - Scroll to the bottom of the page and choose **Create load balancer**.  
        A message should indicate that the load balancer was successfully created.  
Choose **Close**.  
The _mb-load-balancer_ is now in the load balancer list.
    
Wait a few moments, then choose the **Refresh** icon. The **State** of the load balancer should change to _active_.  
[image]

To complete the load balancer configuration, you will modify its security group to open the ports that allow internal communication between the load balancer and the instances in the ECS cluster.
    
In the **Description** tab at the bottom, scroll down to the **Security** section.
    
Next to **Security Groups**, choose the security group ID link, which should be similar to _sg-nnnnnnnnnn_.
    
The details page of the load balancer's security group opens.
    
To copy the security group ID to the clipboard, go to the **Details** tab (in the bottom pane), hover your pointer over the **security group ID**, and choose the **Copy** icon.
    
You will use this ID in a subsequent step.
    
In the bottom pane, select the **Inbound rules** tab.
    
The inbound rules for the security group are displayed.
    
Choose **Edit inbound rules**.
    
The **Edit inbound rules** dialog window opens.

Choose **Add rule**.  
A new line appears in the rules list so that you can add a new rule. It is already preconfigured for a _Custom TCP Rule_, which is the type that you want to add.
    
In the new line, add the following configuration.
- **Port Range**: `31000-61000`
    - **Source > Custom**: Paste the security group ID from the clipboard.  
Choose **Save rules**.  
The security group's inbound rules list shows the new rule that you added.  
[image]

#### Task 4.4: Deploying the Monolith as an ECS Service

You have created all the required Amazon ECS infrastructure components. In this subtask, you will deploy the containerized monolithic application to the cluster as an Amazon ECS service.

An ECS service enables you to simultaneously run and maintain a specified number of task definition instances in an ECS cluster. If one of the tasks fails or stops for any reason, the ECS service scheduler launches another task definition instance to replace it. Thus, it will maintain the desired count of tasks that were specified in the service.

You will now create an ECS service for the message board application's task definition by using the Amazon ECS console.

In the **AWS Management Console** browser tab, choose **Services**, and select **Containers > Elastic Container Service**.
    
In the navigation pane, choose **Task Definitions**.
    
In the **Task Definition** list, choose the **mb-task** link.
    
A page opens with the available revisions of the task definition.
    
Select **mb-task:1** and choose **Actions > Create Service**.
    
In **Step 1: Configure service**, configure these settings.
    
- **Launch type**: _EC2_ (You are running the containerized application directly on a cluster of EC2 instances.)
    - **Service name**: `mb-ecs-service`
    - **Service type**: _REPLICA_ (This setting establishes a scheduling strategy that places and maintains the desired number of tasks across the ECS cluster.)
    - **Number of tasks**: `1` (Normally, to take full advantage of the cluster, you would enter a higher number, depending on the request load that you expect. However, to keep things simple in this exercise, you specify that you want to launch and maintain one task on the cluster at all times.)  
Choose **Next step**.
    
In **Step 2: Configure network**, configure the following settings.
    
- **Load balancer type**: _Application Load Balancer_ (You want the tasks in your service to be load balanced by the _mb-load-balancer_ that you set up earlier)
    - **Service IAM role**: _Create new role_
    - **Load balancer name**: _mb-load-balancer_
    - **Container name:port**: This field is already populated with the correct container information that is associated with the task definition. Choose **Add to load balancer**. (This setting will associate the container with one of the load balancer's listeners.)
    - **Production listener port**: _80:HTTP_ (This setting associates the container with the load balancer listener for HTTP traffic on port 80)
    - **Target group name**: _mb-load-balancer-target-group_  
Choose **Next step**.
    
In **Step 3: Set Auto Scaling (optional)**, choose **Next step**. You do not want to configure any additional automatic scaling.
    
In the **Review** page, make sure that the settings are correct and choose **Create Service**.
    
The **Launch Status** page opens, and shows the tasks that the wizard performs.
    
Wait until all tasks display check marks, which indicate that they are complete.  
[image]  
To open the details page for _mb-ecs-service_, choose **View Service**.

The **Tasks** tab shows that there is now one task that is running the container, with a status of _ACTIVATING_.
    
After a few moments, choose **Refresh**. The task's **Last status** should show: _RUNNING_.  
[image]  
You have successfully deployed the containerized monolith as an ECS service into the cluster.

#### Task 4.5: Testing the Containerized Monolith
You will now validate your deployment by testing the RESTful API methods of the message board application from a web browser.  
First, you will find and record the URL of the load balancer.

In the **Amazon ECS** console browser tab, choose **Services**, and select **Compute > EC2**.  
In the navigation pane, scroll down and choose **Load Balancers**.  
The load balancer list shows the **mb-load-balancer**.  
In the **Description** tab at the bottom, go to **DNS name** and choose the **Copy** icon.  
Paste the DNS name value into a text editor, and label it `Load Balancer DNS Name`. You will use this value multiple times in later steps.  
Open a new browser tab, paste the DNS name into the address bar, and press ENTER.

The page opens with the message _Ready to receive requests_. This message is returned by the message board application when no resource path is included in the GET request.

**Troubleshooting tip**: If you get a server-related HTTP error code, wait a few moments and then try again. It might take a few minutes for the container to register as healthy and begin receiving traffic.

In the browser address bar, add `/api` to the end of the URL and press ENTER.  
[image]  
The application should return the message _API ready to receive requests_.

Test the retrieval of all _users_ in the database. In the browser address bar, add `/users` to the end of the URL and press ENTER.  
[image]  
The application returns a JSON object that lists the four users in the database.

Retrieve the information for the _first user_ in the database. In the browser address bar, add `/1` to the end of the URL and press **Enter**.  
[image]  
The application returns a JSON object that contains the information for _Marcerline Singer_, who is the first user in the database.

Next, you will retrieve all the _threads_ in the database. In the browser address bar, change the URI after the load balancer DNS name to `/api/threads` and press ENTER.  
The application returns a JSON object that contains the three threads in the database.

Finally, retrieve the _posts_ for the _second thread_ in the database. In the browser address bar, change the URI after the load balancer DNS name to `/api/posts/in-thread/2` and press ENTER.  
[image]  
The application returns a JSON object that contains the posted messages for the second thread in the database. The messages are bakery-related.

Optionally, invoke other resource paths that the application can serve. When you are finished testing, close the application browser tab.  
You have now successfully containerized the monolithic message board application and deployed it to an Amazon ECS environment.

### Task 5: Refactoring the Monolith
In this task, you will break the containerized monolithic message board application into several interconnected microservices. You will then push each microservice image to an Amazon ECR repository. Each microservice performs a single business capability of the application, and can be scaled independently of the other microservices. The application is divided into the following microservices, which represent the top-level classes of objects that the application's API serves:
- _Users_ microservice – A service for all _user_-related REST paths (`/api/users/*`)
- _Threads_ microservice – A service for all _thread_-related REST paths (`/api/threads/*`)
- _Posts_ microservice – A service for all _post_-related REST paths (`/api/posts/*`)

To expedite the refactoring, a microservices version of the application is provided to you in the **3-containerized-microservices** folder of your AWS Cloud9 environment.

The steps that you perform in this task are:
- Review the refactored microservices application
- Provision an Amazon ECR repository for each microservice
- Build and push the images for each microservice
#### Task 5.1: Reviewing the Refactored Microservices Application
In this subtask, you will Take a few minutes to review the files to help you understand the changes that were made to refactor the application into microservices.

Switch to the **AWS Cloud9 IDE** browser tab.  
	
In the **Environment** pane on the left, expand the **3-containerized-microservices** folder.  
This folder now has three separate subfolders named **posts**, **threads**, and **users**, which represent the three application microservices. Each subfolder contains the implementation files for the corresponding microservice. 
	
Expand the **posts**, **threads**, and **users** subfolders.  
[image]  
Notice that each subfolder contains a copy of the same application files as those of the containerized monolith application. The _db.json_, _Dockerfile_, and _package.json_ files in each subfolder are identical to their containerized monolith counterparts. The _server.js_ file is the only file that changed from the refactoring.
	
In the **users** subfolder, open **server.js** in an editor tab by double-clicking it.  
**Lines 13 through 20** differ from the containerized monolith version in that the program defines only the API methods and implementations that are related to the _users_ resource paths.
	
In the _Threads_ subfolder, open **server.js** in an editor tab by double-clicking it.  
**Lines 13 through 20** differ from the containerized monolith version in that the program defines only the API methods and implementations that are related to the _threads_ resource paths.
	
In the _posts_ subfolder, open **server.js** in an editor tab by double-clicking it.  
**Lines 13 through 21** differ from the containerized monolith version in that the program defines only the API methods and implementations that are related to the _posts_ resource paths.  
In summary, the only change that is required to refactor the application is to split the RESTful API method handlers in the monolithic version of _server.js_ into three separate _server.js_ files. Each individual _server.js_ file contains a relevant subset of the API method handlers.

#### Task 5.2: Provisioning an Amazon ECR Repository for Each Microservice
Similar to what you did for the containerized monolith version, you will now create an Amazon ECR repository for each application microservice.

You will now create a repository for the _Users_, _Threads_, and _Posts_ microservice container images.

To open the Amazon ECR console, go to the **AWS Management Console** browser tab, choose **Services**, and then select **Containers > Elastic Container Registry**.  
	
Choose **Create repository**.  
	
In **Repository name**, enter `mb-users-repo`.  
	
Choose **Create repository**. A message is displayed at the top of the page indicating that the repository was successfully created.  
	
Repeat the previous steps to create two repositories for the other two microservices, with the following repository information.
- _Threads_ repository name: `mb-threads-repo`
- _Posts_ repository name: `mb-posts-repo`  
When you have created the repositories for all three microservices, the _Repositories_ list should look like the following example:  
[image]

#### Task 5.3: Building and Pushing the Images for Each Microservice

Next, you will build each microservice container image and push it to its corresponding repository. In the following steps, you will use the ready-to-use commands that are provided by the Amazon ECR console to complete the task.
#### **Building And Pushing the _Users_ microservice**
You will start with the container image for the _Users_ microservice.  
Switch to the **AWS Cloud9 IDE** browser tab.  
	
In the terminal tab, change the directory to the **3-containerized-microservices/users** folder by entering the following command:  
``cd ~/environment/3-containerized-microservices/users``
	
Switch to the **Amazon ECR** console browser tab.
	
In the **Repositories** list, select **mb-users-repo**.
	
At the top of the page, choose **View push commands**.  
The **Push commands for mb-users-repo** pop-up window opens.  
First, you will build the Docker image for the microservice.
	
In the **Push commands for mb-users-repo** window, copy the _second_ command to the clipboard by selecting the **Copy** icon next to it. The command should look like:  
``docker build -t mb-users-repo .``  
**Note**: Make sure to include the period (.) at the end of the command.
	
Switch to the **AWS Cloud9 IDE** browser tab.

In the terminal tab, paste the copied command and run it by pressing ENTER.  
	When the command is finished, you should see the messages _Successfully built nnnnnnnnnn_ and _Successfully tagged mb-users-repo:latest_.  
	Next, you will tag the image with the repository URI so that it can be pushed the repository.
	
Switch to the **Amazon ECR** console browser tab.
	
In the **Push commands for mb-users-repo** window, copy the _third_ command to the clipboard by selecting the **Copy** icon next to it. The command should look like:  
``docker tag mb-users-repo:latest 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-users-  repo:latest``

Switch to the **AWS Cloud9 IDE** browser tab.
    
In the terminal tab, paste the copied command and run it by pressing ENTER.  
	The command does not return anything if it completed successfully.  
	Finally, push the container image to the microservice repository.
	
Switch to the **Amazon ECR** console browser tab.
    
In the **Push commands for mb-users-repo** window, copy the _fourth_ command to the clipboard by selecting the **Copy** icon next to it. The command should look like:  
``docker push 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-users-repo:latest``
	
Switch to the **AWS Cloud9 IDE** browser tab.
    
In the terminal tab, paste the copied command and run it by pressing ENTER.  
The command outputs several messages as each layer of the image is pushed to the repository.  
You will now verify that the image was successfully uploaded.
    
Switch to the **Amazon ECR** console browser tab and close the **Push commands for mb-users-repo** pop-up window.
    
Choose the **Refresh** icon.  
In the **Images** list, you see the container image that you pushed identified by the _latest_ tag.
    
Record the _Image URI_. In the **Images** list, locate the _Image URI_ of the _latest_ version of the image and choose the **Copy** icon next to it.
    
Paste the value in a text editor and label it as `Users Image URI`. You will use it in a later step.

#### **Building And Pushing the _Threads_ microservice**
Next, you will build and push the container image for the _Threads_ microservice.

Switch to the **AWS Cloud9 IDE** browser tab. 
	
In the terminal tab, change the directory to the **3-containerized-microservices/threads** folder by entering the following command:  
``cd ~/environment/3-containerized-microservices/threads``
	
Switch to the **Amazon ECR** console browser tab.
    
In the navigation pane, choose **Repositories** and in the **Repositories** list, select **mb-threads-repo**.
    
Choose **View push commands**.  
	The **Push commands for mb-threads-repo** pop-up window opens.  
	First, you will build the Docker image for the microservice.
    
In the pop-up window, copy the _second_ command by selecting the **Copy** icon. The command should look like:  
	``docker build -t mb-threads-repo .``  
	**Note**: Make sure to include the period (.) at the end of the command.
	
Switch to the **AWS Cloud9 IDE** browser tab.
    
In the terminal tab, paste the copied command and run it.  
When the command is finished, you see the messages _Successfully built nnnnnnnnnn_ and _Successfully tagged mb-threads-repo:latest_.  
Next, you will tag the image with the repository URI so that it can be pushed the repository.
	
Switch to the **Amazon ECR** console browser tab.
    
In the pop-up window, copy the _third_ command by selecting the **Copy** icon. The command should look like:  
	``docker tag mb-threads-repo:latest 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-threads-repo:latest``
	
Switch to the **AWS Cloud9 IDE** browser tab.
	
In the terminal tab, paste the copied command and run it.  
The command does not return anything if it completed successfully.  
Finally, you will push the container image to the microservice repository.
	
Switch to the **Amazon ECR** console browser tab.  
 In the pop-up window, copy the _fourth_ command by selecting the **Copy** icon. The command should look like:  
``docker push 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-threads-repo:latest``

Switch to the **AWS Cloud9 IDE** browser tab.
	
In the **Terminal** tab, paste the copied command and run it.  
The command outputs several messages as each layer of the image is pushed to the repository.  
You will now verify that the image was successfully uploaded.
    
Switch to the **Amazon ECR** console browser tab and close the **Push commands for mb-threads-repo** pop-up window.
    
Choose the **Refresh** icon.  
In the **Images** list, you should see the container image that you pushed, which can be identified by the _latest_ tag.
    
Record the _Image URI_. In the **Images** list, go to the _Image URI_ for _latest_ version and choose the **Copy** icon.
    
Paste the value in a text editor and label it as `Threads Image URI`. You will use it in a later step.

#### **Building And Pushing the _Posts_ microservice**
Lastly, you will build and push the container image for the _Posts_ microservice.

Switch to the **AWS Cloud9 IDE** browser tab.
	
In the terminal tab, change the directory to the **3-containerized-microservices/posts** folder by entering the following command:  
``cd ~/environment/3-containerized-microservices/posts``

Switch to the **Amazon ECR** console browser tab.
    
In the navigation pane, choose **Repositories**.
    
In the **Repositories** list, select **mb-posts-repo**.
    
Choose **View push commands**.
    
The **Push commands for mb-posts-repo** pop-up window opens.  
First, you will build the Docker image for the microservice.
    
In the pop-up window, copy the _second_ command. The command should look like:  
``docker build -t mb-posts-repo .``  
	**Note**: Make sure that you include the period (.) at the end of the command.

Switch to the **AWS Cloud9 IDE** browser tab.
    
In the terminal tab, paste and run the copied command.  
When the command is finished, you see the messages _Successfully built nnnnnnnnnn_ and _Successfully tagged mb-posts-repo:latest_.  
Next, you will tag the image with the repository URI so that it can be pushed the repository.
    
Switch to the **Amazon ECR** console browser tab.
    
In the pop-up window, copy the _third_ command. The command should look like:  
``docker tag mb-posts-repo:latest 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-posts-repo:latest``

Switch to the **AWS Cloud9 IDE** browser tab.
    
In the **Terminal** tab, paste and run the copied command.
    
The command does not return anything if it completed successfully.
    
Finally, you will push the container image to the microservice repository.
    
Switch to the **Amazon ECR** console browser tab.
    
In the pop-up window, copy the _fourth_ command. The command should look like:  
``docker push 1234567890.dkr.ecr.us-east-2.amazonaws.com/mb-posts-repo:latest``
	
Switch to the **AWS Cloud9 IDE** browser tab.
    
In the **Terminal** tab, paste and run the copied command.  
The command outputs several messages as each layer of the image is pushed to the repository.  
You will now verify that the image was successfully uploaded.
    
Switch to the **Amazon ECR** console browser tab.
    
Close the **Push commands for mb-posts-repo** pop-up window.
    
Choose the **Refresh** icon.  
In the **Images** list, you should see the container image that you pushed, which should have the _latest_ tag.
	
Record the Image URI. In the **Images** list, copy the _Image URI_ of the _latest_ version of the image.
    
Paste the value in a text editor and label it as `Posts Image URI`. You will use it in a later step.  
You have successfully built container images for the microservices in your application and pushed them to Amazon ECR.

### Task 6: Deploying the Containerized Microservices

In this task, you will deploy the containerized microservices message board application to the same ECS cluster that you used for the containerized monolith. You will also use the same Application Load Balancer from before. However, in this task, you will configure it to route requests to different target groups (one for each microservice container) based on the request URI path.

The following diagram shows the deployment architecture of the containerized microservices application. It also displays the resources that you will create.  
![](https://i.imgur.com/MtxsCTe.png)  
The steps that you perform in this task are:
- Create a task definition for each microservice.
- Configure the Application Load Balancer
- Deploy the microservices as ECS services.
- Validate the deployment.

#### Task 6.1: Creating a Task Definition for Each Microservice
Because the microservices in the application are intended to run independently of each other, they each require their own task definition. In this subtask, you will create three task definitions that run the container image of each individual microservice.

##### **Creating A Task Definition for the _Users_ container**
You will start by creating the task definition for the _Users_ microservice container.

In the navigation pane of the **Amazon ECS** console, choose **Task definitions**, and then choose **Create new Task Definition**.
    
**Note:** You may need to expand the menu in the navigation pane to find **Task Definitions**.
    
In **Step 2: Select launch type compatibility** page, select the **EC2** card.
    
Choose **Next step**.  
In **Step 2: Configure task and container definitions**, configure the following settings:  
    - **Task Definition Name**: `mb-users-task`  
    - Scroll to the **Container Definitions** section and choose **Add container**. In the **Add container** page, enter these settings.  
        - **Container name**: `mb-users-container`  
        - **Image**: Paste the _Users Image URI_ that you copied to a text editor in a previous step.  
        - **Memory Limits**: Make sure that _Hard limit_ is selected, and enter `256`. (This defines the maximum amount of memory that the container is allowed to use.)  
        - **Port mappings > Container port**: `3000` (This specifies the port on which the container receives requests.)  
    - Choose **Add**.
        
Scroll-down and choose **Create**.  
    A message indicates that the task definition was successfully created. Notice that the definition is automatically assigned the version number of _1_.

##### **Creating A Task Definition for the _Threads_ container**
Next, you will create the task definition for the _Threads_ microservice container.  
In the navigation pane, select **Task Definitions** and choose **Create new Task Definition**.
    
In **Step 1: Select launch type compatibility**, select the **EC2** card.
    
Choose **Next step**.
    
In **Step 2: Configure task and container definitions**, configure the following settings.  
    - **Task Definition Name**: `mb-threads-task`.  
    - Scroll to the **Container Definitions** section and choose **Add container**. In the **Add container** page that opens, enter these settings.  
        - **Container name**: `mb-threads-container`  
        - **Image**: Paste the **Threads Image URI** that you copied to a text editor.  
        - **Memory Limits**: Make sure that _Hard limit_ is selected, and enter `256`.  
        - **Port mappings > Container port**: `3000`  
    - Choose **Add**.  
Scroll-down and choose **Create**.  
    A message indicates that the task definition was successfully created. The definition is automatically assigned the version number of _1_.

##### **Creating A Task Definition for the _Posts_ container**

Lastly, you will now create the task definition for the _Posts_ microservice container.

In the navigation pane, select **Task Definitions** and then choose **Create new Task Definition**.
    
In **Step 1: Select launch type compatibility**, select the **EC2** card.
    
Choose **Next step**.
    
In **Step 2: Configure task and container definitions**, configure these settings.  
    - **Task Definition Name**: `mb-posts-task`  
    - Scroll down to the **Container Definitions** section and choose **Add container**. In the **Add container** page, enter these settings.  
        - **Container name**: `mb-posts-container`  
        - **Image**: Paste the _Posts Image URI_ that you copied.  
        - **Memory Limits**: Make sure that _Hard limit_ is selected, and enter `256`  
        - **Port mappings > Container port**: `3000`  
        - Choose **Add**.  
Scroll down and choose **Create**.  
    A message indicates that the task definition was successfully created. The definition is automatically assigned the version number of _1_.
    

#### Task 6.2: Configuring the Application Load Balancer

In this subtask, you will create a new load balancer target group for each microservice so that requests can be routed to their container. You also configure the load balancer listener rule to forward requests to the correct target group, based on the request URI path.
##### **Creating A Target Group for the _Users_ microservice**
In the **Amazon ECS** console browser tab, choose **Services**, and then select **Compute > EC2**.
    
In the navigation pane, scroll down and choose **Target Groups**.
    
Choose **Create target group**.
    
In **Step 1: Specify group details**, configure the following settings.  
    - **Target group name**: `mb-lb-users-target-group`  
    - **VPC**: Select the _load balancer VPC ID_. It should be similar to _vpc-nnnnnnnnnn (10.32.0.0/16)_.  
    - Scroll down, expand **Advanced health check settings**, and enter these settings.  
        - **Healthy threshold**: `2` (This setting tells the load balancer that if it receives two consecutive successful health checks from a target, the target is considered healthy)  
        - **Interval**: `6` (This increases the frequency of health checks to once every 6 seconds)  
Choose **Next**.
    
In **Step 2: Register targets,** choose **Create target group**.  
    A window opens with a message that the target group was successfully created.
    
Close the message window.  
    The _mb-lb-users-target-group_ appears in the target group list.
    
##### **Creating A Target Group for the _Threads_ microservice**
Next, you will create a target group for the _Threads_ microservice.

Choose **Create target group** and in **Step 1: Specify group details**, configure these settings.  
    - **Target group name**: `mb-lb-threads-target-group`  
    - **VPC**: Select the _load balancer VPC ID_. It should be similar to _vpc-nnnnnnnnnn (10.32.0.0/16)_  
    - In the **Advanced health check settings** section, enter these settings.  
        - **Healthy threshold**: `2`  
        - **Interval**: `6`  
Choose **Next**.
    
In **Step 2: Register targets**, choose **Create target group**.  
    A window opens with a message that the target group was successfully created.
    
Close the message window.  
    The _mb-lb-threads-target-group_ appears in the target group list.
##### **Creating A Target Group for the _Posts_ microservice**
Lastly, you will create a target group for the _Posts_ microservice.  
Choose **Create target group** and configure these settings.  
    - **Target group name**: `mb-lb-posts-target-group`  
    - **VPC**: Select the _load balancer VPC_ ID. It should be similar to _vpc-nnnnnnnnnn (10.32.0.0/16)_.  
    - In the **Advanced health check settings** section, enter these settings.  
        - **Healthy threshold**: `2`  
        - **Interval**: `6`  
Choose **Next**, and then choose **Create target group**.  
    A window opens with a message that the target group was successfully created.
    
Close the message window.  
    The _mb-lb-posts-target-group_ appears in the target group list.
    

##### **Creating Listener Rules for the Load balancers**
You have created the target groups for each microservice. You will modify the listener rules for the load balancer. These rules will route traffic to each load balancer, based on the request URI path.

Open the details page for _mb-load-balancer_ by going to the navigation pane and selecting **Load Balancers**.
    
In the bottom pane, choose the **Listeners** tab.
    
Select the **HTTP:80** listener and then from the **Actions** menu choose **Manage rules**.  
    The rules editor opens.  
    You will now create a new rule to forward a request to the _Users_ target group if the request URI matches the pattern `/api/users*`.
    
In the tool bar at the top of the editor, add a new rule by choosing the **Add rules** (**+**) icon.  
    An _Insert Rule_ line appears in the rules list.

Choose **Insert Rule**.  
    A rules box appears allowing you to add an _IF_ condition and a _THEN_ action.
    
Configure the following settings for this rule.  
    - **Add condition**: _Path_  
    - **is > Value**: `/api/users*`  
    - **Add action**: _Forward to_  
    - **Forward to > Target group**: _mb-lb-users-target-group_  
        The rules box should look like the following example:  
[image]  
Choose **Save**.  
    The rule is added to the list as rule _1_.  
    You will now create a rule to forward a request to the **Threads** target group if the request URI matches the pattern `/api/threads*`.
    
In the line below _rule 1_, choose **Insert Rule**.  
    The rules editor opens.
    
Configure the following settings for this rule.  
    - Add condition**: _Path_**  
    - **is > Value**: `/api/threads*`  
    - **Add action**: _Forward to**_  
    - **Forward to > Target group**: _mb-lb-threads-target-group_  
Choose **Save**.  
    The rule is added to the list as rule _2_.  
    You will now create a new rule to forward a request to the **Posts** target group if the request URI matches the pattern `/api/posts*`.
    
In the line below _rule 2_, choose **Insert Rule**.
    
In the rules editor, configure these settings:  
    - **Add condition**: _Path_  
    - **is > Value**: `/api/posts*`  
    - **Add action**: _Forward to_  
    - **Forward to > Target group**: _mb-lb-posts-target-group_  
Choose **Save**.  
    The rule is added to the list as rule _3_.  
    Now, you will create a new rule to forward a request to the **Users** target group if the request URI matches the patterns of `/` or `/api`. You could select any of the application's target groups because their corresponding microservice can handle both types of requests.
    
In the line below _rule 3_, choose **Insert Rule**.
    
In the rules editor, configure these settings.  
    - **Add condition**: _Path_  
    - **is > Value**: `/`  
    - **or > Value**: `/api`  
    - **Add action**: _Forward to_  
    - **Forward to > Target group**: _mb-lb-users-target-group_  
Choose **Save**.  
    The rule is added to the list as rule _4_.  
    Lastly, you will change the action for the _last_ (default) rule so that any other request URI returns an error page with the message _Invalid request_.
    
In the tool bar at the top, choose the **Edit rules** (pencil) icon.
    
    The rules editor switches to edit mode.
    
238. Scroll to the _last_ rule and choose the **Edit Rule** (pencil) icon.
    
1. In the rules editor, configure these settings.
    - **Then**: Delete the existing _Forward to_ action by choosing the **Delete** (trashcan) icon.
    - **Add action**: _Return fixed response_
    - **Response code**: `200`
    - **Response body**: `Invalid request`

The rules editor should look like this example:  
[image]  
Choose **Update**.  
A message indicates that the rule was successfully updated.  
The final listener rules for the load balancer should look like this example:  
[image]

To return to the load balancer details page, choose the **Back arrow** icon (in the top-left area of the window).  
    You have completed the required changes to the load balancer configuration.
    

#### Task 6.3: Deploying the Microservices as ECS Services
In this subtask, you will deploy the three microservices to the cluster as ECS services.

**Creating an ECS service for _Users_**  
You will now create an ECS service for the _Users_ microservice task definition.

In the **Amazon EC2 console** browser tab, choose **Services**, and then select **Containers > Elastic Container Service**.
    
In the clusters list, choose **mb-ecs-cluster**.
    
In the **Services** tab, open the Create Service wizard by choosing **Create**.
    
In **Step 1: Configure service**, configure the following settings.  
    - **Launch type**: _EC2_ (You are running the containerized microservice directly on a cluster of EC2 instances.)  
    - **Task Definition > Family**: _mb-users-task_  
    - **Service name**: `mb-users-ecs-service`  
    - **Service type**: _REPLICA_ (This setting establishes a scheduling strategy that places and maintains the desired number of tasks across the ECS cluster)  
    - **Number of tasks**: `1` (For this exercise, you want to launch and maintain one task on the cluster at all times)  
Choose **Next step**.
    
In **Step 2: Configure network**, configure the following settings.  
    - **Load balancer type**: _Application Load Balancer_ (You want the tasks in your service to be load balanced by the _mb-load-balancer_ that you set up)  
    - **Service IAM role**: _ecsServiceRole_  
    - **Load balancer name**: _mb-load-balancer_  
    - **Container to load balance**: _Add to load balancer_  
    - **Production listener port**: _80:HTTP_ (You are associating the container with the load balancer listener that listens for HTTP traffic on port 80)  
    - **Target group name**: _mb-lb-users-target-group_  
Choose **Next step**.
    
In **Step 3: Set Auto Scaling (optional)**, choose **Next step**. You do not want to configure any additional automatic scaling.
    
In the **Review** page, make sure that the settings are correct and choose **Create Service**.  
    The **Launch Status** page opens, and shows the tasks that the wizard performs.
    
Wait until all tasks display a check mark to indicate that they are complete.
    
Choose **View Service**.  
    The details page for _mb-users-ecs-service_ opens. The **Tasks** tab shows that there is now one task running the container.
    
After a few moments, choose the **Refresh** button.  
    The task's **Last status** should show a value of _RUNNING_.
    
##### **Creating An ECS Service for _Threads_**
Next, you will create an ECS service for the _Threads_ microservice task definition.

To return to the cluster details page, in the breadcrumb trail at the top of the page, choose **mb-ecs-cluster**.
    
In the **Services** tab, choose **Create**.
    
In **Step 1: Configure service**, configure the following settings.  
    - **Launch type**: _EC2_  
    - **Task Definition > Family**: _mb-threads-task_  
    - **Service name**: `mb-threads-ecs-service`  
    - **Service type**: _REPLICA_  
    - **Number of tasks**: `1`  
Choose **Next step**.
    
In **Step 2: Configure network**, configure the following settings.  
    - **Load balancing > Load balancer type**: _Application Load Balancer_  
    - **Load balancer name**: _mb-load-balancer_  
    - **Container to load balance**: _Add to load balancer_  
    - **Production listener port**: _80:HTTP_  
    - **Target group name**: _mb-lb-threads-target-group_  
Choose **Next step**.
    
In **Step 3: Set Auto Scaling (optional)** page, click **Next step**.
    
In the **Review** page, make sure that the settings are correct and choose **Create Service**.  
    The **Launch Status** page opens and shows the tasks that the wizard performs.
    
Wait until all tasks display a check mark to indicate that they are complete.
    
Choose **View Service**.  
    The details page for _mb-threads-ecs-service_ opens. The **Tasks** tab shows that one task is running the container.
    
After a few moments, choose **Refresh**. The task's **Last status** shows a value of _RUNNING_.

##### **Creating An ECS Service for _Posts_**
Lastly, create an ECS service for the _Posts_ microservice task definition.

Return to the cluster details page for _mb-ecs-cluster_.
    
In the **Services** tab, choose **Create**.
    
In **Step 1: Configure service**, configure the following settings.  
    - **Launch type**: _EC2_  
    - **Task Definition > Family**: _mb-posts-task_  
    - **Service name**: `mb-posts-ecs-service`  
    - **Service type**: _REPLICA_  
    - **Number of tasks**: `1`  
Choose **Next step**.
    
In **Step 2: Configure network**, configure the following settings.  
    - **Load balancing > Load balancer type**: _Application Load Balancer_  
    - **Load balancer name**: _mb-load-balancer_  
    - **Container to load balance**: _Add to load balancer_  
    - **Production listener port**: _80:HTTP_  
    - **Target group name**: _mb-lb-posts-target-group_  
Choose **Next step**.
    
In **Step 3L Set Auto Scaling (optional)**, choose **Next step**.
    
In the **Review** page, make sure that settings are correct and choose **Create Service**.  
    The **Launch Status** page opens and shows the tasks that the wizard performs.
    
Wait until all tasks display a check mark to indicate that they are complete.
    
Choose **View Service**.  
    The details page for _mb-posts-ecs-service_ opens. The **Tasks** tab shows that one task is running the container.
    
After a few moments, choose **Refresh**.  
    The task's **Last status** should show a value of _RUNNING_.
    
Return to the cluster details page for _mb-ecs-cluster_.  
    The three new services that you created are now in the **Services** list.
    
[image]

It should only take a few seconds for all your services to start. Double-check that all services and tasks are running and healthy before you proceed.

#### Task 6.4: Validating the Deployment

You will now test the RESTful API methods of the message board application from a web browser. You will also validate that the microservices-based implementation works correctly.

First, you will shut down the ECS service for the containerized monolith version of the application. You do not want it to serve any requests.

In the **Services** list, select **mb-ecs-service**, and choose **Update**.  
    The **Update Service** wizard opens.
    
For **Number of tasks**, change the value to `0`. (This setting instructs Amazon ECS to not run any tasks for the service.)
    
Choose **Skip to review**.
    
In the **Review** page, choose **Update Service**.  
    The _Launch Status_ page opens with a message that the service has been updated.
    
Choose **View Service**.  
    The details page for _mb-ecs-service_ opens. The **Deployments** tab shows that the **Running count** for the service is _0_.  
    **Note**: If you do not see the change immediately, wait a few seconds and choose **Refresh**.
    
[image]

Open a new browser tab, paste the _Load Balancer DNS Name_ that you recorded earlier, and press ENTER.  
    This action returns the message _Ready to receive requests_. The application returns this message when no resource path is included in the GET request. Recall from the listener rules configuration that this type of request is sent to the _Users_ microservice.
    
Add `/api` to the end of the URL and press ENTER.  
    The application—specifically, the _Users_ microservice—returns the message _API ready to receive requests_.
    
Test the retrieval of all _users_ in the database. Add `/users` to the end of the URL and press ENTER.  
    The _Users_ microservice returns a JSON object that lists the four users in the database.
    
Retrieve the information for the _first user_ in the database. Add `/1` to the end of the URL and press ENTER.  
    The _Users_ microservice returns a JSON object that contains the information for _Marcerline Singer_, who is the first user in the database.
    
Next, retrieve all the _threads_ in the database. Change the URI after the load balancer DNS name to `/api/threads` and press ENTER.  
    The _Threads_ microservice returns a JSON object that contains all three threads in the database.
    
Retrieve the _posts_ for the _second thread_ in the database. Change the URI after the load balancer DNS name to `/api/posts/in-thread/2` and press ENTER.  
    The _Posts_ microservice returns a JSON object that contains the posted messages for the second thread (which are bakery-related) in the database.
    
Finally, test the submission of a request with an invalid URI. Change the URI after the load balancer DNS name to `/xyz` and press ENTER.  
    The request is forwarded to default handler in the load balancer's listener rules, which returns the message _Invalid request_.  
    You have successfully converted a monolithic Node.js application to a microservices architecture. The original application ran, without containerization, directly on an instance. In contrast, microservices-based application is deployed in a containerized environment that is orchestrated by Amazon ECS.