Deploy a .NET web app on Amazon ECS
Let’s look at how to deploy a .NET web application on Amazon ECS.
In this blogpost i will share with you:
- Create a AWS Cloud9 environment using AWS ClouFormation.
- Create a Docker image and push it to ECR
- Create an ECS cluster
- Deploy the app
- Configure monitoring and logging.
As you know AWS Cloud9 is an online IDE. there is no upfront cost to use this IDE. AWscloudFormation is a service that gives an easy way to create a collection of related AWS resources.
ECR is a fully managed container registry offering high-performance hosting. You can deploy application images and artefacts anywhere. ECS is a fully managed container orchestration service that makes it easy for you to deploy, manage and scale containerized apps.
Create CloudFormation stack
First, we need to configure an environment using AWS CloudFromation template. This template describes all the resources and dependencies. So we can launch and configure them as a stack. You can use this template to create the stack. Then, Go to the AWS CloudFormation console and begin to create a stack.
In create stack page choose Template is ready as Prerequisite — Prepare template. In specify template tab there are 2 options. One is you can upload the template to S3 and can provide the S3 url in the given box or you can upload the template file. Click on Next and in the next page, you can specify the stack name, network configuration and RDS configuration.
After providing all details click next. Now you are in the configure stack options page. Here we don’t have to make any changes. Just go to the review screen. Check and review all the details you provided and make sure to tick all the checkboxes inside Transforms might require access capabilities.
Click on create stack. Now you can see the status of your stack. Just check Events, Resources and Outputs to get an idea about all information about the resources created by the cloudFormation template.
Cloud9 Workspace
After your CloudFormation stack is completed check the Outputs tab. You can find your Cloud9 IDE workplace lick on the given URL and go to the workspace. For the rest of the tutorial, I’m going to use a sample application. This sample application dependencies need more space that what is allocated with Cloud9. We have to increase the partition size using these commands. You can use Cloud9 bash to run these commands.
sudo growpart /dev/xvda 1
sudo resize2fs /dev/xvda1
And Download the sample application. Try following the command in the Cloud9 terminal.
git clone https://github.com/aws-samples/amazon-ecs-dotnet-app-graviton.git
Build Docker Image
Before creating the ECR repository we need to set up environment variables in Cloud9. Go to the cloud9 IDE again and configure the AWS CLI with the current region.
export AWS_REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/region)
aws configure set default.region ${AWS_REGION}
aws configure get default.region
Set up environment variables for AWS account id,
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity — query Account — output text)
echo $AWS_ACCOUNT_ID
Now we can create an ECR repository to store docker image. You can choose any name for the repository.
export IMAGE_REPO_URI=$( \
aws ecr create-repository \
— repository-name movie-app-repo \
— query repository.repositoryUri \
— output text \
)
echo Repo URI: $IMAGE_REPO_URI
After running this command you can see the image repository URI on the bash terminal.
You will need this URI when you specify the container definition in the ECS Task definition in the next steps.
Before creating a Dockerfile move to the source code directory.
cd ~/environment/amazon-ecs-dotnet-app-graviton/app/
Now create the Dockerfile in the project.
touch Dockerfile
Now open the docker file. You can use nano, vi, or Cloud9 IDE to edit the file. Then copy the following commands and paste them into your docker file. Make sure to save it.
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
# These lines copy MvcMovie.csproj project files in the current directory
# and then restore for the specified runtime, using -r.
COPY [“MvcMovie.csproj”, “./”]
RUN dotnet restore “MvcMovie.csproj” -r linux-musl-arm64
# Build dotnet project and publishes the application and its dependencies to a folder for deployment to a hosting system.
COPY . .
WORKDIR “/src/.”
RUN dotnet publish “MvcMovie.csproj” -c Release -o /app/publish -r linux-musl-arm64 — self-contained false — no-restore
# Docker build command
# You need to use an architecture-specific tag if you want to target ARM based instances.
# Note that .NET is only supported on Alpine on ARM64 and x64, and not ARM32.
FROM mcr.microsoft.com/dotnet/aspnet:5.0-alpine-arm64v8
WORKDIR /app
EXPOSE 80
COPY — from=build /app/publish .
ENTRYPOINT [“dotnet”, “MvcMovie.dll”]
Build and publish the docker images with a tag. Tag your image with the ECR registry. Run these commands to complete that task.
docker build -t movie-app .
docker tag movie-app $IMAGE_REPO_URI
Check the image is created successfully
docker images movie-app
As the last step, we need to publish the Docker image. You need to log in to the ECR repository and publish the new image you built in the previous step. Hope you remember we created environment variables earlier. We have to use them now. In the following command replace your AWS account id with $AWS_ACCOUNT_ID and replace the region with $AWS_REGION.
aws ecr get-login-password | docker login — username AWS — password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
Now, build your docker image using following command
docker build -t movie-app-repo .
After build completes, tag your image then you can push the image to repository. Make sure to replace you aws account id and the region in the command before run it.
docker tag movie-app-repo:latest aws_account_id.dkr.ecr.region.amazonaws.com/movie-app-repo:latest
Push this image to the repository
docker push aws_account_id.dkr.ecr.region.amazonaws.com/movie-app-repo:latest
Using this command you can find the information about the image in the repository
aws ecr describe-images — repository-name movie-app-repo
Create an Amazon ECS cluster
Navigate to the AWS Elastic container service console. Click on create cluster button and in the select cluster template page choose EC2 Linux + Networking go ahead with the next step. In the Configure cluster page, we need to configure the details related to the cluster.
Cluster details should be like this:
Cluster name : Graviton2ECSCluster
EC2 Instance type : t4g.medium
Number of instances: 1
In the networking section:
VPC : select TargetVPC from the dropdown
Subnets: TargetVPC-private-a-web and TargetVPC-private-b-web
Security Group: ECSServiceSG
In the Container instance IAM Role section:
Container instance IAM role: select Create new role from the dropdown
CloudWAtch Container Insights: Tick the Enable container insights check box
Now create the cluster!
After cluster creating completed need to create ECS Task Definition. On the left side navigation page, you can find an option for Task definitions. Go to Task Definition and select EC2 as Select launch type compatibility. Click on the Next step button and move to Configure task and container definitions page.
To create task and container definition enter the following values.
Task definition name: Graviton2ECSTask
Task role: none
Task execution IAM role: ContainerizeDotNetOnECSGraviton2-ECSTaskExecutionRole or use can use the name suggested at the beginning of this process
Task memory: 512
Task CPU: 1024
In Container Definition, click Add Container. Then input these values to create a container.
Container name: Graviton2Container
Image: put your IMAGE_REPO_URI. (should be look like <AWS_ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com/movie-app-repo:latest)
Port mapping: 0, 80
Next, you have to add environment variables for the container to access the Database instance. Check the outputs tab on the CloudFormation console. You can find the RDSSecretARN . copy it because you will need it to create environment variables.
In the Environment section add following environment variables.
Key
Value/ValueFrom
Value
DBHOST
ValueFrom
<RDSSecretARN from CloudFormation Outputs>:host::
DBNAME
ValueFrom
<RDSSecretARN from CloudFormation Outputs>:dbname::
DBUSER
ValueFrom
<RDSSecretARN from CloudFormation Outputs>:username::
DBPASS
ValueFrom
<RDSSecretARN from CloudFormation Outputs>:password::
DBSSLMODE
Value
none
Under storage and logging section tick the Log Configuration — Auto-configure CloudWatch Logs checkbox. Leave the rest of the things as it is and click on Add button. Now you are back on the Task definition page. Click on Create button to create the task definition. Again go to Clusters and click on your cluster name from the list. In the services, you’ll see no services there. It means that your Task definition is complete but no tasks are running yet.
Deploy the app to Amazon ECS
Go to your cluster and under the services tab click the Deploy button. Expand Compute Configuration (advanced) section. Since you have an existing cluster it should already be selected. Then select EC2 as Launch Type. now under Deployment configuration select Service and select Graviton2ECSTask as Task definition — Family from the dropdown. Revision should be LATEST.
Give Graviton2ECSService as your service name or you can use preferable name for your service. Enter value ‘2’ for desired tasks.
Let’s move to creating a load balancer. In the Load balancing — optional section, select create new load balancer and enter a name. Ensure Listener Port is 80 and Protocol HTTP. then give a name to the Target group and select HTTP as the protocol.
In the Networking boundaries, select TargetVPC from the dropdown. Then you have to choose public subnets. Under Security group, select Use an existing security group and choose the security group which is you created in the beginning using CloudFormation template. It looks like <CloudFormation-Stack-Name>-ALBSG security group. Now you can leave rest of the things to default and move with click on Deploy button. Oce it finished you can see the Tasks running, Health check status and notifications.
Since its completed, we need to enable session management for this application. Here we take the simplest route by enabling sticky session. Elastic load balancers support sticky sessions. Navigate EC2 console and click on Targe groups from Load balancing section. Choose the name of the target group use created in the previous step. On the Group details tab, in Attributes section, click on Edit. select Stickiness. For Stickiness type, select Load balancer generated cookie and leave the default value is 1 days as Stickiness duration. Now Save changes.
Now you can test the deployment! Staying on EC2 console, click on Load balancers then select Load balancer name. Copy the value of DNS Name from the description. Open that copied URL in a new browser window. That’s the sample application we deployed. Try login to the application using credentials.
Username: admin
Password: Pass@word1
This last step completed the deployment of your .Net app on Amazon ECS.
Logging and Monitoring
First confirm container insights is enabled. If you missed enabling container insights you can enable it using this command.
aws ecs update-cluster-settings — cluster Graviton2ECSCluster — settings name=containerInsights,value=enabled — region ${AWS_REGION}
In the “settings”, “name” should be “containerIsights” nad “value” — “enabled”. Go to the CloudWatch console to visualize container insights. Click on Container Insights under the Insights section. Select List View. now you can see the list of the container resources. Click on each of the resources to see the metrics.
Cluster metrics provide the view of the CPU utilization, Network transferred and Memory management. It also provides a view of number of container instance, task and service within the cluster.
Service metrics provide a view of the aggregated metrics of the tasks running and also the performance for each of the tasks.
Task metrics give you a view of the metrics for each task running in the cluster
On the CloudWatch console click to on Log Group under Logs to view logs. Select ”/ecs/<your-ecs-TaskName>” which is the log group that was created in the previous deployment step. Select that log group to show log streams from the containers in the ECS tasks. Select a log stream to view the application logs. On the screen, you can specify filters based on date and time to retrieve logs.
finally, if you are done with the process you can clean up the resources you created.