Deploying SKS Blazor migrated app to Azure Container Instances
This document provides a detailed guide for deploying SKS Blazor migrated applications using Azure Container Instances (ACI). It covers the necessary steps for setting up a local Docker environment, building container images, defining base images, and pushing images to container registries, specifically GitHub Container Registry (GHCR) and Azure Container Registry (ACR). Additionally, it includes instructions for creating and running containers in Azure, along with important considerations for ensuring successful deployment, particularly regarding the choice of base images and runtime dependencies for Windows-based applications.
Installing Docker local environment.
To first build a Docker image with the SKS application is important to install and configure a local Docker runtime environment.
Add containers and hyper-v features on windows:
Open Windows Features:
Press Win + R, type optional features, and press Enter.
Or, search for "Turn Windows features on or off" in the Start menu and open it.
Enable Containers:
In the Windows Features dialog, scroll down and check the box for Containers.
Enable Hyper-V:
In the same list, find and check Hyper-V (expand it and ensure both "Hyper-V Management Tools" and "Hyper-V Platform" are checked).
Apply and Restart:
Click OK.
Windows will search for required files and apply changes.
Restart your computer when prompted.
Download Docker Desktop from: https://www.docker.com/products/docker-desktop
Run the installer (Docker Desktop Installer.exe)
During installation:
Enable "Install required Windows components for WSL 2"
Enable "Use Windows containers instead of Linux containers"
Click "Ok" to install
Wait for installation to complete
Restart your computer
Run Docker desktop application.
Right click on Docker tray icon and select switch to windows containers (Since the images used to build the WebMap Blazor images are Windows OS based it’s necessary to work with Windows containers).
In settings verify that desktop-windows is running
How to build a Windows image with SKS app.
For this exercise the SKS application was used. You can find the application along with the Dockerfile in the repo: https://collaboration.artinsoft.com/tfs/Product/Product/_git/BlazorDemos
The branch with the changes and the Dockerfile is: support/DockerContainerWindowsSKS.
Before creating the Dockerfile it’s important to define the base image used to create the container.
Defining a base image
There a are 3 different types of base image the election should be based on the requirements:
Linux Images
Base OS: Linux (usually Debian or Alpine).
Image Example: mcr.microsoft.com/dotnet/aspnet:9.0
Size: Smallest.
Performance: Fast startup, low resource usage.
Compatibility:
Runs on Linux hosts (including most cloud/container platforms).
Cannot run Windows-specific workloads (e.g., Windows Forms, WPF, COM).
Best for:
Web apps (Blazor, ASP.NET Core, APIs).
Cloud-native deployments (Azure Container Apps, Kubernetes, Docker Hub).
Nano Server Images
Base OS: Windows Nano Server (minimal Windows kernel).
Image Example: mcr.microsoft.com/dotnet/aspnet:9.0-nanoserver-1809
Size: Smaller than Server Core, larger than Linux.
Performance: Good, but not as fast or small as Linux.
Compatibility:
Runs only on Windows hosts (Windows containers).
No support for full .NET Framework, Windows Forms, WPF, or GDI+.
Only supports .NET Core/.NET 5+ console and web apps.
Best for:
.NET Core web apps that require Windows but not full Windows APIs.
Server Core Images
Base OS: Windows Server Core (more complete Windows environment).
Size: Largest.
Performance: Slower startup, higher resource usage.
Compatibility:
Runs only on Windows hosts (Windows containers).
Supports full .NET Framework, Windows Forms, WPF, GDI+, COM, etc.
Best for:
Legacy .NET Framework apps.
Apps needing full Windows APIs (desktop, GUI, COM, etc.).
Since most migrations come from windows architecture usually they are tightly coupled to windows environments, also WebMap Blazor code is compiled and designed to target Windows Desktop runtime that’s why the selected base image for the SKS POC is Server Core Images.
Once the based image is defined, a Dockerfile should be created to perform the image build. The Dockerfile used for this exercise can be found in the branch mentioned above.
After creating the Dockerfile, open a command line window pointing to the same folder where the dockerfile is and run the build command to generate an image.
docker build --no-cache -t <desired-image-name>:<version>
You should have the image created in the docker desktop UI.
Then you can run the image locally as a container using the docker run command.
docker run -p 8080:8080 -p 8081:8081 --name <desired-container-name> <image-name-used-build-command>
There should be a new container named sks_blazor_container created
Since one of the ports exposed when running the container is 8080. The app will listen in http://localhost:8080
Next step is to push the image to a Container registry so it can be run from the Azure Container instances app. But first you need to define which container registry to use.
Define container registry
These are some of the most common container registry options:
Git Hub Container Registry
Free for public repositories and generous free tier for private images.
No extra Azure cost (unlike ACR, which may incur charges after the free tier).
Easy integration with GitHub Actions for CI/CD.
Widely supported by Azure Container Apps and Azure Web App for Containers.
No vendor lock-in—you can use the same registry for other platforms.
Docker Hub
Free for public images (rate limits apply).
Simple to use and supported everywhere.
Private repositories are limited to the free tier.
Azure Container Registry
If you need enterprise features (private networking, managed identities, geo-replication).
If you want tight Azure integration and are comfortable with potential costs.
Using GHCR to push the image to the remote repository
Go to GitHub.com → Settings → Developer Settings → Personal Access Tokens → Tokens (classic).
Click "Generate new token (classic)"
Select the following scopes:
read:packages
write:packages
delete:packages (if you need to delete containers)
Copy the generated token
Login the local docker environment to GHCR:
echo <GENERATED-TOKEN>| docker login ghcr.io -u <YOUR_GITHUB_USERNAME> --password-stdin
Tag the image in GHCR:
docker tag <image-name>:<version> ghcr.io/<YOUR_GITHUB_USERNAME>/<image-name>:<version>
Push the image
docker push ghcr.io/<YOUR_GITHUB_USERNAME>/<image-name>:<version>
Using ACR to push the image to the remote repository
Open the Azure Portal
Go to https://portal.azure.com and sign in with your Azure account.
Open Azure Cloud Shell
In the top-right corner of the portal, click the Cloud Shell icon (it looks like a terminal or command prompt).
When prompted, select Bash as your shell environment.
If this is your first time, you may be asked to create a storage account—follow the prompts to set it up.
Create a resource group.
az group create --name <resource-group-name> --location <location>
Create ACR
az acr create --resource-group <resource-group-name> --name <acr-name> --sku Basic
Go back to you local environment, open a cmd and login to azure.
az login
Login to acr.
az acr login --name <acr-name>
Tag the image.
docker tag <image-name>:<version> <acr-name>.azurecr.io/<image-name>:<version>
Push the image.
docker push <acr-name>.azurecr.io/<image-name>:<version>
Create an Azure Container instance that runs the pushed image.
Open the Azure Portal
Go to https://portal.azure.com and sign in with your Azure account.
Open Azure Cloud Shell
In the top-right corner of the portal, click the Cloud Shell icon (it looks like a terminal or command prompt).
When prompted, select Bash as your shell environment.
If this is your first time, you may be asked to create a storage account—follow the prompts to set it up.
Create a resource group (If you don't have one).
az group create --name <resource-group-name> --location <location>
Create Azure Container Instances.
Using GHCR:
az container create --resource-group <resource-group-name> --name <aci-name> --image ghcr.io/<YOUR_GITHUB_USERNAME>/<image-name>:<version> --registry-login-server ghcr.io --registry-username <YOUR_GITHUB_USERNAME> --registry-password <GENERATED-TOKEN> --dns-name-label <desired-site-name> --ports 8080 8081 --os-type Windows --cpu 2 --memory 4
Using ACR:
Go back to Azure Portal
Navigate to Your Container Registry
In the left sidebar, select "All services" and search for "Container registries".
Click on your desired ACR instance from the list.
Access the Access Keys Section
In the ACR blade, find and select "Access keys" in the left menu.
View or Enable Admin User
By default, the Admin user is disabled for security reasons.
To generate access keys, toggle Admin user to Enabled.
Copy Username and Passwords
After enabling, you will see:
Username (usually the registry name)
Password and Password2 (two interchangeable passwords)
az container create --resource-group <resource-group-name>
--name <aci-name>
--image <acr-name>.azurecr.io/<image-name>:<version> --registry-login-server <acr-name>.azurecr.io
--registry-username <username-from-accesskeys>
--registry-password <password-from-accesskeys>
--dns-name-label <desired-site-name>
--ports 8080 8081
--os-type Windows --cpu 2
--memory 4
Navigate to the deployed app. In any browser navigate to: http:// ..azurecontainer.io:/
Important considerations
Current SKS app requires a to run in a mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022 image because migrated app and dcp classes are compiled using Microsoft.WindowsDesktop.App runtime:
This tells .NET to target the Windows Desktop runtime, which is not included in the ASP.NET Core runtime images (mcr.microsoft.com/dotnet/aspnet).
The aspnet image only includes Microsoft.AspNetCore.App and Microsoft.NETCore.App, not Microsoft.WindowsDesktop.App.
Under normal circumstances build and runtime images are different for optimization purposes:
Windows Desktop apps (WPF/WinForms) are not designed to run in containers—they require a Windows session and often access the UI, which is not available in containers. Blazor projects should not require the Windows Desktop runtime unless you are using desktop-specific APIs.
Telerik.UI for Blazor Trial is currently being obtained from a local repository because windows image cannot access https://ais-build-w7.artinsoft.com:8625/nuget/researchExternal/v3/index.json and public feed doesn’t have the required version https://nuget.telerik.com/v3/index.json . The issue with ais probably has to do with network security constraints such as firewalls, antiviruses or certificates. Possible solutions: consume the package from a public feed such as packages.mobilize or fix the network connection issue between the container and ais server.
Last updated