.NET Core Workers in Azure Container Instances
In .NET Core 3.0 we are introducing a new type of application template called Worker Service. This template is intended to give you a starting point for writing long running services in .NET Core. In this walkthrough you’ll learn how to use a Worker with Azure Container Registry and Azure Container Instances to get your Worker running as a microservice in the cloud.
Since the Worker template Glenn blogged about is also available via the dotnet new
command line, I can create one on my Mac and edit the code using Visual Studio for Mac or Visual Studio Code (which I’ll be using here to take advantage of the integrated Docker extension).
dotnet new worker
I’ll use the default from the Worker template. As it will write to logs during execution via ILogger
, I’ll be able to tell quickly from looking in the logs if the Worker is running.
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
Visual Studio Code’s Docker tools are intelligent enough to figure out this is a .NET Core app, and will suggest the correct Docker file via the Command Palette’s Add Docker files to workspace
option.
By right-clicking the resulting Dockerfile
I can build the Worker into a Docker image in one click.
The Build Image option will package my Worker’s code into a Docker container locally. The second option, ACR Tasks: Build Image would use Azure Container Registry Tasks to build the image in the cloud, rather than on disk. This is helpful for scenarios when the base image is larger than I want to download locally or when I’m building an application on a Windows base image from Linux or Mac. You can learn more about ACR Tasks in the ACR docs. The Azure CLI makes it easy to login to the Azure Container Registry using the Azure CLI. This results in my Docker client being authenticated to the Azure Container Registry in my subscription.
az acr login -n BackgroundWorkerImages
This can be done in the VS Code integrated terminal or in the local terminal, as the setting will be persisted across the terminals’ environment. It can’t be done using the cloud shell, since logging into the Azure Container Registry requires local shell access so local Docker images can be accessed. Before I push the container image into my registry, I need to tag the image with the URI of the image once it has been pushed into my registry. I can easily get the ACR instance URI from the portal.
I’ll copy the URI of the registry’s login server in the portal so I can paste it when I tag the image later.
By selecting the backgroundworker:latest
image in Visual Studio Code’s Docker explorer pane, I can select Tag Image.
I’ll be prompted for the tag, and I can easily paste in the URI I copied from the portal.
Finally, I can right-click the image tag I created and select Push, and the image will be pushed into the registry. Once I have a Docker image in the registry, I can use the CLI or tools to deploy it to Azure Container Instances, Kubernetes, or even Azure App Service.
Now that the worker is containerized and stored in the registry, starting an instance of it is one click away.
Once the container instance starts up, I’ll see some logs indicating the worker is executing, but these are just the basic startup logs and not my information-level logs I have in my Worker code.
Since I added Information-level logs during the worker’s execution, the configuration in appsettings.json
(or the environment variable for the container instance) will need to be updated to see more verbose logs.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Once the code is re-packaged into an updated Docker image and pushed into the Azure Container Registry, following a simple Restart…
… more details will be visible in the container instance’s logging output.
The Worker template makes it easy to create long-running background workers that you can run for as long as you need in Azure Container Instances. New container instances can be created using the portal or the Azure Command Line. Or, you can opt for more advanced scenarios using Azure DevOps or Logic Apps. With the Worker template making it easy to get started building microservices using your favorite ASP.NET Core idioms and Azure’s arsenal of container orchestration services you can get your microservices up and running in minutes.
I want to implement CI CD on worker service and have to deploy worker service on AKS. What steps should I follow in CI CD?
Hi Brady, good article. How do I configure healthcheck endpoint for worker service in container so that Kubernetes/Swarm can know if it is down?
Hi,
Thank you very much for that article.
Is is good to use this WorkerService in docker container as RabbitMQ consumer on Azure Containers ?
I am not familiar with Azure, could you give a tip?
Best regards
Brady, With new SDK Worker template in csproj, i am getting the following error when i build the docker image.
error MSB4236: The SDK ‘Microsoft.NET.Sdk.Worker’ specified could not be found.
FROM microsoft/dotnet:3.0-runtime AS base
FROM microsoft/dotnet:3.0-sdk AS build
Any help would be appreciated.
Sorry about that - it's the nature of the beast that our SDKs are a little ahead of our Docker image publishes. I'm happy to see you putting it through the loop - apologies for the //build/-caused delay in response.
Change your Dockerfile to match this below:
FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS baseWORKDIR /appFROM mcr.microsoft.com/dotnet/core/runtime:3.0 AS buildWORKDIR /src
Thanks Brady. That worked. 🙂 I actually used runtime image as base and SDK image for build.
Hello Brady. Can I deploy the workers to Azure web apps instead of Container service? What is the difference between them?
You can push them to App Service. If you install the WebJobs SDK NuGet, they’ll even show up as WebJobs. 🙂
Going forward does that mean the default way to write a WebJob in Core is to use
BackgroundServic
e viadotnet new worker
?That is indeed one way. My favorite way, personally, but yes. The VS publishing tools will publish a Worker to App Service as a WebJob.
Hey, Great article, had been looking for windows background service like implementation.However what difference would it make if I just write my service like a console application and run it on docker?
Did you see Glenn’s article on using the Worker for Windows services?
HangFire provides with the ability to schedule the tasks with chron pattern. There is an alternative https://github.com/kdcllc/CronScheduler.AspNetCore.
Hi, thanks for this article .
I have one question though, when i read the ACI document, it was mentioned that it isbideal for scenarios where you run the applixation for some time and then shutdown the container as ACI charges per second. Then why someone will creates a always running worker in ACI ?
You're right in that ACI charges per-second, so it isn't typically thought of as a host for forever-running containers. That said, the price of ACI instances have been reduced significantly so for some workloads it may be more attractive now. ACI is that it works great for not only testing one's containers out, but for scenarios in which you have some other "thing" - like scheduled CLI execution or a Logic App running on a...
Thanks Brady for explaining well.
Btw SF Mesh is also a good place for containers.
Brady, I didn’t get to read the whole article, but my question is, is the worker available if we are hosting our app on a dedicated server and NOT Azure?
Secondly, what’s the difference between Worker service and the product called “HangFire”? Do they both accomplish the same thing? If yes, is it better to use yours for long scheduling jobs that is is running 24/7?
Thanks!
..Ben
Hangfire existed long before the generic host and the worker template and is a valid alternative. It’s much more feature rich. If anything I’d expect a future where more frameworks like hangfire re-plat on top of the generic host. The generic host is trying to be a low level building block for higher level frameworks like hangfire.
@David;
Thanks David for clear answer.
Totally agree with David after reviewing HangFire. I see so much potential for these two things to work well together.
Pardon me, as I missed the second question – I’m unfamiliar with HangFire. I’ll mention HangFire to Glenn and investigate it myself. But unless Glenn is aware of it, the Worker and HangFire are mutually exclusive concepts.
Yes, Ben, you can totally use the Worker template "outside of Azure." Glenn wrote a fantastic blog last week on a key non-cloud scenario for the Worker project - you can use these to build Windows services, too. So they're "not just for cloud," but they sure do make microservice development easier, so they're great for cloud-native scenarios. Keep watching the blog, we have a few other use-cases on the horizon we'll be showing off for...