Skip to content

A prescriptive guidance on how to host an ASP.NET core application in AWS Fargate using Linux containers.

License

Notifications You must be signed in to change notification settings

aws-samples/amazon-ecs-fargate-aspnetcore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Reference Architecture

Development environment

The development environment needs to have the following :-

a)Mac OS latest version (or) Windows 10 with latest updates (or) Ubuntu 18.0.4 or higher

b).NET Core 3.0

c)Docker latest version

d)aws cli

e)aws ecs cli

Create ASP.NET core mvc application

Let's leverage the terminal in the mac for creating, building and publishing the ASP.NET core mvc core application. Navigate to the directory where the entire set up needs to be created and issue the following commands in the terminal

mkdir mymvcweb

cd mymvcweb

dotnet new mvc

dotnet restore

dotnet build

dotnet publish -c "Release"

The above set of commands creates an ASP.NET core mvc application, restores required dependencies, builds the application and publish the application package to the release folder which will be used by the ASP.NET container (to be created in the next section).

Before proceeding to create containers for ASP.NET core mvc, you can test the application locally issuing 'dotnet run' command in the terminal.

Open 'http://localhost:5000' in the browser and you should the ASP.NET core mvc application getting rendered there.

Containerize ASP.NET core application

Create the following Dockerfile in the mymvcweb folder.

FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS build-env

WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out



# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "mymvcweb.dll"]

ENV ASPNETCORE_URLS http://+:5000
EXPOSE 5000
 

The above Dockerfile definition creates an ASP.NET core 3.0 container and copies the application deployment package from 'bin/Release/netcoreapp3.0/publish' folder on to mymvcweb folder in the container.It also leverages Kestrel as the web server and the default port of 5000 for ASP.NET core mymvc application.

Create Nginx container

Navigate to the aspnetcorefargate directory and create a directory called 'reverseproxy'.

mkdir reverseproxy
cd reverseproxy

Create a new file called 'Nginx.conf'.

sudo nano nginx.conf


Edit the nginx.conf file and add the following definition.

worker_processes 1;

events { worker_connections 1024; }

http {

    sendfile on;

    upstream web-site {
        server mymvcweb:5000;
    }

    server {
        listen 80;
        server_name $hostname;
        location / {
            proxy_pass         http://web-site;
            proxy_redirect     off;
            proxy_http_version 1.1;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection keep-alive;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }
}

Since we are in the development environment we can tag service name 'mymvcweb' for the 'upstream app_servers' section in the nginx.conf file. When this is hosted in AWS Fargate task, we need change the value of 'upstream app_servers' to '127.0.0.1:5000'. Because when the Fargate task runs in Awsvpc networking mode (which is default) it will use the local loopback interface of 127.0.01 to connect to the other container (service) defined as a part of the Fargate task which will be covered in the later sections.

Create a Dockerfile for containerizing the Nginx reverse proxy and it should look like the following:-

FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf

The above Docker file creates an Nginx container and copies nginx.conf file in the reverse proxy folder to the '/etc/nginx/nginx/conf' inside the containers.

Docker compose

Now let's compose both these container as an application by defining the Docker-compose.yml. It should look like below.

version: '2.1'
services:
  mymvcweb:
    build:
      context: ./mymvcweb
      dockerfile: Dockerfile
    expose:
      - "5000"
    restart: always
  reverseproxy:
    build:
      context: ./reverseproxy
      dockerfile: Dockerfile
    ports:
      - "80:80"
    restart: always
    links :
      - mymvcweb

The above docker-compose.yml defines two service. The first service 'mymvcweb' relies the Dockerfile definition defined in the mymvcweb folder and it exposes port (5000) to another service 'reverseproxy'. The second service 'reverseproxy' runs the nginx container on the port 80 and exposes port 80 to outside world. It also links with the first service 'mymvcweb'. The links are good for docker-compose.yml in the development environment. When you convert this into ECS service definition for Fargate tasks links are not supported in the Awsvpc networking mode.

Now let's build and run these containers as a cohesive service in the local environment by issuing the following commands in the terminal.

docker-compose build

The docker-compose build should give you the following results and container ids will vary based on your environment.

Building mymvcweb
Step 1/12 : FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS build-env
 ---> 170a7f2ec51a
Step 2/12 : WORKDIR /app
 ---> Running in 75f2ce0d3031
Removing intermediate container 75f2ce0d3031
 ---> fb7e7c8d1d45
Step 3/12 : COPY *.csproj ./
 ---> 93e1841eb97d
Step 4/12 : RUN dotnet restore
 ---> Running in 95cc9be35811
  Restore completed in 97.46 ms for /app/mymvcweb.csproj.
Removing intermediate container 95cc9be35811
 ---> 6b337daceca5
Step 5/12 : COPY . ./
 ---> b48e4d7c5ae7
Step 6/12 : RUN dotnet publish -c Release -o out
 ---> Running in 43496e3d57d4
Microsoft (R) Build Engine version 16.3.0+0f4c62fea for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 97.04 ms for /app/mymvcweb.csproj.
  mymvcweb -> /app/bin/Release/netcoreapp3.0/mymvcweb.dll
  mymvcweb -> /app/bin/Release/netcoreapp3.0/mymvcweb.Views.dll
  mymvcweb -> /app/out/
Removing intermediate container 43496e3d57d4
 ---> dd7f9e27e5a0
Step 7/12 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.0
 ---> 930743cb4e19
Step 8/12 : WORKDIR /app
 ---> Running in cfcca1d91e7f
Removing intermediate container cfcca1d91e7f
 ---> 16fe7ba01b5b
Step 9/12 : COPY --from=build-env /app/out .
 ---> 6116e9ca8d14
Step 10/12 : ENTRYPOINT ["dotnet", "mymvcweb.dll"]
 ---> Running in f023750450bf
Removing intermediate container f023750450bf
 ---> a1eecd4e274c
Step 11/12 : ENV ASPNETCORE_URLS http://+:5000
 ---> Running in 7f17f58828da
Removing intermediate container 7f17f58828da
 ---> 0d97ddb4b1e8
Step 12/12 : EXPOSE 5000
 ---> Running in 16e23550217f
Removing intermediate container 16e23550217f
 ---> 6d7c3f00f2fd
Successfully built 6d7c3f00f2fd
Successfully tagged amazon-ecs-fargate-aspnetcore_mymvcweb:latest
Building reverseproxy
Step 1/2 : FROM nginx
 ---> 540a289bab6c
Step 2/2 : COPY nginx.conf /etc/nginx/nginx.conf
 ---> ba2256942a3b
Successfully built ba2256942a3b
Successfully tagged amazon-ecs-fargate-aspnetcore_reverseproxy:latest

Then invoke 'docker-compose up' command in the terminal. It should give you the following results if everything is succesful.

Creating network "amazon-ecs-fargate-aspnetcore_default" with the default driver
Creating amazon-ecs-fargate-aspnetcore_mymvcweb_1 ... done
Creating amazon-ecs-fargate-aspnetcore_reverseproxy_1 ... done
Attaching to amazon-ecs-fargate-aspnetcore_mymvcweb_1, amazon-ecs-fargate-aspnetcore_reverseproxy_1
mymvcweb_1      | warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
mymvcweb_1      |       Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
mymvcweb_1      | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
mymvcweb_1      |       No XML encryptor configured. Key {1a961d37-10de-4921-a41d-ca3627533b63} may be persisted to storage in unencrypted form.
mymvcweb_1      | info: Microsoft.Hosting.Lifetime[0]
mymvcweb_1      |       Now listening on: http://[::]:5000
mymvcweb_1      | info: Microsoft.Hosting.Lifetime[0]
mymvcweb_1      |       Application started. Press Ctrl+C to shut down.
mymvcweb_1      | info: Microsoft.Hosting.Lifetime[0]
mymvcweb_1      |       Hosting environment: Production
mymvcweb_1      | info: Microsoft.Hosting.Lifetime[0]
mymvcweb_1      |       Content root path: /app

Open http://localhost:80 in the browser and you should see the default view of index.cshtml getting rendered. After completing the testing in the local development environment you can issue the following commands to clean up docker-compose.

docker-compose stop
docer-compse rm

Push container images to ECR

Create two ECR repositories namely 'mymvcweb' and 'reverseproxy', one for the ASP.NET core mvc application and other for the nginx reverse proxy.

Now let's fetch the push commands for 'mymvcweb' repository and execute the following in the terminal.

aws ecr get-login --no-include-email --region us-east-1

It should return you the docker login command with token. Copy the Docker login with tokens and execute.

Tag the local container image (for mymvcweb) with the remote ECR repository.

docker tag aspnetcorefargate_mymvcweb:latest yourawsaccountnumber.dkr.ecr.us-east-1.amazonaws.com/mymvcweb:latest 

Push the 'mymvcweb' image to the remote 'mymvcweb' repository.

docker push yourawsaccountnumber.dkr.ecr.us-east-1.amazonaws.com/mymvcweb:latest 

Follow the same steps for 'reverseproxy' repository to push the nginx container.

docker tag aspnetcorefargate_reverseproxy:latest yourawsaccountnumber.dkr.ecr.us-east-1.amazonaws.com/reverseproxy:latest 

docker push yourawsaccountnumber.dkr.ecr.us-east-1.amazonaws.com/reverseproxy:latest 

Create ECS Fargate Cluster

Let's create the ECS Fargate cluster using AWS Console.

Clusters --> Create Cluster --> Networking mode only --> Next step

Name the cluster as 'aspnetcorefargatecluster' and enabled a create a new VPC for this cluster.

Leave the CIDR blocks and subnets as default and click create.

You should see a successful creation of cluster and confirmation of the same.

It creates a VPC with three public subnets, internet gateway and a public route table.

Create an Application Load balancer

Navigate to the EC2 console and create an application load balancer.

Create load balancer --> Application Load Balancer and set the following :-

  • Name - aspnetcorefargatealb
  • Scheme - Internet facing
  • IP address type - ipv4

Select all the availability zones and proceed to configure security group settings.

Create a new security group 'aspnetcorealbsg' for ALB.

Name the target group as 'default' and set the following for the rest of the parameters.

The Target type should be selected as ip address for the ECS task level load balancing.

You should get a confirmation for the successful creation of the application load balancer.

Create an ECS Fargate Task

Let's leverage the aws console for creating Fargate task.

Task Definition --> Create new Task Definition --> Fargate

Define the task definition name as 'aspnetcorefargatetask' and select the appropriate task role.

Select the task execution role and define the CPU and memory settings for Task size.

Let's add the two containers 'mymvcweb' and 'reverseproxy' to the container definitions.

Define the container for 'reverseproxy'

The container 'Links' are not supported in Fargate Task because of 'awsvpc' networking mode. Hence no need to Link containers and leave the rest of settings as default for 'reverseproxy' container.

Complete the task creation and you should get the confirmation for successful creation of Fargate task.

Create an ECS Fargate Service

Let's leverage the AWS console for creating the Fargate service.

Select the 'aspnetcorecorefargatetask' --> Actions --> Create service and name it as 'aspnetcorefargatesvc'.

Specify the number of tasks as 2 and the leave the defaults for the rest.

Proceed to configure network settings by selecting the appropriate VPC and subnets of the assoiated ECS Fargate cluster.

Select Application Load Balancer under Load balancing.

You should see 'aspnetcorefargatealb' listed there and make sure it is selected.

Under the container to load balance select the 'reverseproxy' container and click 'add to load balancer'.

Select the Target name as 'default' and the rest will get auto-populated.

Since Service Discovery is optional and leave it unselected. However we'll define service level autoscaling even though it is optional.

Define the automatic task scaling policy like mentioned below.

Proceed to complete the service creation and you should get a confirmation for successful creation of Fargate service.

Test the service

After few minutes you should see couple of tasks in running status

You should see the task IP addresses getting added to the application load balancer.

The health host count in the metrics of application load balancer should also reflect two tasks.

Open the DNS A record of the application load balancer in the browser.The ASP.NET core mvc application should get successfully rendered.

This completes this post about hosting an ASP.NET core mvc application and nginx reverse proxy in AWS ECS Fargate.

About

A prescriptive guidance on how to host an ASP.NET core application in AWS Fargate using Linux containers.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •