Containerizing A .Net Core Application Using Docker, ACS And Kubernetes - Part Two

Brief Introduction to Containers and Docker

For those who are new to the terms container and Docker, a container image is a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries, settings. Available for both Linux and Windows based apps, containerized software will always run the same, regardless of the environment.

Containers isolate software from its surroundings, such as differences between development and staging environments, and help reduce conflicts between teams running different software on the same infrastructure.

For those who are thinking about Virtual machines at this point and wondering how containers are different from VM, here is a good read.

And, Docker is the world’s leading software container platform. So, let’s get started with containerizing our .NET Core application which we created in our previous exercise.

Step 1 Creating the Dockerfile

We will start by creating a Dockerfile at the root directory of our application.

For this demo, I am using an Ubuntu 16.04 machine. Doing so, we will be able to test the cross-platform compatibility of .NET Core application. To initialize the code, open a terminal and get started.

  1. # Create the file using  
  2. touch Dockerfile  
  3. # Open the file in editor of your choice  
  4. vi Dockerfile  

Step 2 Configure the Dockerfile

  1. # Use the standard Microsoft .NET Core container  
  2. FROM microsoft/dotnet  
  3. # Copy our published code from the “/app” folder to the “/app” folder in our container  
  4. WORKDIR /app  
  5. COPY /app /app  
  6. # Expose port 5000 for the Web API traffic  
  7. EXPOSE 5000  
  8. # Restore the necessary packages  
  9. # Build and run the dotnet application from within the container  
  10. ENTRYPOINT dotnet demoservice.dll  

So, the above Dockerfile is pretty much self explanatory. We are using the official Microsoft .NET Core container and building our application on top of that.

WORKDIR command specifies the working directory of the container.

Copy command does copy the files form our machine to the container.

But before we run the docker build command, we need to do couple more things.

Step 3 Build and publish our application

At this point, we need to build our application and publish it to an output directory before running any docker command.

dotnet build

The dotnet build command builds the project and its dependencies into a set of binaries.

dotnet publish –o app

The dotnet publish command compiles the application, reads through its dependencies specified in the project file, and publishes the resulting set of files into a directory.

For more details on .NET Core CLI tool and commands, please visit here.

Step 4 Building the Docker image from the Docker file

Before we proceed towards building the docker image from the dockerfile, we should have a machine setup with docker installed in it. For this demo, I will be using an Ubuntu 16.04 machine with Docker installed.

Note

You can install Docker on any machine. I am using Ubuntu because its comparatively easy to install Docker in Ubuntu.

To install Docker in Ubuntu 16.04, please check here.

After you have successfully installed Docker, now let’s move forward to build our docker image form the dockerfile that we have created.

docker build –t demoservice .

Step 5 Run the Docker image

docker run -d -p 5000:5000 demoservice

docker run command runs the docker image in a container.

  • - p/ — publish is used to publish a container’s port to a host.
  • - d/ — detach is used to run container in background.
Note

The EXPOSE instruction informs Docker that the container listens to the specified network ports at runtime. EXPOSE does not make the ports of the container accessible to the host. To do that, you must use either the -p flag to publish a range of ports or the -P flag to publish all of the exposed ports.

To learn more about various docker commands, visit the following links.

Step 6 Check the application in your browser

curl http://localhost:5000/api/values

Oops!!! That didn’t work.

Making the same curl request repeatedly, causes the error

curl: (56) Recv failure: Connection reset by peer
or 
curl: (52) Empty reply from server

We will fix this issue using one line of code. Open the file Program.cs in any text editor.

  1. namespace demoservice {  
  2.     public class Program {  
  3.         public static void Main(string[] args) {  
  4.             var host = new WebHostBuilder().UseKestrel().UseUrls(“http: //*:5000") //Add this line of code.  
  5.                 .UseContentRoot(Directory.GetCurrentDirectory()).UseIISIntegration().UseStartup < Startup > ().Build(); host.Run();  
  6.             }  
  7.         }  
  8.     }  

So, let’s quickly discuss what went wrong in the first place. By default, ASP.NET application (kestrel) only listens to a loopback interface i.e. in our case localhost. But when running inside a container, localhost is only reachable from inside the container and not from outside. So, we have added the above line of code and replaced the domain/host name with “*” to indicate the server should listen to requests on any IP address or host using the specified port and protocol.

Once you have added the line of code, repeat step 3 and 4. Now, if we do a curl

http://localhost:5000/api/values

And now, you will be able to get the response :)

Step 7 Tag an push image to Docker hub

Once we see that our application is working fine, we will proceed towards pushing the image to Docker hub which is a public registry to store your image and pull it from anywhere.

Docker login # Login to your Docker hub account with your userId and password docker tag <image-id> <image-tag> # Tag the docker image with the <Dockehub account>/<repository name>
 
e.g. If your docker hub account is dotnetcore and you want to push this image to repository demoservice, then the above command will be like docker tag <image-id> dotnetcore/demoservice docker push dotnetcore/demoservice
 
docker tag and push.

Once this is complete, log into your docker hub account to check if the image is pushed properly or not.

In the next part, we will be running this image in a kubrnetes cluster.