/ azure

Deploying your Docker Container via Azure DevOps to Azure Cloud

Starting on a new side-project, I decided to go with the full Azure experience.
AzureDevOps has become a daily tool for me and in addition I always containerize my applications (no more version, OS hell).
The last missing part was deploying my containers to Azure using their Azure Container Service.

To my surprise it was a bit more difficult than I would have imagined and the Azure Portal UI/UX leaves a lot to be desired in terms of understanding what is happening or is required.
I have the same feeling a lot of times when using Azure Portal, it is very flexible but at the same time very generic.
Hopefully with this article other people won't have to go through the same struggles that I had.

Steps:

  • Containerize your application
  • Set up your Azure DevOps
  • Set up your Azure Cloud
  • Navigate to your app's url :)

Containerize your application

Introduction

I think this boils down to the individual application and your needs.
However bellow you can find what I usually employ as my dockerfile. (this is a working example but you should use it with considerations).

Implementation

FROM mcr.microsoft.com/dotnet/nightly/sdk:5.0.100-focal-amd64 AS base

WORKDIR /app

FROM mcr.microsoft.com/dotnet/nightly/sdk:5.0.100-focal-amd64 AS build

COPY ["MyApp/MyApp.csproj", "MyApp/"]
COPY ["NuGet.config", "NuGet.config"]

RUN dotnet restore --configfile ../NuGet.config "MyApp/MyApp.csproj"
COPY . .
WORKDIR /Fina

FROM build AS publish
ARG BUILD_CONFIG
RUN dotnet publish "MyApp.csproj" -c $BUILD_CONFIG -o /app/publish
RUN dotnet dev-certs https --clean

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

EXPOSE 5001
EXPOSE 5000
ENTRYPOINT ["dotnet", "MyApp.dll"]

Set up your Azure DevOps

Introduction

This step assumes you have a basic knowledge of how to use Azure DevOps and/or other similar tools to set up pipelines.

So Azure DevOps has two distinct features that behave similarly and can be used for the same exact reasons, however the context that they operate in is different. I am talking about "Pipelines" and "Releases".

This separation comes probably from the separation of CI/CD.
Pipelines are part of the Continuous Integration and Releases part of Continuous Delivery.
Pipeline usually takes code, build it, tests and creates an artifact. Release takes the artifact and releases/deploys it.
That however does not mean you cannot do Releases within your pipelines and that is where it becomes confusing and I would leave that to the discretion of the implementer.

Implementation

Flow

The flow is pretty simple, when code is pushed, a build pipeline is initiated which acts as a gatekeeper for the health of the code base.
If all is good a docker image is pushed. For this implementation I used Azure Container Registry but any registry can be used.

After the build pipeline succeeds an automatic trigger creates the new Release using the Continuous Delivery Trigger on the master branch.
This is very important in case you also want to transfer artifacts from the Build Pipeline over to the Release Pipeline.

AzureDevOps-Release-Trigger

The Release Pipeline can contain different steps, like sending some notifications or webhooks, however the important one is to execute the Azure App Service Deploy.

You will need to connect your Azure Cloud account to get access to the subscriptions etc.

Important At this point I was confused, but in hindsight it makes a lot of sense, that you can only target an existing App Service - so head over to Azure and create an App Service with target Container either for Windows or Linux.

AzureDevOps-Release-AppService-Deploy

Configuring the application

The Azure Container service cannot know what port you have exposed on your container/application so by default it looks for Port 80.

There were 2 problems in my case, my App was configured to run on Http:5000 and Https:5001.

By default Azure Container Service checks the health of the initiated container by pinging the container on Http:80. You can imagine why this is problematic.

After digging around I found out that if you want to configure the health-check to use a different port it needs to be provided as App setting with the following Key Value pair Port: XXXX

ApplicationConfiguration

The second issue was that the Container service can only direct towards http (or at least I cannot find how to switch it to https), I tried setting up https redirect but the requests always go to http and thus created an infinite redirect loop.

To counter this, I disabled https redirection on the application.

Container "hiccups"

To save you the trouble, if you believe that the container has not restarted correctly or that the logs seem funky, you might be correct.
Changes don't propagate as fast or even always, especially if Always On is turned off. Due to the way that the warm up of idle states works, the changes might not happen immediately, I had to enable Always On to make my changes appear many times. Disclaimer, I am not sure how that affects pricing.

End

Hopefully this article will help anyone having issues like myself. 🙏