Docker and ASP .NET Core

How to dockerize a .NET Core application

Install docker on your machine.
Test the installation
$ docker run hello-world
The expected output is: Hello from Docker!

Read https://docs.docker.com/get-started/

The goal is to build an image that you can copy to the target machine and start to create a running container.
The container will contain all applications needed to run your app.

A container is launched by running an image. An image is an executable package that includes everything needed
to run an application — the code, a runtime, libraries, environment variables, and configuration files.

As an analogy: A docker-image is a class, a docker-container is an instance of a class.

First, you have to create a docker image on the development machine.
Docker images are created from docker-files (called Dockerfile without an extension) which contain statements that docker
will execute to create the image.

Go to the folder that contains the solution (.sln) file.
Create a file called ‘Dockerfile’ without extension.
Edit the Dockerfile in a text editor.

Here is my example Dockerfile:

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
#FROM mono:6.0.0.313-slim AS build
WORKDIR /app

# debug output
RUN pwd
RUN hostname
RUN uname -r

# install npm
RUN apt-get update && apt-get install -y curl
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -
RUN apt-get update && apt-get install -y nodejs

# copy csproj and restore as distinct layers
COPY *.sln .
COPY clone_angular/*.csproj ./clone_angular/
RUN dotnet restore

# copy everything else and build app
COPY clone_angular/. ./clone_angular/
WORKDIR /app/clone_angular

RUN npm install
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /app/clone_angular/out ./
ENTRYPOINT ["dotnet", "clone_angular.dll"]

 

Execute docker to build the docker image from the Dockerfile.
Navigate to the folder that contains the docker file.
$ docker build --tag=<TAG_NAME> .

‘docker build’ will run the Dockerfile.
During the execution, the operating system is 4.9.184-linuxkit.
So you are actually running a linux and apt-get is available for installing software.

On that linuxkit, there is no software installed.
If your build requires any tools, you have to install them on the linuxkit.
For example if your application uses angular, you will need node and npm you have to
install those tools first before building your app.
To install software, prepare a working installation command, then add a RUN command
to the dockerfile and paste the install command after it.

Once the dockerfile was executed, check if your docker installation lists your new image:
$ docker image ls

You should see

REPOSITORY TAG IMAGE ID CREATED SIZE
<TAG_NAME> latest 8797820ed5c5 3 minutes ago 262MB

Start a container from that image:
$ docker run -d -p 8888:80 <TAG_NAME>

In this command, the -d flag detaches the process from the command line. The container will run in the background and
the terminal is free for subsequent input. -p <EXPOSED_PORT>:<INTERNAL_PORT> will open the port 8888 in the host system
and bind it to the port 80 of the system running inside the container. This is necessary for accessing webapps from
the outside world. Open ports are shown in the last column of the output of the ‘docker container ls –all’ command.
The rightmost column shows which external port is bound to which internal port. In the example above you can now
access your webapp at localhost:8888. The last command is the image tag name to start the container from.

Errors during image creation

Q: The command ‘/bin/sh -c dotnet publish -c Release -o out’ returned a non-zero code: 1
A: You have to install software during the installation by adding commands to the Dockerfile
https://stackoverflow.com/questions/49088768/dockerfile-returns-npm-not-found-on-build

Deploy to the Remote server

The idea is to prepare an image in your local development environment.
Then create a .tar file of that image and upload the .tar file to the remote system.
https://stackoverflow.com/questions/23935141/how-to-copy-docker-images-from-one-host-to-another-without-using-a-repository

1. Install docker on the remote server:

The assumption is that your remote server is running Ubuntu Linux.
https://docs.docker.com/install/linux/docker-ce/ubuntu/

ssh root@<yourip>
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
apt-cache madison docker-ce
EXAMPLE: sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io
sudo apt-get install docker-ce=18.06.3~ce~3-0~ubuntu docker-ce-cli=18.06.3~ce~3-0~ubuntu containerd.io
sudo apt-get install docker-ce=5:19.03.1~3-0~ubuntu-xenial docker-ce-cli=5:19.03.1~3-0~ubuntu-xenial containerd.io
sudo docker run hello-world

2. On your local machine, build a Dockerfile and an image from that Dockerfile. The steps for dockerizing an application are explained above.

3. On your local machine, create a .tar file from the docker image, upload and import it on the remote machine.

You can list all images available on your local machine:
docker image ls

Then export one of the images to a file on your filesystem:

docker save -o <path for generated tar file> <image name>
docker save -o ./clone_tag_1_image.tar clone_tag_1

Now, zip the file to save time uploading it.

zip -r clone_tag_1_image.tar.gz clone_tag_1_image.tar

Upload the file to the server using scp:

scp <source> <destination>
scp clone_tag_1_image.tar.gz root@<your_ip>:/temp

Unzip the image on the server:

gunzip clone_tag_1_image.tar.gz

Import the image on the server:

docker load -i <path to image tar file>
docker load -i /temp/clone_tag_1_image.tar

Run the docker detached while exposing the port 80 t0 8888:

docker run -d -p 8888:80 clone_tag_1

The web app should now be available via the servers IP on the port 8888. If it is not, check the firewall settings of your server.

Example repository

cd /Users/<USER>/dev/dot_net_core
git clone https://github.com/dotnet/dotnet-docker.git


Example

https://github.com/dotnet/dotnet-docker/tree/master/samples/aspnetapp
$ docker run --name aspnetcore_sample --rm -it -p 8000:80 mcr.microsoft.com/dotnet/core/samples:aspnetapp

The app starts and is reachable on http://localhost:8000/


Cheatsheet

Version
$ docker version

General info
$ docker info

List all images downloaded to your local machine
$ docker image ls

List all running docker containers
$ docker container ls --all

Find all running docker containers and their IDs
$ docker ps -a

$ docker port <ContainerID>

Stopping a container
$ docker stop <ContainerID-Prefix>

Find info about a specific docker container
$ docker inspect <containerid>
$ docker inspect <containerid> | grep IPAddress

Build an image from a Dockerfile
$ docker build --tag=clone_tag_1 .

$ docker rm
$ docker container prune

Leave a Reply