This post will be about creating a dot net core application in a docker container. This allows us to run .NetCore in linux so we don’t need a windows server.
Todo this we will use docker. Docker desktop is a great tool for the mac and PC for personal use but no longer free for large organizations. This post will show you how to use docker in linux instead.
Linux
This post uses linux. We recommend using virtual box https://www.virtualbox.org/ to install Ubuntu. Get that set up and return here when complete.
Install dot net
We need to set up a few things before we get started. First we need packages from Microsoft. Then we can search the packages for the dot net version we want. Do this with the following commands.
wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb sudo dpkg -i packages-microsoft-prod.deb sudo apt-get update apt search dotnet-sdk Sorting... Done Full Text Search... Done ... dotnet-sdk-3.1/bionic 3.1.416-1 amd64 Microsoft .NET Core SDK 3.1.416 dotnet-sdk-5.0/bionic 5.0.404-1 amd64 Microsoft .NET SDK 5.0.404 dotnet-sdk-6.0/bionic 6.0.101-1 amd64 Microsoft .NET SDK 6.0.101
Next install dotnet 6.0 sdk using the following commands.
sudo add-apt-repository universe sudo apt-get install apt-transport-https sudo apt-get update sudo apt-get install dotnet-sdk-6.0
Check the version you have installed by using the following commands. You will see that the dotnet sdk is installed as well as the needed AspNetCore and NetCore runtimes.
dotnet --list-sdks 6.0.101 [/usr/share/dotnet/sdk] dotnet --list-runtimes Microsoft.AspNetCore.App 6.0.1 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.1 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
Install docker using the repository
Before you install Docker Engine for the first time on a new host machine, you need to set up the Docker repository. Afterward, you can install and update Docker from the repository. The following is a condensed set of instructions from https://docs.docker.com/engine/install/ubuntu/
Set up the repository
Update the apt
package index and install packages to allow apt
to use a repository over HTTPS:
sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release
Add Docker’s official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Use the following command to set up the stable repository.
echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Install Docker Engine
Update the apt
package index, and install the latest version of Docker Engine as follows:
sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io
Verify that Docker Engine is installed correctly by running the hello-world
image.
$ sudo docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
Setup permissions for docker
Next setup your user to have permission to use docker using the following command. This remove the need to use sudo before every docker command. After you run this command restart Ubuntu for the changes to take effect.
sudo usermod -a -G docker $USER
Create dotnet app
To create a dotnet app we need to set up a working folder using the following commands.
cd ~ mkdir Developer cd Developer
Next make a precanned “Hello World” console app using the following command.
dotnet new console -o App -n DotNet.Docker The template "Console App" was created successfully.
This will create several files in the the working folder.
We can see the apps directory structure from the command line by installing tree using the following command.
sudo apt-get install tree
Then list the apps directory structure use the following command.
tree App App ├── DotNet.Docker.csproj ├── obj │ ├── DotNet.Docker.csproj.nuget.dgspec.json │ ├── DotNet.Docker.csproj.nuget.g.props │ ├── DotNet.Docker.csproj.nuget.g.targets │ ├── project.assets.json │ └── project.nuget.cache └── Program.cs
To run the app, navigate to the app folder, and enter dotnet run
and the following will be displayed.
dotnet run Hello, World!
The app is not interesting but it is useful to demonstrate creating a dot net core app in a docker container.
Publish app
To do this first publish our app using.
dotnet publish -c Release Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET Copyright (C) Microsoft Corporation. All rights reserved. Determining projects to restore... All projects are up-to-date for restore. DotNet.Docker -> /home/jbailey/Developer/App/bin/Release/net6.0/DotNet.Docker.dll DotNet.Docker -> /home/jbailey/Developer/App/bin/Release/net6.0/publish/
Notice that a DotNet.Docker.dll is created. This is will later be used as an ENTRYPOINT by docker.
Install vim
If you have vim installed already you can skip this step. Vim will be used to create our docker file. You can install vim using the following.
sudo apt install vim
Build image
To build our image we need to create a docker file. The docker file will contain commands which will be processed with docker build
. This will result with an image with our app in it.
To create one use touch Dockerfile
then vim into it using vim Dockerfile
.
touch Dockerfile vim Dockerfile
Activate insert mode in vim by pressing i
and then paste in the following code. When finished press esc
then :wq
to save your file. You can confirm your changes using cat Dockerfile
.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 COPY bin/Release/net6.0/publish/ App/ WORKDIR /App ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
The FROM command gets the dot net image from the docker image store. The COPY command copies our published app. WORKDIR sets where the app is located and the ENTRYPOINT sets the target dll.
Now that the Dockerfile is created we can create a image that includes the dotnet runtime and our app using the following command.
docker build -t counter-image -f Dockerfile . Sending build context to Docker daemon 1.013MB Step 1/4 : FROM mcr.microsoft.com/dotnet/aspnet:6.0 ---> 53451db35067 Step 2/4 : COPY bin/Release/net6.0/publish/ App/ ---> 445ac43d6a88 Step 3/4 : WORKDIR /App ---> Running in c7cb0bceb8fd Removing intermediate container c7cb0bceb8fd ---> f1ec37c57944 Step 4/4 : ENTRYPOINT ["dotnet", "DotNet.Docker.dll"] ---> Running in 017e7ff6b231 Removing intermediate container 017e7ff6b231 ---> 2cf2ec73576f Successfully built 2cf2ec73576f Successfully tagged counter-image:latest
Check out the images that were created using docker image ls
. Notice that counter-image
was created. This will be used later to create a container.
docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE counter-image latest d8c0d20a6d8b 2 minutes ago 208MB mcr.microsoft.com/dotnet/aspnet 6.0 53451db35067 18 hours ago 208MB
Run app in docker container
Next lets run the container once with the image we just created using the following command.
docker run -it --rm counter-image Hello, World!
Congratulations! You have created your first dotnet core app in a docker container.
More advance stuff
Things get more complicated when you need nuget packages that are required for more complex dotnet projects.
Install mono
nuget.exe is a windows implemetation. You can run it in linux but first install mono using: see https://www.mono-project.com/download/stable/#download-lin for more information.
sudo apt install gnupg ca-certificates sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee/etc/apt/sources.list.d/mono-official-stable.list sudo apt update sudo apt install mono-devel
Verify mono is installed by running a simple “Hello World” example. Navigate to your development folder
cd ~/Documents/Developer mkdir mono-example cd mono-example
Create a file called hello.cs using the following commands.
touch hello.cs vim hello.cs
Paste the following into your file by pressing i
to insert, paste and press esc :wq
to save. Confirm your changes are made using cat hello.cs
.
using System; public class HelloWorld { public static void Main(string[] args) { Console.WriteLine ("Hello Mono World"); } }
To compile, use csc:
mcs hello.cs
The compiler will create “hello.exe”, which you can run using:
mono hello.exe
The program should run and output:
Hello Mono World
HTTPS connections
To make sure HTTPS connections work, run the following command to check whether you can connect to nuget.org:
csharp -e 'new System.Net.WebClient ().DownloadString ("https://www.nuget.org")'
The program prints the website contents if everything works or throws an exception if it doesn’t.
WinForms Hello World
The following program tests writing a System.Windows.Forms application.
Create a file called helloforms.cs using the following commands.
touch helloforms.cs vim helloforms.cs
Paste the following into your file by pressing i
to insert, paste and press esc :wq
to save. Confirm your changes are made using cat hello.cs
.
using System; using System.Windows.Forms; public class HelloWorld : Form { static public void Main () { Application.Run (new HelloWorld ()); } public HelloWorld () { Text = "Hello Mono World"; } }
To compile, use mcs with the -r option to tell the compiler to pull in the WinForms libraries:
mcs helloforms.cs -r:System.Windows.Forms.dll
The compiler will create “hello.exe”, which you can run using:
mono hello.exe
ASP.NET Hello World
Create a text file with the name hello.aspx and the content:
<%@ Page Language="C#" %> <html> <head> <title>Sample Calendar</title> </head> <asp:calendar showtitle="true" runat="server"> </asp:calendar>
Then run the xsp4 command from that directory:
xsp4 --port 9000
Use a web browser to contact http://localhost:9000/hello.aspx
Install nuget
Install nuget using the following command:
- Install Mono 4.4.2 or later.
- Execute the following command at a shell prompt:BashCopy
# Download the latest stable `nuget.exe` to `/usr/local/bin` sudo curl -o /usr/local/bin/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
- Create an alias by adding the following script to the appropriate file for your OS (typically
~/.bash_aliases
or~/.bash_profile
):BashCopy# Create as alias for nuget alias nuget="mono /usr/local/bin/nuget.exe"
- Reload the shell. Test the installation by entering
nuget
with no parameters. NuGet CLI help should display.
sudo apt install nuget
Verify nuget is installed using.
nuget NuGet Version: 2.8.7.0 usage: NuGet <command> [args] [options] Type 'NuGet help <command>' for help on a specific command. Available commands: config Gets or sets NuGet config values. delete Deletes a package from the server. help (?) Displays general help information and help information about other commands. install Installs a package using the specified sources. If no sources are specified, all sources def ined in the NuGet configuration file are used. If the configuration file specifies no source s, uses the default NuGet feed. list Displays a list of packages from a given source. If no sources are specified, all sources de fined in %AppData%\NuGet\NuGet.config are used. If NuGet.config specifies no sources, uses t he default NuGet feed. pack Creates a NuGet package based on the specified nuspec or project file. push Pushes a package to the server and publishes it. NuGet's default configuration is obtained by loading %AppData%\NuGet\NuGet.config, then load ing any nuget.config or .nuget\nuget.config starting from root of drive and ending in curren t directory. restore Restores NuGet packages. setApiKey Saves an API key for a given server URL. When no URL is provided API key is saved for the Nu Get gallery. sources Provides the ability to manage list of sources located in %AppData%\NuGet\NuGet.config spec Generates a nuspec for a new package. If this command is run in the same folder as a project file (.csproj, .vbproj, .fsproj), it will create a tokenized nuspec file. update Update packages to latest available versions. This command also updates NuGet.exe itself. For more information, visit http://docs.nuget.org/docs/reference/command-line-reference