I've recently been playing around with .NET Core MVC and trying to get it running on Azure Container Service (ACS).
Why .NET Core? Because you'll be able to run those containers on Linux environments, which will generally be lower cost.
It has been quite challenging as there is quite a bit of documentation out there and some of it is out of date already (I certainly expect this to be out of date as we march towards release versions) due to the pace of change with Docker, Docker on Windows, Azure, and the Azure CLI tools. There are some tutorials which show you how to do it via VSTS and some that seem to show VS2017 tooling for deployment (I sure hope its easier...); I have not been able to activate any tooling support for Docker in VS2015.
Some of the newer capabilities like managing Azure Container Registries (ACR) is only available in CLI 2.0 preview. For example, one would think that once you've created a container registry in Azure, you'd easily be able to see a listing of images you have registered in the Azure dashboard; not so! The images can seemingly only be seen via the CLI 2.0 commands for now.
There are also multiple ways to take advantage of containers in Azure, but we'll walk through the easiest way using "Web App on Linux" to handle most of the Docker configuration.
Before you get started, you'll need the following:
- Visual Studio 2015 (or 2017)
- Latest versions of .NET
- Visual Studio tooling for .NET Core
- Azure CLI (optional)
- Docker Toolbox (for Windows 7, 8)
- Docker for Windows (for Windows 10)
Now be warned that Docker for Windows runs on HyperV while Docker Toolbox uses VirtualBox. If you run VMWare locally on your workstation, you won't be able to have HyperV enabled so you've got to settle for Docker Toolbox. This walkthrough assumes you're using Docker Toolbox, but I assume there's not too much deviation.
For this walkthrough, we're going to focus on the ACR/ACS side of things so we're going to leave the .NET Core side just a basic site. Follow the instructions here to create a .NET Core web application.
Once you've got that set up and compiled, we need to add one file to the mix: the Dockerfile. At the root of your web project, add a file named "Dockerfile":
My file contents, based off of this Stormpath tutorial, look like so:
FROM microsoft/dotnet:1.0-sdk-projectjson COPY . /app WORKDIR /app RUN ["dotnet", "restore"] RUN ["dotnet", "build"] EXPOSE 5000/tcp ENV ASPNETCORE_URLS http://*:5000 ENTRYPOINT ["dotnet", "run"]
Nate Barbettini has a good description of what each of the lines means. Pay attention to the 5000; when we move this into Azure, we'll want to change this to port 80.
For production environments, you'll want to revisit this for sure and build an optimized image using Steve Lasker's walkthrough (I have not tried it yet!) as it will yield a significantly smaller image. The base image size for the dotnet image is 542MB. The final size of my basic web application image is a whopping 683MB!
Now if you are using Docker Toolbox, you need to click on the Docker Quickstart Terminal icon which should be on your desktop. This launches the terminal that we'll be using to:
- Build the image
- Tag the image
- Upload to Azure
We're going to follow along with Barbettini's tutorial. From the Docker Terminal (terminal), change directories into your .NET application directory (where the Dockerfile was created) and build the image:
docker build -t mywebapp:latest .
This builds a Docker "repository" with the name "mywebapp" and "tag" value of "latest". Important: note the trailing "." which indicates "from the current directory".
While not strictly necessary, I would recommend running it at this point locally to make sure that it actually works. Again, we follow along with Barbettini's tutorial and run:
docker run -d -p 8080:5000 -t mywebapp:latest
The application should load at the IP address assigned to the Docker virtual machine and not necessarily localhost. To see and manage the running instance, you can use the Kitematic application that was installed with Docker Toolbox. It will generate a random name for the running container and show up on the left hand side.
Hopefully, you've got it running and you've confirmed that it works. While you're in Kitematic, terminate the container as we're going to now prep it for Azure. For Azure Web App on Linux (WAL), we will need to map the port directly to 80 (I'm sure there's a way to instruct WAL to map it at runtime, but I haven't figured that out yet). So update your Dockerfile and replace 5000 with 80.
Now we're going to remove the previous image before we compile a new one. From the terminal, type:
This will list the images we have locally. Then:
docker rmi mywebapp:latest
Verify that the image has been removed. Now we run the build command again and it's time to move onto Azure.
Our first step is to create a private ACR where we can store our image to be used in Azure. Log into the portal and type in "registry" in the search to find it:
Add a new registry and configure the settings:
I recommend creating a new resource group so that you can more easily delete all of the artifacts later. Also note to enable "Admin user". The registry should take a few moments to complete provisioning, but once it's done, go back to the Azure Container Registry to find your newly created registry and select it. Click on the Access key tab and grab the Username and Password:
Next, click on the Quick start tab. This tab provides the customized commands that we'll need to access our ACR from our local Docker terminal.
Run the following command from the terminal:
docker login mywebappreg-innovocommerce.azurecr.io
The "mywebappreg" will be whatever name you gave to your ACR registry and the "innovocommerce" will be your Azure domain. This is where you'll need the Username and Password from above. Next, we're going to tag or rename the image we built earlier:
docker tag mywebapp mywebappreg-innovocommerce.azurecr.io/mywebapp
And finally, we're going to push it into the repository:
docker push mywebappreg-innovocommerce.azurecr.io/mywebapp
This will move the image into your repository -- though there's no way to actually see it in there without the CLI 2.0 preview. The command should be:
az acr repository list -n mywebappreg -o json
(You'll need to log in first! Use az login and follow the instructions)
Now we're ready to create our Docker container instance! You have two options at this point: use the actual Azure Container Service (ACS) OR use Web App on Linux (WAL). We'll go the WAL route since it's significantly easier! From the search bar, type "web app" and you should see the Web App On Linux option:
Now we configure the web app:
- Your App name for the desired external URL
- Select your existing registry (again, for easier cleanup later!)
- And click the Configure container option
- Select Private registry for the Image source
- Now enter the tag of the image we pushed earlier: mywebappreg-innovocommerce.azurecr.io/mywebapp:latest
- Enter the URL of the ACR we created: https://mywebappreg-innovocommerce.azurecr.io
- Enter the login name and password for the admin user you used to log into the terminal.
- Leave Startup Command blank (note to Microsoft: inconsistent casing!); I suppose this may be where you could potentially map the ports (maybe?)
If everything works out, you'll be able to click OK and it will go off and provision your container!
To test it out, you can try hitting your site. As per my example, that would be http://mywebapp5542.azurewebsites.net. Be patient as it may take a bit of time for the site to come on line. Remember that this isn't an optimized image.
Next time, we'll explore how to achieve the same result with ACS and maybe optimizing the image for release!