In the Part 1 and Part 2 of this series we created an ASP.Net Core app in Visual Studio 2015 and manually installed it on an EC2 instance in the AWS cloud. In Part 3 we automated the deployment using AWS OpsWorks Configuration Management Service and custom Chef recipes. Part 4 will utilize the AWS Elastic Beanstalk service as an alternative to OpsWorks. “AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.”
There are numerous advantages with Elastic Beanstalk with the primary one being it’s very easy to deploy a typical three tiered app – [Web, Network, and Data Tier]. There is overlap between OpsWorks, Elastic Beanstalk, and CloudFormation so it really depends on how much control you want and what workflow you require. Here is a really good white paper from AWS on the subject. For us Elastic Beanstalk will be the focus.
One other comment before we get started. As I covered in Part 1 you should install the AWS Toolkit for Visual Studio. There is an option to publish directly to AWS Elastic Beanstalk. It will create for you the components like Load Balancers, VPC’s, Pubic IP Addresses, Monitoring, and EC2 Instances. As of this writing you can only select Windows instances to run the application. That may be fine for you but for this blog series we use ASP.NET Core running on Linux so we will need another way to set it up. AWS overcomes this limitation by use Docker Containers.
Step 1: Update the Application by Adding Docker Support.
- To support Docker Containers in the app you will need to download the Visual Studio Tools for Docker.
- Launch Visual Studio 2015 and open the app you created in Part 1 of this blog series.
- Within the Solutions Explorer window right click on your application then select “Add” the choose “Docker Support”.
- It will create a few files and you will need to update the “Dockerfile to use ASP.Net Core 1.1.0. Open Dockerfile and change “aspnetcore:1.0.1” to “aspnetcore:1.1.0”.
- In order for this to work you may need to update the .NET frameworks to use v.1.1.0. For me it required numerous attempts to get it updated and compile clean.
- Once your updated hit F5 and it should launch the application from within a Docker Container. You should the splash screen.
- Within the Solutions Explorer window right click on your application then select “Add” the choose “Publish”.
- Select “Custom” and give it a name and click “OK”.
- I changed my “Target location” because the default is buried pretty deep in the file system. We will need to run some command line commands from Powershell so make a note where you published.
- Select Publish.
At this point there are a few options to prepare the application for deployment within Elastic Beanstalk. You can either:
- Push the content to a private online Docker repository like Docker Hub or AWS EC2 Container Service.
- Push the content to a gitHub repository. Requires a command line. Here’s how.
- Zip up the content and upload it to an S3 Bucket.
For other use cases check out Run a Docker Container from the Docker Registry and Use Private Docker Repositories.
For this exercise and to utilize another AWS service I have elected to use EC2 Container Service.
Step 2: Create a Docker Repository
In order for Elastic Beanstalk to load your docker containers with your application you will need to store it a Docker style repository. For this exercise we will use the AWS repository called EC2 Container Service. “Amazon EC2 Container Service (ECS) is a highly scalable, high performance container management service that supports Docker containers and allows you to easily run applications on a managed cluster of Amazon EC2 instances.”
- Login to the AWS Console if you are not already.
- Select EC2 Container Service from the main menu then click “Create repository”.
- Click “Next Step”. The next screen will display the steps required to publish your docker image.
- To publish your docker image you will run through the steps above one at a time.
- Open up Powershell and change directories to where you published the app.
- After the first command above to request login AWS will send back a very long command for you to copy and paste back to the command line. I had a problem because Powershell truncates really long lines with newline characters. After you copy the response open up a text editor and paste in the contents. Remove all new lines. Its should resemble one long line.
- Finally due to this bug “Some versions of Docker for Windows use a credential manager called
wincred
, which does not properly handle the Docker login command produced by aws ecr get-login“. The fix is to remove the https:// scheme from the registry argument in the Docker login command. Its appears close to the end of the line. - Then copy and paste the newly formatted long line back in to Powershell. It should reply with “Login Succeeded”.
- Copy and paste the remaining commands until the image is pushed to ECS.
Step 3: Launch a new Application in Elastic Beanstalk
If you remember from the first three parts of this series the ASP.Net Core Web Application uses kestrel for its web server. In order to provide some enhanced web services we used an Nginx reverse proxy to serve requests to kestrel. This configuration will require a second image to contain an “nginx-proxy” which will be pulled from The Docker Store. Since Elastic Beanstalk now supports Multi Container Docker Environments this will easy to configure. See Multi Container Docker Configuration for all the details but I will build the configuration bundle here to support this application.
- First create a directory on your local systems to hold the configuration bundle. The name is not important but I named mine “dotnetcoreappdocker”.
- In the new directory create a new text file called Dockerrun.aws.json and insert the following content:
{ "AWSEBDockerrunVersion": 2, "volumes": [ { "name": "dotnetcoreapp", "host": { "sourcePath": "/var/app/current/dotnetcoreapp" } }, { "name": "nginx-proxy-conf", "host": { "sourcePath": "/var/app/current/proxy/conf.d" } } ], "containerDefinitions": [ { "name": "dotnetcoreapp", "image": "<strong>YOUR IMAGE URI HERE</strong>", "essential": true, "memory": 128 }, { "name": "nginx-proxy", "image": "nginx", "essential": true, "memory": 128, "portMappings": [ { "hostPort": 80, "containerPort": 80 } ], "links": [ "dotnetcoreapp" ], "mountPoints": [ { "sourceVolume": "nginx-proxy-conf", "containerPath": "/etc/nginx/conf.d", "readOnly": true }, { "sourceVolume": "awseb-logs-nginx-proxy", "containerPath": "/var/log/nginx" } ] } ] }
- Note the line “image”: “YOUR IMAGE URI HERE” needs to be replaced with the contents you used in Step 2 above command number 5. Something like “??????????.dkr.ecr.us-east-1.amazonaws.com/dotnetcoreappdocker:latest”. You always go back to EC2 Container Service then select your repository then “View Push Commands” to find the URI.
- When your done save the file.
- Within your configuration bundle directory create a directory called “proxy”.
- Within “proxy” directory create a directory called “conf.d”.
- Within “conf.d” create a new text file called “default.conf” and add the following content:
server { listen 80; server_name localhost; root /var/www/html; location / { proxy_pass http://dotnetcoreapp:80; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } }
Whats interesting here is the “proxy_pass http://dotnetcoreapp:80” line. Docker can create special “links” to allow different containers to communicate. In the file “Dockerrun.aws.json file above where nginx-proxy was setup there is a “links” section. This allows the proxy to reference the dotnetcoreapp by name and connect to the kestrel server in other container. - Here’s what the file systems looks like:
| |____dotnetcoreappdocker | | |____Dockerrun.aws.json | | |____proxy | | | |____conf.d | | | | |____default.conf
- Now zip up the configuration bundle. Its important to be in the root directory of this bundle when zipping the content. On a MAC type:
cd dotentcoreappdocker zip -r ../dotnetcoreappdocker.zip *
Step 4: Launch a new Application in Elastic Beanstalk
- Login to the AWS Console if you are not already.
- Select Elastic Beanstalk from the main menu. If this is the first time you opened Elastic Beanstalk you should see the getting started page. If not click here. This screen lets you create an application with a few clicks. You could select “Create New Application” and go through a seven details setup but we can modify everything later
- Click “Select a platform” and choose “Multi-container Docker”.
- Click “Launch Now” to up the Application and Environment:
- Elastic Beanstalk will create the following:
- everything for including a sample php application.
- S3 Bucket to store the environment data
- Security Groups
- Elastic Load Balancer
- Auto Scaling Group Policy and Launch Configurations
- An Ec2 Instance
- Cloud Watch Alarms
Once its deployed (about 6-7 minutes) we will simple deploy our on configuration we created in the last step. But first Open the Cloud Formation Screen from the AWS Console main menu.
- Select the Outputs Tab on the newly created stack Elastic BeanStalk created.
- Click the link under value. Its the public URL of the Elastic Load Balancer created for you.
- The page displays the sample app Elastic Beanstalk created. There are some links to videos you may find useful when deploying docker containers.
- Before we deploy our new app we need to add permissions to the newly created IAM role elastic Beanstalk created. Launch the IAM screen in the main AWS Console, select ‘Roles” from the left menu the select the role created by Elastic Beanstalk. Should be named something like aws-elasticbeanstalk-ec2-role and add the policies called “AmazonEC2ContainerServicefor EC2Role” and “AmazonDynamoDBDBFullAccess” like this:
- Lastly reenter the Elastic Beanstalk page and select the link “My First Elastic Beanstalk Application”.
- Select “Application versions” in the left menu to expose application installed on the Ec2 instance.
- Select the “Sample Application” and then “Delete” the “Done”. Time to reply our own version.
- Select “Upload”, give it a version name and choose the zipped up file we created Step 3 above.
- Select “Upload” then select the new app we uploaded and select “Deploy”.
At this point Elastic Beanstalk will load our configuration bundle and install the two containers we setup. All the deployment details will be handled by Elastic BeanStalk.
Final Step: Checkout the new app and Clean up
- Reload the Elastic Load Balancer we checked earlier and you will now see our application running in Elastic Beanstalk. There is also a link at the top right of the Environment Page. Looks something like this: “http://default-environment.ibgnvd28ge.us-east-1.elasticbeanstalk.com”. Remember to /Books to the url so see the DynamoDB page.
- Remember to delete all the resources created in this blog. You can go to the Application page in Elastic Beanstalk and under the “Action” drop down select “Delete application”.
- If you created an EC2 Container Service Image return to the main page there, select “Repositories”, select the one you created and “Delete repository”.
In Closing
If you made it to the end of this series well done. You a very persistent and patient person.
I hope you enjoyed this four part series on “HOWTO Build an ASP.NET CORE Web App on AWS Running Linux with DynamoDB”. AWS is a seriously powerful platform to quickly deploy enterprise level applications that are extensable and scalable as you can dream up.
Cheers