Overview
After we learned a little bit a docker and containers, let's use docker for what it was meant to :) I have created a simple HTTP server which listens on port: 1234
Source code you can see in my Git
Packaging application in image, we call dockerize and it is done pretty simle.
Steps
Firstly, you need a Dockerfile in the place of your project. Since my project is on C#.NET Core and assuming your application is called: HttpServerDemo.dll, I have used the following Dockerfile:
Dockerfile
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env WORKDIR /app # Copy csproj and restore as distinct layers COPY *.csproj ./ RUN dotnet restore # Copy everything else and build COPY . ./ RUN dotnet publish -c Release -o out # Build runtime image FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "HttpServerDemo.dll"]
Now, let's go through the steps:
- Workdir - The workdir on the container which will be used.
- FROM - The external resources which will be used.
- COPY & RUN - These are self explanatory I hope.
You have to verify you have docker at least 17.05 or newer. My current one is 19.03:
[root@postgresqlpgpool netcoreapp3.1]# docker --version Docker version 19.03.5, build 633a0ea
Build
The building is also done fairy simple.
[root@postgresqlpgpool HttpServerDemo]# docker build -t httpserverdemo . Sending build context to Docker daemon 398.3kB Step 1/10 : FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env ---> 2fe8fe202baf Step 2/10 : WORKDIR /app ---> Using cache ---> 931056fe84ac Step 3/10 : COPY *.csproj ./ ---> Using cache ---> 33c701ccd6cf Step 4/10 : RUN dotnet restore ---> Using cache ---> 2acbc600037a Step 5/10 : COPY . ./ ---> 68177b9bdcf6 Step 6/10 : RUN dotnet publish -c Release -o out ---> Running in 34db589b7d0b Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Restore completed in 127.94 ms for /app/HttpServerDemo.csproj. HttpServerDemo -> /app/bin/Release/netcoreapp3.1/HttpServerDemo.dll HttpServerDemo -> /app/out/ Removing intermediate container 34db589b7d0b ---> d81f005279bc Step 7/10 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 ---> 5b704ff3cb6b Step 8/10 : WORKDIR /app ---> Using cache ---> e35d6ba6b507 Step 9/10 : COPY --from=build-env /app/out . ---> dc3b27c05e4d Step 10/10 : ENTRYPOINT ["dotnet", "HttpServerDemo.dll"] ---> Running in ff14d57a08fc Removing intermediate container ff14d57a08fc ---> 46b4167e5b2d Successfully built 46b4167e5b2d Successfully tagged httpserverdemo:latest [root@postgresqlpgpool HttpServerDemo]#
You can list the images as follows:
[root@postgresqlpgpool netcoreapp3.1]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpserverdemo latest 4ab730ac8ab5 6 hours ago 207MB
Start
Once the image has been built, you can start the container using that image:
[root@postgresqlpgpool HttpServerDemo]# docker run -d httpserverdemo 80:1234 c23e4bb41a9f660f8b409addb58d398b98dce38e93da00682214141f5bc719c9 [root@postgresqlpgpool HttpServerDemo]#
Finally, you can check the container:
[root@postgresqlpgpool netcoreapp3.1]# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9afb2dcbd6c2 httpserverdemo "dotnet HttpServerDe…" 5 hours ago Up 5 hours 0.0.0.0:80->1234/tcp web [root@postgresqlpgpool netcoreapp3.1]#
Upload in docker hub
Docker hub is the default registry for docker images. You can upload your image there if you want, bare in mind that it will be public.
Login
[root@postgresqlpgpool netcoreapp3.1]# docker login --username=andonovj Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@postgresqlpgpool netcoreapp3.1]#
Package
[root@postgresqlpgpool netcoreapp3.1]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE httpserverdemo latest 4ab730ac8ab5 3 hours ago 207MB [root@postgresqlpgpool netcoreapp3.1]# docker tag 4ab730ac8ab5 andonovj/httpserverdemo
Push
[root@postgresqlpgpool netcoreapp3.1]# docker push andonovj/httpserverdemo The push refers to repository [docker.io/andonovj/httpserverdemo] 6f2df37fa757: Pushed 64bca5e22c97: Pushed 05682a6a4056: Pushed fcd021389694: Pushed 2c52aed6692d: Pushed c51868eee26f: Pushed 556c5fb0d91b: Pushed latest: digest: sha256:5e0866ff45e12c8e350923fbe32d94bd76bd2d1576722d4d55ca786043bfcbe1 size: 1791 [root@postgresqlpgpool netcoreapp3.1]#
Now you can also download this simple web from your docker hub or list it as follows:
[root@postgresqlpgpool ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE andonovj/httpserverdemo latest 4ab730ac8ab5 6 hours ago 207MB [root@postgresqlpgpool ~]#
Troubleshooting
You can have the following error:
Searching wrong Nuget
Nuget Issue
Restore completed in 41.36 ms for /app/HttpServerDemo.csproj. /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: The "ResolvePackageAssets" task failed unexpectedly. [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: NuGet.Packaging.Core.PackagingException: Unable to find fallback package folder 'C:\Program Files\dotnet\sdk\NuGetFallbackFolder'. [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at NuGet.Packaging.FallbackPackagePathResolver..ctor(String userPackageFolder, IEnumerable`1 fallbackPackageFolders) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.NuGetPackageResolver.CreateResolver(IEnumerable`1 packageFolders) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.NuGetPackageResolver.CreateResolver(LockFile lockFile) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheWriter..ctor(ResolvePackageAssets task) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheReader.CreateReaderFromDisk(ResolvePackageAssets task, Byte[] settingsHash) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.ResolvePackageAssets.CacheReader..ctor(ResolvePackageAssets task) [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.ResolvePackageAssets.ReadItemGroups() [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.ResolvePackageAssets.ExecuteCore() [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.NET.Build.Tasks.TaskBase.Execute() [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() [/app/HttpServerDemo.csproj] /usr/share/dotnet/sdk/3.1.201/Sdks/Microsoft.NET.Sdk/targets/Microsoft.PackageDependencyResolution.targets(234,5): error MSB4018: at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask) [/app/HttpServerDemo.csproj] The command '/bin/sh -c dotnet publish -c Release -o out' returned a non-zero code: 1
In that case, either:
- Delete the “obj” and “bin” folders from the directory
- Add a command to the “Dockerfile” to not upload these to the container as follows:
Edit Dockerfile
# copy and build everything else COPY . ./ RUN find -type d -name bin -prune -exec rm -rf {} \; && find -type d -name obj -prune -exec rm -rf {} \; <- This line ENTRYPOINT ["dotnet", "HttpServerDemo.dll"]
Wrong ASP.NET
Be careful about the dockerizing the application. I tried to build the application with ASP.NET 2.2 while the app was build with ASP.NET 3.1, so I had to update my Dockerfile as follows:
Updated Docker File
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env <- This line WORKDIR /app # Copy csproj and restore as distinct layers COPY *.csproj ./ RUN dotnet restore # Copy everything else and build COPY . ./ RUN dotnet publish -c Release -o out # Build runtime image #FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 FROM mcr.microsoft.com/dotnet/core/sdk:3.1 WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "HttpServerDemo.dll"]
Otherwise, you will receive the following error:
Error for wrong ASP.NET version
It was not possible to find any compatible framework version The specified framework 'Microsoft.NETCore.App', version '3.1.0' was not found. - Check application dependencies and target a framework version installed at: /usr/share/dotnet/ - Installing .NET Core prerequisites might help resolve this problem: https://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409 - The .NET Core framework and SDK can be installed from: https://aka.ms/dotnet-download - The following versions are installed: 2.2.8 at [/usr/share/dotnet/shared/Microsoft.NETCore.App]