Run .NET Application on Docker 🐳

Containerizing your application these days has become somewhat of a necessity in most projects. It allows you to deploy and horizontally scale your application in simpler fashion using Docker Compose or Kubernetes.

Containers include everything your application needs to run, which simplifies deployment. You don't have to worry about installing dependencies on the server, because they're included in the container. They also ensure that your application runs the same way in every environment, from a developer's local machine to a test environment to production. This eliminates the "it works on my machine" problem.

Let's see how to simply prepare a Dockerfile that allows you to run your application on Docker.

Before doing anything please note that this tutorial is only applicable on Windows, and you need to install Docker (and preferably Docker Desktop too) before the following steps.

Sample API

First of all, let's create a project and add the following controller that will allow us to test our application after running it on Docker.
using Microsoft.AspNetCore.Mvc;

namespace HARDCODE.API.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class HomeController : Controller
    {
        [HttpGet]
        [Route("test-docker")]
        public IActionResult TestDocker()
        {
           return Ok("Docker is working fine");
        }
    }
}
That should do it. Okay now let's now focus on the important part which is preparing the Dockerfile.

Dockerfile

A Dockerfile is a text file that contains a set of instructions used to create a Docker image. These instructions include actions like setting the base image to use, copying files from your local system into the Docker image, running commands inside the image, and specifying the command that should be run when a container is started from the image.

Let's prepare a simple Dockerfile that can run a .NET 8.0 application.
# Stage 1: Build the application
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY . /app
RUN dotnet restore

# Copy everything else and build the application
COPY . .
RUN dotnet publish -c Release -o out

# Stage 2: Run the application
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "HARDCODE.API.dll"]
This Dockerfile does the following:

1. It uses the .NET 8.0 runtime image as a base image.
2. It uses the .NET 8.0 SDK image to restore NuGet packages, build the application, and publish it.
3. It defines a final stage that uses the base image, copies the published application into it, and sets the entry point to run the application.

Replace the directories and "HARDCODE.API.dll" with the actual paths to your .csproj file and the output DLL file.

It's common practice to add your Dockerfile to the root directory of your solution (where your .sln file exists).

Also, note that this is a basic Dockerfile and might need to be adjusted based on your specific needs, such as if your application needs to connect to a database or if it has other specific requirements.

Building the Image

To build your solution you need to run the following command on cmd in the path where the Dockerfile exists. 
docker build -t hardcode-sample .

 Here's a breakdown of the command:

docker build: This is the Docker command to build an image from a Dockerfile.

-t hardcode-sample: The -t option is used to tag the image with a name. In this case, the name is hardcode-sample. This name can be used later to refer to the image, for example when running a container from the image.

The dot at the end: This specifies the build context, which is the set of files that are available to be copied into the image during the build. In this case, the build context is the current directory (.), which means all files in the current directory and its subdirectories are available to be copied into the image. The Dockerfile is expected to be located in the build context.

Okay now that your build has run successfully you can view your images if you have Docker Desktop as follows after you open the images tab from the left.

Perfect! Now that our image has built successfully let's run it in a container.

Running the Container

The next step is to run a container which contains the image we just built in the previous step and to do so we just need to run the following command.

docker run -p 12334:8080 --name hardcode-container  hardcode-sample

 Here's a breakdown of the command:

docker run: This is the Docker command to create and start a new container.

-p 12334:8080: The -p option is used to map a network port on the host to a port in the container. In this case, port 12334 on the host is mapped to port 8080 in the container. This means that if your application inside the container is listening on port 8080, you can access it at port 12334 on your host machine.

--name hardcode-container: The --name option is used to assign a name to the container. In this case, the name is hardcode-container. This name can be used later to refer to the container, for example when stopping or removing the container.

hardcode-sample: This is the name of the Docker image to create the container from. This image should have been previously created with a docker build command.

So, this command will create and start a new container from the hardcode-sample image, map port 12334 on the host to port 8080 in the container, and assign the name hardcode-container to the container.

After you run it successfully, your Docker Desktop should be showing this on your containers tab.

This should do it. Now let's try to hit our sample API test-docker which we created at the beginning.

Communicating With the Container

Now we've set our port of communication to be 12334 so we need to try to communicate with our sample API through this port on the localhost where it is hosted. So, let's just curl the following URL and see what happens.

curl http://localhost:12334/home/test-docker

Perfect! Seems like our sample API is well and alive inside the container. Now this container is ready to be deployed or scaled using Kubernetes or Docker Compose.

Comments

Popular posts

Google & Microsoft Token Validation Middleware in ASP.NET Applications

Publish and Consume Messages Using RabbitMQ as a Message Broker in 4 Simple Steps 🐰

Real Life Case Study: Synchronous Inter-Service Communication in Distributed Systems