ASP.NET Core with Docker Container – Part 2 Dockerfile

In ASP.NET Core with Docker Container – Part 1 Mounted Volume, I covered my experiment with Mounted Volume. In this post, I will explore the possibilities of Dockerfile. By reading on the internet, watching courses on Pluralsight, I know what Dockerfile is. “Know” means, well, just heard about it, saw people playing with it … on videos. Just like the first part, I want to explore it, do something with it.

I want to ship my application in a container. I want to be able to take that container and run it on another machine.

Dockerfile

I found a good article about it here by digital ocean. I feel it is too much to get started. And for a beginner, like me, it is hard to understand.

Dockerfile is a set of instructions to build a Docker image.

So the next question is what are the fundamental instructions to build an image? I always like to start with fundamental.

Fundamental Instructions

FROM

Instruct the base image we will use to build up. Docker gives you the ability to build your own image base on existing one. Think about it for a moment. We can take an existing aspnetcore-build image (which is made and maintained by Microsoft), and build our own image with some custom features.

FROM microsoft/aspnetcore-build

That’s all it takes to build your own custom image with full power of the aspnetcore-build.

MAINTAINER

It is nice to tell the docker that you maintain the image. It is you, the owner, the maintainer.

MAINTAINER thaianhduc

 

COPY

Start making your own custom image. The “COPY” instruction will tell Docker to copy a folder into a specific folder inside the container. It is the same concept as Mounted Volume, except, instead of creating a mapping, it copies the data.

COPY . /app

The above command will tell the Docker to copy the working directory into “app” folder inside the container. The equivalent in Mounted Volume is “-v ${pwd}:/app“.

WORKDIR

The directory that container will start. Think the same way when we open a Powershell or CMD in Windows. In our web application, it will be the web directory that we created in the COPY instruction.

WORKDIR /app

 

RUN

Given that the working directory, the container will run commands instructed by RUN. In our previous web application, we want to run “dotnet restore” and “dotnet run” commands. They might look like this

RUN dotnet restore

RUN dotnet run

Note: I might not want to build application inside the container. Most of the time, I want to ship my application, not source code.

EXPOSE

The port that a container exposes to the outside.

EXPOSE 8080

Which means other systems can communicate with it via port 8080.

ENTRYPOINT

All the above instructions tell Docker how to build an image. The ENTRYPOINT instruction tells containers what command to run once it starts. Let’s think about a web application scenario, once a container starts, we want to start our web server inside the container.

ENTRYPOINT ["dotnet", "Coconut.Web.dll"]

In Action

With the discovery from Dockerfile, I reframe my steps more precisely. I will/want

  1. Build an ASPNET Core Web Application on my host machine with VS2017 Community.
  2. Publish it to a local folder.
  3. Build a Docker image with the published application in.
  4. Start a container from my custom image.
  5. Access my web application from host browser.

Before started, I want to make sure that I have a working website published. This should be easy done by asking VS2017 to publish my project to a local folder. By default, it will publish to bin\Release\PublishOutput folder.

Website up and run well

So given at the published folder, when run “dotnet Coconut.Web.dll“, my website is up and run. So far so good.

How about recap the Mounted Volume approach? Which means I want to run this command

Recap: Run app with mounted volume

At the last line, I want to start an ASPNETCORE container to host my published application. Shall it work? Let’s find out.

It looks ok. Except, I cannot access the website from host browser. Which means something was wrong; well not a surprise at all. Turn out I made the wrong port mapping. It should be port 80 inside Container instead of 8080.

docker run -t -p 5000:80 -v ${pwd}:/app -w /app microsoft/aspnetcore bash -c "dotnet Coconut.Web.dll"

Create Dockerfile

A Dockerfile is a simple text file. You can create it with any your favorite editor.

# Custom image based on aspnetcore to host a web application
FROM         microsoft/aspnetcore
MAINTAINER   Thai Anh Duc
COPY         . /app
WORKDIR      /app
ENTRYPOINT   ["dotnet", "Coconut.Web.dll"]

For naming convention, I name it Dockerfile. I use VS2017.

Build a Custom Image

So far I have created a published application and a Dockerfile. Things seem ready. Next, we need to tell Docker to build an image from the Dockerfile.

The current folder structure looks like this

\bin
    \Release
            \PublishOutput
Dockerfile

Let’s try to run my very first build command. However, it failed right after build. Because that folder structure will cause some security issues. To make my life easy, I move the Dockerfile into the PublishOutput folder.

docker build -t thaianhduc/aspnetcore:0.1 .

Hey Docker, take the default Dockerfile at the current location (where the command is run), build an image, give it a name “thaianhduc/aspnetcore” and tag it with version “0.1”.

Do not forget the “.” at the end. It represents for “current location“.

// Run the command to list all the images. The new image should be there
docker images

Run It

Time to enjoy the fruit

docker run --name my-coconut -p 5000:80 thaianhduc/aspnetcore:0.1

Open the browser on my host machine, type in http://localhost:5000/hello_beautiful. Oh yeah! It works.

A Few Words

I have failed many times while experimenting and writing the post. Everything seems easy while you read it on the internet. However, when it gets down to actual do it. Evil hits your face at the first try. But that is actually a good thing. I have learned so much while trying to solve those problems. Some of them I understand, some I do not.

So far I have been playing around with the fundamentals of Docker. For every single command, for every single action, I try to explain to myself in my own language. The language that I can understand and explain to other.

Having small goals at the beginning keeps me focus. It allows me to temporary ignore some problems. Otherwise, you will wonder in the sea of information out there. Reading something is easy. Making something works for you is hard.

How do I take my custom image and use on other machines? Easy. I can push my image to Docker hub. Then I can run it just like other images. Things make sense now. I can resonate without effort.

Deployment Options Recap

I started with learning ASP.NET Core and other new cool stuff. I want to learn about the infrastructure that I can take advantages of. Let’s assume that I have a web application, how many options do I have to deploy it?

  1. Local host (IIS): Obviously I can simply press F5
  2. Deploy to Azure for free.
  3. Run it inside a container using Mounted Volume approach.
  4. Or deploy it as a Docker Image.

What’s Next?

I want to step further into the ASP.NET Core, from a fundamental point of view. Maybe later in the series, explore the possibilities of Docker in term of Microservices.

That would be fun!

 

Write a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.