Previously, I discussed that I started a side project to discover better ways to build “web apis”. In this case, I am using ASP.NET Web API but I think the lessons I am after could be applied to many technologies and clouds.
One of the things I was looking for was some light continuous deployment after code is committed. At the same time, I wanted to see what the process was to get different kinds of web sites, using different frameworks and technologies, running on Azure Web Sites.
After all, the marketing says it supports .NET, Java, PHP, Node.js, and Python. It also claims continuous deployment. So is it faster, easier to use, and more fun?
What To Deploy?
I created a repository on GitHub called WebJumpStart for the purpose of testing out a few tricks Azure Web Sites has up its sleeve.
In it, you will find three web sites.
- AspNetMvc is an ASP.NET 5 MVC site right out of the gate after File > New Project.
- HelloWorld is just static content files (simple html/js/css files).
- NodeExpress is the Node Express starter site, also unmodified (it is a bit out-of-date at this point, but the magic of npm ensures the versions I’ve picked in package.json are there for me to use).
Note that only one of these projects is based in ASP.NET. HelloWorld and NodeExpress could have been built with notepad, Sublime Text, Brackets whatever…
But wait, when I deploy to Azure Web Sites, how is it going to know which of these sites I want deployed? It turns out, Azure Web Sites has a built in engine that takes care of these deployment issues. It’s time to meet Kudu.
The Code Doesn’t Know
The Kudu Documentation on GitHub is pretty good. Just using that I was able to reach my goal:
- Deploy each of these folders as a separate web site in Azure Web Sites.
- Keep the code repository free from any of this configuration information.
Kudu operates by convention, but is also highly configurable. It was a mission of mine to rely solely on convention and have none of that configuration present in the committed code. This may not be your goal. In fact, sometimes it makes a ton of sense to customize the Kudu engine to do more than just deploy your code. I look forward to getting to that.
I chose to take advantage of the conventions to pick each folder for each website. Here are my websites running in Azure:
As you can guess, the contents of each folder in the repository are being used to build and deploy each of these separate websites.
There are many great articles about deploying to Azure Web Sites from GitHub. Here are several posts with great insight into deploying from source code repositories:
Publishing from Source Control to Azure Websites – straight from the Azure Documentation
Deploying TWO websites to Windows Azure from one Git Repository – Scott Hanselman explains the details of selecting which ASP.NET project to deploy from your repository
Iris Classon brings together TeamCity, ASP.NET MVC, Azure Web Sites, and MSTest – a tour de force on bringing a lot of technology together the way a real DevOps scenario might.
Deploying an Azure Web Site Using Git and Continuous Integration – Kirk Evans uses Visual Studio Online instead of GitHub
Azure Web Sites Deployment and Unit Testing – Eli discusses using GitHub deployment WITHOUT granting the default permissions to Azure. Then he gets it to validate his unit tests.
Starting with Continuous Integration in the Cloud With Steven Edouard – In this podcast, Steven Edouard talks about how Azure Web Sites is really a continuous deployment aware compute engine, and how he customizes Kudu deployment scripts to do interesting things you might not associate with just “web sites”. Don’t miss his Azure DevOps Labs repository!
Selecting an ASP.NET Project to Deploy
The Kudu deployment engine built into Azure Web Sites has a convention for selecting a project or project folder. That is how I will link these projects to their various sites in the cloud.
Beginning with the AspNetMvc project, I went to the Configure tab in the Azure portal and scrolled down to app settings. Kudu will look for a Project setting, and for ASP.NET applications, you provide the path to the project file (in this case, a .csproj).
Just Select a Folder To Deploy A Web Site
For the HelloWorld and NodeExpress projects, there are no Visual Studio style project files. There’s no web.config file in the code repository to set up IIS either. But Kudu is still ready to deploy them. You specify the folder in your repository to serve as the root of your deployed web site.
Here’s HelloWorld’s setup for a basic HTML web site.
And here’s the setup for NodeExpress. Note that you can supply a desired Node version in configuration. But please do not confuse this with the NEED to have this configured. Kudu analyzed the repository to make this decision.
I can infer this because my other Azure Web Sites had the same WEBSITE_NODE_DEFAULT_VERSION app setting in place. I simply deleted it out of curiosity and my ASP.NET MVC site and Basic HTML5 site worked fine.
But I can do better than inference!
Let’s go look at the code!
The primary decision point (as of this writing) was the presence of a package.json file, but it’s willing to poke around a little more to decide if your project “looks like Node”. The detection is there for us to see in this code excerpt I pulled from NodeSiteEnabler.cs.
So, Kudu just figures this all out?
It can, yes. Like any convention based system, it will figure it out if you follow the rules the system happens to be following. If you take a look at the Deployments tab on your Azure Web Site, you can see Kudu figuring this all out.
Open the log next to “Running deployment command…”:
And you’ll see the engine figures out the folder I gave it was a Node.js project. It runs npm install to make sure the packages are up to date.
Here’s an excerpt from that log:
Handling node.js deployment.
KuduSync.NET from: 'D:\home\site\repository\NodeExpress' to: 'D:\home\site\wwwroot'
Deleting file: 'NodeExpress.njsproj'
Deleting file: 'NodeExpress.sln'
Copying file: 'app.js'
Copying file: 'package.json'
Looking for app.js/server.js under site root.
Using start-up script app.js
The package.json file does not specify node.js engine version constraints.
The node.js application will run with the default node.js version 0.10.32.
The engine removed files no longer in the repository, figured out this was a Node.js project and read through the package.json file to see if I specified a version of Node. A suitable web.config was generated for Azure Web Sites to use. Then it updated the packages, and that’s where I cut the log off. After that, it was done.
And the code doesn’t know
There is nothing preventing you from committing a web.config to your repository that sets up iisnode. There is no reason you can’t use the excellent Visual Studio Tools for Nodejs, either. But you don’t have to. With the built-in Kudu deployment engine in Azure Web Sites and a Node.js code repository, there is nothing more to do to get your site deployed.
And you might value the code being agnostic over committing the configuration right into the repository. I’d like to check on the ability to use this same repository to deploy to other platforms. You might argue that could control vendor lock-in, which certainly is a concern many people have over going to platform-as-a-service.
Where to go from here
This was a nice step forward in getting ready to build my reference “web api + front-end” application. I now knew I could put everything in one GitHub repository (or source control repository of most any kind) and even into one Visual Studio solution and I could deploy multiple Azure Web Site instances. This means I could build and test my ASP.NET Web API in the same solution as some client-side static files (AngularJS based) but it would all deploy with a few clicks and little ceremony.