Hosting an Angular application in a Docker container on Amazon EC2 deployed by Amazon ECS
Tags: angular, docker, aws, container
Published: 2024-03-10 10:17:47

# Introduction


In this article, a WEB application using the latest version of [Angular](https://angular.io/) in a built [Docker](https://www.docker.com/) image will be hosted on [Amazon EC2](https://aws.amazon.com/ec2/) (Elastic Compute Cloud) and deployed by [Amazon ECS](https://aws.amazon.com/ecs/) (Elastic Container Service) using an [Amazon ECR](https://aws.amazon.com/ecr/) (Elastic Container Registry) containers repository.



# Prerequisites


Before you start, you need to install and configure the tools below to create the Angular application, the Docker image and push the image to the repository on Amazon ECR.

* [git](https://git-scm.com/): Git is a distributed version control system and it will be used to sync the repository.
* [Node.js and npm](https://nodejs.org/): Node.js is a JavaScript code runtime software based on Google's V8 engine. npm is a package manager for Node.js (Node.js Package Manager). They will be used to build and run the Angular application and install the libraries.
* [Docker Engine](https://docs.docker.com/engine/install/): Docker Engine is a command line utility tool for Docker and it will be used to create and run containers.
* IDE (e.g. [Visual Studio Code](https://code.visualstudio.com/) or [WebStorm](https://www.jetbrains.com/webstorm/)): IDE (Integrated Development Environment) is a tool with a graphical interface to help in the development of applications and it will be used to develop the Angular application.
* [AWS CLI](https://docs.aws.amazon.com/cli/): AWS Command Line Interface is a command line utility tool for interacting with all Amazon Web Services services.



# Getting started


## Create the repository on Amazon ECR


[Amazon ECR](https://aws.amazon.com/ecr/) is a Docker containers registry service that enables you store and manage conteiner images.

**1.** Let's create and configure the account. Access the site [ https://aws.amazon.com/ecr/]( https://aws.amazon.com/ecr/) and click on the button *Get started with Amazon ECS*.

![Amazon ECR - Home page](https://res.cloudinary.com/rodrigokamada/image/upload/v1709036748/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step1.webp)

**2.** Now we will click on the option *Root user*, fill in the field *Root user email address* and click on the button *Next*.

![Amazon ECR - Sign in](https://res.cloudinary.com/rodrigokamada/image/upload/v1709045805/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step2.webp)

Note:

* If you don't have an Amazon account, do steps 1 to 9 of the post *[Authentication using the Amazon Cognito to an Angular application](https://dev.to/rodrigokamada/authentication-using-the-amazon-cognito-to-an-angular-application-ilh)* in the session *Create and configure the account on the Amazon Cognito*.

**3.** Next, we will fill in the field *Password* and click on the button *Sign in*.

![Amazon ECR - Root user sign in](https://res.cloudinary.com/rodrigokamada/image/upload/v1709046141/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step3.webp)

**4.** Then, we will type *ecr* in the search field and click on the option *Elastic Container Registry*.

![Amazon ECR - Elastic Container Registry service](https://res.cloudinary.com/rodrigokamada/image/upload/v1709046474/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step4.webp)

**5.** After click on the option *Elastic Container Registry*, we will click on the button *Get started*.

![Amazon ECR - Elastic Container Registry](https://res.cloudinary.com/rodrigokamada/image/upload/v1709052667/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step5.webp)

**6.** Now we will click on the option *Public*, fill in the field *Repository name* and click on the button *Create repository*.

![Amazon ECR - Create repository](https://res.cloudinary.com/rodrigokamada/image/upload/v1709060788/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step6.webp)

**7.** Next, we will click on the created repository and click on the button *View push commands*.

![Amazon ECR - Public repositories](https://res.cloudinary.com/rodrigokamada/image/upload/v1709133766/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step7.webp)

**8.** Then, we will copy the commands because they will be used to push the Docker image of the Angular application and click on the button *Close*.

![Amazon ECR - Push commands](https://res.cloudinary.com/rodrigokamada/image/upload/v1709081149/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step8.webp)

**9.** Ready! The repository to store the Docker image of the Angular application was created.



## Push the Docker image of the Angular application


**1.** Let's user the Angular application created in the post [Creating and running an Angular application in a Docker container](https://dev.to/rodrigokamada/creating-and-running-an-angular-application-in-a-docker-container-40mk). We will clone the repository [https://github.com/rodrigokamada/angular-docker](https://github.com/rodrigokamada/angular-docker).

```powershell
git clone https://github.com/rodrigokamada/angular-docker angular-docker-amazon-ecs
```

**2.** Now we will change the file `Dockerfile` with the content below.

```powershell
FROM node:alpine AS app

WORKDIR /usr/src/app

COPY . /usr/src/app

RUN npm install

RUN npm run build



FROM nginx:alpine

COPY --from=app /usr/src/app/dist/angular-docker/browser /usr/share/nginx/html

RUN ls /usr/share/nginx/html

COPY ./nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
```

Notes:

* The `FROM node:alpine AS app` setting defines the base Docker image of Node.js to build the Angular application.
* The `WORKDIR /usr/src/app` setting defines the default application directory. The defined directory is created if it does not exist.
* The `COPY . /usr/src/app` setting copies the local application files and directories to the defined directory.
* The `RUN npm install` setting installs the Angular application dependencies.
* The `RUN npm run build` setting compiles the Angular application.
* The `FROM nginx:alpine` setting defines the base Docker image of NGINX to serve the Angular application files.
* The `COPY --from=app /usr/src/app/dist/angular-docker/browser /usr/share/nginx/html` setting copies the compiled Angular application files to the NGINX directory.
* The `COPY ./nginx.conf /etc/nginx/conf.d/default.conf` setting copies the NGINX configuration file to serve the Angular application.
* The `EXPOSE 80` setting defines the Docker port. NGINX uses the default port 80.

**3.** Next, we will create the file `nginx.conf` with the NGINX configuration in the root directory of the Angular application.

```powershell
touch nginx.conf
```

**4.** Then, we will configure the file `nginx.conf` with the content below.

```powershell
server {
    listen 80;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html =404;
    }
}
```

**5.** After configure the file `nginx.conf`, we will authenticate the Docker client with the repository registry.

```powershell
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/d3o6w2v8

Login Succeeded
```

**6.** Now we will create the Docker image.

```powershell
docker build -t angular-docker-amazon-ecs .
[+] Building 45.5s (10/10) FINISHED                                                                                                         docker:default
 => [internal] load build definition from Dockerfile                                                                                                  0.1s
 => => transferring dockerfile: 191B                                                                                                                  0.0s
 => [internal] load metadata for docker.io/library/node:alpine                                                                                        2.4s
 => [internal] load .dockerignore                                                                                                                     0.1s
 => => transferring context: 2B                                                                                                                       0.0s
 => [1/5] FROM docker.io/library/node:alpine@sha256:d3271e4bd89eec4d97087060fd4db0c238d9d22fcfad090a73fa9b5128699888                                  4.5s
 => => resolve docker.io/library/node:alpine@sha256:d3271e4bd89eec4d97087060fd4db0c238d9d22fcfad090a73fa9b5128699888                                  0.0s
 => => sha256:6af33fd59f0638fb0acc2992b2b54c7baf68fe593083f0f52815cf29d1288803 7.13kB / 7.13kB                                                        0.0s
 => => sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8 3.41MB / 3.41MB                                                        1.0s
 => => sha256:2997c41553473c7c926a796f330b4a7b03e9d2a7a9ee059a66bf68e02040bf40 43.53MB / 43.53MB                                                      2.0s
 => => sha256:803074618b54a85228c5e10d79b5320e5eba82a2f89abddf233e852420430ba2 2.37MB / 2.37MB                                                        1.0s
 => => sha256:d3271e4bd89eec4d97087060fd4db0c238d9d22fcfad090a73fa9b5128699888 1.43kB / 1.43kB                                                        0.0s
 => => sha256:f5d3a6aea1b1d35066e6c034f5c264cd5b051fc7c7cb0160bb88899e7b1f0c83 1.16kB / 1.16kB                                                        0.0s
 => => extracting sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8                                                             0.1s
 => => sha256:249f9271d1d17cdc2d12d106e2dcfafdc306da21f65123a06aa2290baa5c4fac 451B / 451B                                                            1.4s
 => => extracting sha256:2997c41553473c7c926a796f330b4a7b03e9d2a7a9ee059a66bf68e02040bf40                                                             1.7s
 => => extracting sha256:803074618b54a85228c5e10d79b5320e5eba82a2f89abddf233e852420430ba2                                                             0.3s
 => => extracting sha256:249f9271d1d17cdc2d12d106e2dcfafdc306da21f65123a06aa2290baa5c4fac                                                             0.0s
 => [internal] load build context                                                                                                                     0.1s
 => => transferring context: 683.88kB                                                                                                                 0.0s
 => [2/5] WORKDIR /usr/src/app                                                                                                                        0.3s
 => [3/5] COPY . /usr/src/app                                                                                                                         0.1s
 => [4/5] RUN npm install -g @angular/cli                                                                                                            20.1s
 => [5/5] RUN npm install                                                                                                                            13.8s
 => exporting to image                                                                                                                                4.0s
 => => exporting layers                                                                                                                               4.0s
 => => writing image sha256:e6b87cf9530701fe49f487780093e6bd0e87c2052147750debf8fdf3e6544851                                                          0.0s
 => => naming to docker.io/library/angular-docker-amazon-ecs
```

**7.** Next, we will create the image tag.

```powershell
docker tag angular-docker-amazon-ecs:latest public.ecr.aws/d3o6w2v8/angular-docker-amazon-ecs:latest
```

**8.** Then, we will push the Docker image to the repository.

```powershell
docker push public.ecr.aws/d3o6w2v8/angular-docker-amazon-ecs:latest
The push refers to repository [public.ecr.aws/d3o6w2v8/angular-docker-amazon-ecs]
0d182ddaeba2: Pushed 
692f273c8005: Pushed 
f19fda91d840: Pushed 
118d5d6c8a47: Pushed 
6ac923e38b05: Pushed 
18ffdcddf862: Pushed 
aab2cca0cf91: Pushed 
d4fc045c9e3a: Pushed 
latest: digest: sha256:2f09379b02c2669c915fc63116536d1bb5040c3d608a68b8f3306f10af4d125d size: 2000
```

Note:

* The AWS CLI user must have the permission `AmazonElasticContainerRegistryPublicFullAccess`.

**9.** After push the Docker image to the repository, we will check if the Docker image was pushed to the repository. We will go back to the site and click on the repository name.

![Amazon ECR - Public repositories](https://res.cloudinary.com/rodrigokamada/image/upload/v1709118064/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step9.webp)

**10.** Now we will see the Docker image pushed.

![Amazon ECR - Images](https://res.cloudinary.com/rodrigokamada/image/upload/v1709122674/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step10.webp)

**11.** Ready! The Docker image of the Angular application was pushed to the repository on Amazon ECR.



## Create the conteiner on Amazon ECS


[Amazon ECS](https://aws.amazon.com/ecs/) is a Docker containers orchestration service that enables you deploy, manage and scale containerized applications.

**1.** Let's type *ecs* in the search field and click on the option *Elastic Container Service*.

![Amazon ECS - Access Elastic Container Service](https://res.cloudinary.com/rodrigokamada/image/upload/v1709132711/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step11.webp)

**2.** Now we will click on the button *Create cluster*.

![Amazon ECS - Elastic Container Service](https://res.cloudinary.com/rodrigokamada/image/upload/v1709134105/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step12.webp)

**3.** Next, we will fill in the field *Cluster name*, click on the option *Amazon EC2 instances*, select the option *Amazon Linux 2* in the field *Operating system/Architecture*, select the option *c1.medium* in the field *EC2 instance type*, fill in the field *Maximum*, select the option *Turn on* in the field *Auto-assign public IP* and click on the button *Create*.

![Amazon ECS - Create cluster](https://res.cloudinary.com/rodrigokamada/image/upload/v1709230689/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step13.webp)

**4.** Then, we will click on the menu *Task definitions*.

![Amazon ECS - Clusters](https://res.cloudinary.com/rodrigokamada/image/upload/v1709167153/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step14.webp)

**5.** After click on the menu *Task definitions*, we will click on the button *Create new task definition*.

![Amazon ECS - Tasks definitions](https://res.cloudinary.com/rodrigokamada/image/upload/v1709167206/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step15.webp)

**6.** Now we will fill in the field *Task definition family*, click on the option *Amazon EC2 instances*, select the option *default* in the field *Network mode*, fill in the field *CPU*, fill in the field *Memory*, fill in the field *Name* with the tag name, fill in the field *Image URI* with the Docker image name, fill in the field *Host port* with the external port, fill in the field *Container port* with the NGINX port and click on the button *Create*.

![Amazon ECS - Create new task definition](https://res.cloudinary.com/rodrigokamada/image/upload/v1709229737/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step16.webp)

**7.** Next, we will click on the button *Deploy* and click on the option *Run task*.

![Amazon ECS - Overview](https://res.cloudinary.com/rodrigokamada/image/upload/v1709168668/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step17.webp)

**8.** Then, we will click on the button *Create* because the fields *Existing cluster*, *Family* and *Revision* was filled in.

![Amazon ECS - Create run task](https://res.cloudinary.com/rodrigokamada/image/upload/v1709168972/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step18.webp)

**9.** After click on the button *Create*, we will wait for the EC2 instance to be created in the session *Tasks*.

![Amazon ECS - Tasks launched](https://res.cloudinary.com/rodrigokamada/image/upload/v1709231852/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step19.webp)

**10.** Now we will type *ec2* in the search field and click on the option *EC2*.

![Amazon ECS - Search EC2](https://res.cloudinary.com/rodrigokamada/image/upload/v1709170013/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step20.webp)

**11.** Next, we will click on the menu *Instances*.

![Amazon ECS - EC2 Dashboard](https://res.cloudinary.com/rodrigokamada/image/upload/v1709232482/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step21.webp)

**12.** Then, we will click on the created instance.

![Amazon ECS - Instances](https://res.cloudinary.com/rodrigokamada/image/upload/v1709242278/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step22.webp)

**13.** After click on the created instance, we will click on the icon to copy the domain in *Public IPv4 DNS*.

![Amazon ECS - Copy domain](https://res.cloudinary.com/rodrigokamada/image/upload/v1709248161/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step23.webp)

**14.** Now we will access the URL `http://ec2-54-146-190-174.compute-1.amazonaws.com` in a browser.

![Amazon ECS - Angular application](https://res.cloudinary.com/rodrigokamada/image/upload/v1709249205/Blog/angular-docker-amazon-ecs/angular-docker-amazon-ecs-step24.webp)

**15.** Ready! The Docker image of the Angular application was deployed and the application is working.



# Conclusion

Summarizing what was covered in this article:

* We created a public repository on Amazon ECR.
* We changed the Docker configuration of the Angular application.
* We created the NGINX configuration file in the Angular application.
* We created a Docker image.
* We pushed the Docker image to the repository.
* We created a container on Amazon ECS for the deployment.
* We tested the Angular application inside the Docker container served on EC2 instance.

You can use this article to create a Docker container with an Angular application image, push the image to a repository on Amazon ECR and deploy the container using Amazon ECS to an EC2 instance where the Angular application will be served.

Thank you for reading and I hope you enjoyed the article!

This tutorial was posted on my [blog](https://rodrigo.kamada.com.br/blog/hospedando-uma-aplicacao-angular-em-um-conteiner-docker-no-amazon-ec2-implantado-atraves-do-amazon-ecs) in portuguese.

To stay updated whenever I post new articles, follow me on [Twitter](https://twitter.com/rodrigokamada) and [LinkedIn](https://www.linkedin.com/in/rodrigokamada).