Azure Web Apps and Containers

Containers have been in the back of my mind for a few months.  There does seem to be an unstoppable movement in container adoption right now, so I may as well get on the bandwagon. What triggered this for me was noticing this in Azure...


So Microsoft don't care what you write your code in, as long as you run your code in Azure.  We know that already, so hosting on Linux is no big deal.  But the option to move from bring your own code, to bring your own container (Docker Image) is new.  When you select this option, you are presented with a container configuration option, like so...



So if you want to get a quick start on containers, it's really not much effort to learn some docker commands to build and tag an image.  Equally from that point it's not too much of a challenge to create a registry and push that image to it.  In my example I created a Azure Container Registry in the portal, and pushed an image straight up there, and was able to select from the drop downs.

But you probably don't want to be managing your app that way.  If you are using containers you are probably doing so for a reason, and those reasons tend to be as you are leveraging DevOps principles.  And that means a pipeline of some kind to implement CI\CD.  I've become quite the fanboy of Azure DevOps lately, so I tend to building everything in there.



So I added a pipeline to trigger the image build and push, this would fire each time a commit to the dev branch was made (I'm keeping my code in  Azure Repos, but Azure Pipelines supports all the usual culprits from Git to Bitbucket and beyond).  

I'm targeting a Ubunto build agent for no special reason.  Well actually, that is not quite true. I did spend some time using the Windows agent on another project, but what I found was it was particular about the .net core version build tools, and I needed an extra step to download the SDK version to the agent, which seems a bit unnecessary.

For my example, the dockerfile was building a ASP.NET core 2.2.0 API on top of a Angular 6 single page app.  I'm going to write up a post on that, so won't delve too deep into those specifics here. Except to say that when the build step fails, it's usually down to how you are approaching your docker image build.

The agent tasks are just 2 steps, the first reads my Dockerfile and builds an image, the second takes a commit of that image and pushes it to my Azure Container Registry.  Both of these steps are configurable in the version 1.* Docker task in Azure Pipelines.

Not to much to see here if you configure the task for build.


  • You will be asked to authorise access to your container registry in the build step, I think this is so if you select "Qualify image name" then it can prefix the Image name with the registry name if you have not added it already.  You don't push in this step, so I can't see any other reason for it.
  • Another call-out is specifying the Dockerfile.  This will be relative to the source code, so if you have multiple projects in a VS solution, the path to your project Dockerfile is relative to the solution root.  Keep in mind that the source code has been checked out and copied to the build agent, so that is your root (or parent directory).
  • This tripped me up a few times, moving the Dockerfile about for organisation purposes is a pretty bad idea.  The build context for the image is defined by the Dockerfile location. Build context is a bigger concept than this post can cover, but just think of it as the root of your container - so you can only reach down to sub directories via docker commands (like COPY, RUN etc) but you can't navigate above it. 
  • It's not really a pipeline issue, but worth mentioning that not all .dockerignore files are made equal, and excluding **/bin might be safe for a ASP.NET Core, but that glob pattern is going to be an issue if you are building an Angular app because there will be required bin folders in the node_modules sub-directories.  I scratched my head on that one for a few hours.
  • Image name is defined using system variables generated by the build process, you want to make sure each image is tagged to be unique - so that can usually be achieved with a combination of build number and revision.
The push step is even simpler, just specify the container registry, and use the same image name configuration (including the Qualify Name option if you selected it in the build step).



So as this point, if you trigger a build, you should get yourself a new tagged image in your registry.  Just check in repositories, and then expand to see your tagged history of images.  These will now be available to select on the Web App "bring docker image" option.


The 15.* tagged version is what I selected in the container configuration for the web app at provisioning.

As an aside if you use a on-premise agent you will be better able to leverage cache and speed up you docker build step.  With the hosted agent, you are getting an agent from a pool so you will see your container layers being pulled down every time, any installs getting downloaded every time (for this example I need to download and install node to get access to npm for the angular build).

Comments