This blog post is part of the course Node in Production with Docker and AWS at Node University. You can follow the text tutorial here or watch my video screencasts on Node University.

In this tutorial, we will Deploy two containers (API and DB) which connect using ECR and EC2 ECS. If you are interested in building images for container, read the first tutorial Dockerizing Node and Connecting Multiple Containers.

Steps to deploy a two-container project (app + database):

  1. Create registry (ECR)
  2. Upload the app image to ECR
  3. Create task definition with 2 containers
  4. Create a cluster
  5. Create a service and run it

Time to finish: 15 min ☁️

1. Create Registry (ECR)

Each image needs to be uploaded to a registry before we can use it to run a container. There is registry from docker: AWS provides its own registry service called EC2 Elastic Container Registry (ECR). Let’s use it.

Log in to your AWS web console at Navigate to us-west–2 (or some other region, but we are using us-west–2 in this lab) and click on CE2 Container Service under Compute:

Then click on Repositories from a lift menu and on a blue button Create repository. Then new repository wizard will look like this:

Enter the name of your repository for container images. I picked azat-main-repo because my name is Azat:

Click next and on Step 2, you will see bunch of commands.

Successfully created repository, e.g., my URL is

Next, follow instructions to upload an image (must build it before uploading/pushing).

To install the AWS CLI and Docker, and for more information on the steps below, visit the ECR documentation page.

Command 1: Retrieve the docker login command that you can use to authenticate your Docker client to your registry:

aws ecr get-login --region us-west-2

Command 2: Run the docker login command that was returned in the previous step. For example,

docker login -u AWS -p eyJwYXlsb2FkIjoiQ1pUVnBTSHp
-e none


Login Succeeded

Command 3:: Build your Docker image using the following command. For information on building a Docker file from scratch see the instructions here. You can skip this step if your image is already built:

cd code/banking-api
docker build -t azat-main-repo .

You might have done this already in the lab 1 (labs/ Skip to step 4. If not, then build the app image. The build command should end with a similar looking output:

Step 13/13 : CMD npm start
> Running in ee5f0fb12a2f
> 91e9122e9bed
Removing intermediate container ee5f0fb12a2f
Successfully built 91e9122e9bed

Command 4: After the build completes, tag your image so you can push the image to this repository:

docker tag azat-main-repo:latest

(No output)

Command 5: Run the following command to push this image to your newly created AWS repository:

docker push

Push output example:

The push refers to a repository []
9e5134c1ad7a: Pushed
e949bf24b1c4: Pushed
2b5c968a7072: Pushed
858e5e857851: Pushed
10e038bbd0ad: Pushed
ad2f0f4f7c5a: Pushed
ec6eb0ab894f: Pushed
e0380bb6c0bb: Pushed
9f8566ee5135: Pushed
latest: digest: sha256:6d1cd529ced84a6cff1eb5f6cffaed375717022b998e70b0d33c86db26a04c74 size: 2201

Remember digest (last hash) 📝 Compare digest with one in the repository when you look up your image in the web console in EC2 -> ECS -> Repositories -> azat-main-repo:

2. Create New Task Definition

Tasks are like run commands in docker CLI (docker run) but for multiple containers. Typical tasks define:

  • Container images to use
  • Volumes if any
  • Networks
  • Environment variables
  • Port mappings

Go to the Task Definitions in EC2 ECS and as you might guess, press on the button which says Create new Task Definition:

Main Task Settings for the Example

Use the following settings for the task to make sure your project is running (because some other values might make the project nonfunctional):

  • Two containers: banking-api (private AWS ECR) and mongodb (docker hub)
  • Connect to mongodb via network alias
  • Map 80 (host) to 3000 (container) for banking-api
  • Set env vars for NODE_ENV and DB_URI

Let’s define the first container — app.

First Container—App

Enter the name: banking-api-container.

Define the image URL (your URL will be different), e.g.,

Define host 80 and container 3000 ports in port mappings. Name, image and ports are shown below:

Scroll down in the same modal view and add Env Variables:


Add to Links the name of the MongoDB container (not defined yet) to give access to the database container to the app container such as one is the name of the container in the task definition and the other is the host name in the DB_URI:


See the screengrab below:

Second Container—Database

Analogous to the previous container, define name and URL with these values:

  • Name: mongod-banking-api-prod-container
  • Image URL:

Scroll down to the hostname in Network settings and enter Hostname as mongod-banking-api-prod-container as shown below:

After you added two container to the task, create the task and you’ll see a screen similar to the one shown below:

Alternatively, you could specify volumes for database or/and the app at the stage of the task creation.

3. Create Cluster

Cluster is the place where AWS runs containers. They use configurations similar to EC2 instances. Define the following:

  • Cluster name: banking-api-cluster
  • EC2 instance type: m4.large (for more info on EC2 type, see AWS Intro course on Node University)
  • Number of instances: 1
  • EBS storage: 22
  • Key pair: None
  • VPC: New

Launch the cluster. It might take a few minutes.

You’ll see the progress:

ECS creates a lot of EC2 resources for you such as Internet Gateway, VPC, security group, Auto Scaling group, etc. which is great because you don’t have to create them manually.

4. Create Service and Verify

The last step is to create a service which will take the task and the cluster and make the containers in the task run in the specified cluster. It’s oversimplified explanation because service will do more such as monitor health and restart containers.

Go to Create Services which is under Task Definition -> banking-api-task -> Actions -> Create Service. You will see this:

Everything is ready

Phew. Everything should be ready by now. To verify, we need to grab a public IP or public DNS. To do so, click Clusters -> banking-api-cluster (cluster name) -> ESC Instances (tab) and Container instance:

Copy public IP or DNS 📝.

Dynamic Test

To test the dynamic content (content generated by the app with the help of a database), open in browser with {PUBLIC_DNS}/accounts. Most likely the response will be [] because the database is empty but that’s a good response. The server is working and can connect to the database from a different container.

Static Test

To test the static content such as an image which was downloaded from the Internet by Docker (ADD in Dockerfile) and baked into the image, navigate to


to see the images with Docker downloaded via ADD. Using ADD, you can fetch any data such as HTTPS certificates (from a private S3 for example).

Terminate Service and Cluster/Instances

Don’t forget to terminate your service and instances. You can do it from the web console.

Wrap Up

AWS has good services for Docker and you can run Node and other servers. Both allow to create very lightweight microservices for a more scalable architecture. Make sure to checkout some free preview lectures in Node in Production with Docker and AWS at Node University.