We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

Facundo Aita • 5 years ago

Great Article, thank you. For those who are working with aspnet core 3.1, this works for me is:
Runs with: docker build -f PROJECT_NAME/Dockerfile -t IMAGE_NAME .

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env
WORKDIR /app

COPY . ./
RUN dotnet publish PROJECT_NAME -c Release -o PROJECT_NAME/out

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
WORKDIR /app
COPY --from=build-env /app/PROJECT_NAME/out .
ENTRYPOINT ["dotnet", "PROJECT_NAME.dll"]

See the main diference is in bold.
Regarding the dotnet publish command documentation the output option has change from 2.X to 3.X

.NET Core 3.x SDK and later
If a relative path is specified when publishing a project, the output directory generated is relative to the current working directory, not to the project file location.

.NET Core 2.x SDK
If a relative path is specified when publishing a project, the output directory generated is relative to the project file location, not to the current working directory.

Pankaj • 3 years ago

tometchyFacundo Aita

Hi

about your explanation in the section "how to adjust dockerfile":

So we copy all projects (because build context is now solution directory) to /app directory inside container. Next from /app workdir we run dotnet publish command, specifying which project to compile - RUN dotnet publish PROJECT_NAME -c Release -o out - here PROJECT_NAME is the directory name with .csproj file inside.

[Modified as per Facundo Aita, i modified as below for .NET6 though:
RUN dotnet publish PROJECT_NAME -c Release -o out]

Does this mean,
……….
FROM mcr.microsoft.com/dotnet/sd... AS build
WORKDIR /src
COPY . .
……….

The COPY command copies the project files with existing local folder structure to the working directory in the image?

I mean:

In my local “localsrc” folder I have 3 projects like this: (Dockerfile is in “/localsrc/PROJECT_API”)

/localsrc/PROJECT_API
/localsrc/PROJECT_DPENDENT_DLL_1
/localsrc/PROJECT_DPENDENT__DLL_2

And I am running the “docker build” command from /localsrc folder (i.e. this is the build context).

Does this copy the project files like below in the image? - i mean with existing folder structure?

/src/PROJECT_API/project_api.csproj
/src/PROJECT_API/Properties/launchSettings.json
……………
/src/PROJECT_DPENDENT_DLL_1
/src/PROJECT_DPENDENT__DLL_2

Thanks again
Pankaj

tometchy • 3 years ago

Yes, directory structure is preserved. You can "enter" into running container with:
docker exec -t -i containerIDorName /bin/bash
And see it for yourself (pwd, ls etc.). You can also run container and "enter" to it from some building phrase with "docker run -t -i IMAGE_ID /bin/bash" -> you see intermediate image id's during building image.

tometchy • 5 years ago

Thank you for your comment, it might be helpful for many people :)

Devin Quince • 5 years ago

Quick ? for you. We have a .net core app that needs to connect to an Azure DevOps artifact feed, but I keep getting the 401 not authorized error no matter what I do. This works for the non docker dotnet restore using the same feed. Any ideas?
thanks

tometchy • 5 years ago

Hi Devin Quince , good question, I had to came through this too.

You have to authorize accessing this feed. In your PC it takes your credentials from Windows passwords store, which won't work in Docker.

You can use "--configfile Nuget.config" option for dotnet publish/restore and pass nuget config with proper credentials - https://docs.microsoft.com/...

Unfortunately in my case proper credentials didn't work and any Azure DevOps server admin didn't know why and couldn't read it from logs (I hope it won't be your case). Switching to authenticating with PAT solved the problem (personal access token), which luckily is allowed in nuget config https://docs.microsoft.com/...

Moreover, in my case due to bug in dotnet, I had to add "DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0" before using dotnet publish, like this:
RUN DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 dotnet publish project -c Release --configfile Nuget.config

I hope this will help you get through this too.

sethnejame • 5 years ago

tometchy excellent article. . .however I still have a question about the changes you made to the Dockerfile. . .it seems you are still only referencing one project (PROJECT_NAME). . .I have a solution with multiple projects. How would we change the Dockerfile to include multiple projects? Like this?

RUN dotnet publish PROJECT_ALPHA -c Release -o out
RUN dotnet publish PROJECT_BRAVO -c Release -o out
RUN dotnet publish PROJECT_CHARLIE -c Release -o out
RUN dotnet publish PROJECT_ECHO -c Release -o out

FROM mcr.microsoft.com/dotnet/co...
WORKDIR /app
COPY --from=build-env /app/PROJECT_ALPHA/out .
COPY --from=build-env /app/PROJECT_BRAVO/out .
COPY --from=build-env /app/PROJECT_CHARLIE/out .
COPY --from=build-env /app/PROJECT_ECHO/out .

But then, how do we reference the entry point to the Dockerfile? Below, you just have "PROJECT_NAME".

ENTRYPOINT ["dotnet", "PROJECT_NAME.dll"]

Thanks again for this awesome article!

tometchy • 5 years ago

Hi sethnejame , thanks for flattering comment :)

What you try to achieve is to run multiple apps inside one Docker, which is known as anti pattern.
Instead, create separated image for every project from your solution. So put analogous Dockerfile in every project directory like this:
solution_directory/PROJECT_ALPHA/Dockerfile
solution_directory/PROJECT_BRAVO/Dockerfile

And prepare every Dockerfile the way I have described in this article, so with only one Dotnet publish.

By "Multi-project" from articles title I mean one exacutable project with references to other dll projects from the same solution.

If you want to run multiple containers at once (in the same Docker network), use Docker-compose, I have written introduction to it as well - https://www.softwaredevelop...

Running multiple dotnet projects in one container is simple, compile every project the way you have written (but with different output directory for every project), or simple compile whole solution like this: RUN dotnet publish solution-file.sln -c Release
and set bash script as entrypoint, and inside this script run all projects, something like this:
ENTRYPOINT ["/bin/bash", "./entrypoint.sh"]
entrypoint.sh (pseudo code): dotnet PROJECT_ALPHA.dll & dotnet PROJECT_BRAVO.dll & dotnet PROJECT_CHARLIE.dll
but as I said before, it's better to separate it and run one exacutable project per one container.

sethnejame • 5 years ago

Thanks for your response Tom!

To clarify, my solution w/ multiple projects are all part of the same application. The entry point for the application is in the "Project.API" project. The other projects are for business logic, services, dataAccess, among other things. So are you suggesting that I make a docker file for each one of these projects? Where then would I run the docker image build from? I want to build the entire app (from these projects) into one docker image, and then run that image in a container.

tometchy • 5 years ago

If other projects are just libraries, dependencies for one exacutable project (Project.API), then one Dockerfile inside exacutable project is enough.

When you run dotnet publish, then dotnet knows, to take other projects as dependencies, as they are referenced in Project.API.csproj so you don't have to run "dotnet publish" for dependent projects.

The point is, to have Docker context at level which contains all projects, otherwise dotnet will report, that referenced projects are not available.

sethnejame • 5 years ago

Gotcha. . .I managed to get my image built! However, now the container fails because Docker doesn't have permissions to access Azure Key Vault (we get secrets inside the app from Azure) . . .have you dealt with that before? I tried running the container from Azure CLI with no luck :(

tometchy • 5 years ago

I haven't used Azure Key Vault, but I have used many different third parties from Docker container, so in my view it should work as well. What is communication channel to Azure Key Vault (is it http?) and what exception tells?

sethnejame • 5 years ago

Yes https. . .essentially I get an error that my identity can't be confirmed - I'm 95% sure that this is because my docker container does not have the authority to access Azure Key Vault. . .so I think maybe I need to run Azure CLI inside the docker container, then the actual .dll? Not sure. Here's my error:

---> System.AggregateException: One or more errors occurred. (Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXXXXXXXXXXXXXXXX. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXXXXXXXXXXXXXXXX. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. Connection refused
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXXXXXXXXXXXXXXXX. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/XXXXXXXXXXXXXXXXXX. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. /bin/bash: az: No such file or directory

tometchy • 5 years ago

It looks like configuration problem:

Connection String: [No connection string specified]

Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set.

sethnejame • 5 years ago

We've had this error before when trying to connect from our dev environment and it was because we weren't able to get an access token from Azure (connectionString) that is then passed to the key vault function (this basically boils down to not being authorized to access the endpoint because we aren't passing in the right credentials).

tometchy • 5 years ago

And how did you authorize it then? My point is, if it works from your PC, it should be possible to run it from Docker on your PC, it should be transparent for Azure if you connects from your PC directly or from container.
What did you do, to fix it on your PC, how did you authorize it?

sethnejame • 5 years ago

tometchy thanks again for keeping in touch.

Basically, we were building our app in the Azure Devops pipeline. When we would try to run unit tests for our application (after the build stage), we got the same error mentioned above. Our application was trying to get access to Azure Key Vault after it was built inside the pipeline, so that we could initialize the app's config and run our unit tests. . .but our access was denied.

The workaround for this was to build the application and then run the tests from within Azure CLI. This way, we were logging into azure with valid creds and giving the app permission to gain access to the vault. This same idea doesn't work via docker though, because I think the docker container is trying to access the key vault and getting denied. A workaround would be to have azure CLI run inside the docker container, then run the app via the azure CLI, but I don't know if that's even possibe.

tometchy • 5 years ago

In my view it's not workaround, if Azure CLI is tool required to build / run your app, then I find it perfectly fine to put it in Docker :) If Azure CLI works in Linux, then it will work in Docker, when you base on Microsoft dotnet image, then you simply have Ubuntu and can install whatever works on Ubuntu (I assume you use Linux containers, as Windows containers are not production ready yet). Quick search provs it will work:

The Azure CLI is available to install in Windows, maxOS and Linux environments. It can also be run in a Docker container and Azure Cloud Shell.


https://docs.microsoft.com/...
:)

sethnejame • 5 years ago

Gonna try this now. Thanks again for all your help! Extremely useful :)

tometchy • 5 years ago

No problem :) I'm writing few more Docker and .NET Core related
posts, you can subscribe to be notified after publish. One is about
optimizing image build time, and the other about solving SSL problem in
container to container communication with dotnet apps.

sethnejame • 5 years ago

Will do!

Eric • 6 years ago

Hi Tometchy and thank you for this post. Would it be possible to share the source code? Thanks

tometchy • 6 years ago

Hi Eric , thanks for your comment!
It sounds a good idea, but unfortunately I wrote it for production code which I'm not allowed to share, but I will write some Hello World example with above Docker configuration, and share it here.

tometchy • 6 years ago

Eric - I have prepared example app to show dockerized solution - https://github.com/Software... feel free to use it for your needs :)

SAGAR BINGI • 4 years ago

Great article. Thank you so much for putting your effort to describe each docker command in detail. It helped me a lot.

It's a great article, and it has helped me a lot
Thank you

tometchy • 4 years ago

Thanks for sharing that it helped you :)

Patrick Hitch • 5 years ago

This is wonderful solution to using docker build command, works great; however, when I try to use this approach with docker-compose it complains that it can't find the project file for any of my services - even though issuing docker build command works perfectly fine. Any suggestions?

tometchy • 5 years ago

Hi, I'm glad you find it helpful. You probably have wrong path in docker-compose. Follow this example then you should find where the problem is: https://www.softwaredevelop...

Rodrigo Ramírez • 5 years ago

Great work, thanks

tometchy • 5 years ago

Thanks :)

Ritika Agarwal • 5 years ago

Thanks for the article, it was super helpful.
It all works okay for until the code reaches the RUN dotnet publish line.
I get the error NU1101 : Unable to find package package_name. No packages exist with this id in source(s) : nuget.org.
This is a package which is a Nuget dependency (a local one) in my dependent projects. Would you have any idea how I can fix this?
Thanks for the help.

tometchy • 5 years ago

Hi, thanks for your comment. If this is dependency from your private feed, check comment by Devin Quince and my reply, I have already described this. Maybe I will write short article about this topic as well :)

If this is dependency from nuget.org first ensure there is internet connection (it probably works well, but it's always good to check, maybe some network configuration failed), just add RUN curl https://www.softwaredevelop... under FROM mcr.microsoft.com/dotnet/co... AS build-env

If it's fine, ensure that it works without Docker (in your host machine) invoked exact the same way (dotnet publish with the same arguments).

If there is internet connection and it's from default public feed (nuget.org), then it's for sure matter of properly set dependency in csproj file.

Check: https://stackoverflow.com/a... and https://docs.microsoft.com/...

Ritika Agarwal • 5 years ago

Thank you. Yes, it is a private feed, which is stored locally on my computer. My config file has <add key="Package source" value="C:\Users\rXXXX\Build"/> . This is where the package is stored.
I copied the NuGet.Config to my project folder and added in --> COPY project/NuGet.Config ./
Now, when the restore happens, I get this error.
error : The local source '/app/C:\Users\XXXX\Build' doesn't exist. [/app/project.csproj]

Why is it adding in the app to my path? Because it's my current working directory? How do I get around that?

tometchy • 5 years ago

Hi absolute path on Linux starts with / character. Your path starts without it (C:\...) so it's treated like path relative to current working directory (/app). Path starting with Windows drive (C:\...) will not work, you need to use relative path and it will work (and use slashes instead of backslashes if you need nested path). If you have it stored on your computer then it should be easy, just copy nuget files to image and fix above path. It's more difficult to access private feed using network, I have described problems and solutions which I have encountered under Devin Quince comment.

Ritika Agarwal • 5 years ago

Thanks , I didn't think of that. Although now, if I try and copy the .nupkg , it says , that's a forbidden path outside the build context. :/
This package lies in a different repo altogether. If I can't copy anything from outside this solution..how is it going to work? Should I change my build context for that then?

tometchy • 5 years ago

You can copy outside solution, just set build context one directory higher and adjust paths in Dockerfile. But if it's in different repo, then it will work locally but will be problematic in CI/CD machines. It would be better to have it in the same repo or use for example git submodules. Otherwise you will have to use some script which downloads it first then invokes Docker build.

flipdoubt • 5 years ago

Thanks, Tometchy. This helps a lot.

One thing I'm not finding many examples on is how/when to add custom configuration. I've found some articles suggesting adding a volume that contains appsettings.Production.json, custom report files, etc., but no concrete examples such as you've done in this article. Can you point me to a walk through of how you configure volumes? Do we add this to the dockerfile or is it an environment variable? These are the kinds of questions that prevent me from using Docker in production.

Thanks again.

tometchy • 5 years ago

Hi flipdoubt good questions.

First let me answer about how to add custom configuration. 12factor says to store configuration in environment variables and this is what I recommend. You just need to add "ENV KEY VALUE" in Dockefile, and call it from C# like this "Environment.GetEnvironmentVariable(KEY)". Docker volumes are not meant for configuration and I wouldn't use it for this. If you need many variables (which usually indicates, that you made mistake somewhere in design), then you can store them in ".env" file - https://docs.docker.com/com...

About Docker volumes - I think I will write article about configuring it some day, but I'm not sure, because it's described quite well in official documentation - https://docs.docker.com/sto... - so I recommend starting with it. In short - you don't put it in Dockerfile, it can't be tied to image, you configure it from host perspective. But as I said before, as far as I know, it's not meant for configuration, just for storing data from containers.

Piotr • 5 years ago

Nice and tidy - I own you one ;)

tometchy • 5 years ago

Thanks @Piotr :)

patheyacine gueye • 6 years ago

Great article indeed

tometchy • 6 years ago

Thank you :)

Bukunmi Aluko • 6 years ago

Thanks a lot man!.

tometchy • 6 years ago

Thanks Bukunmi Aluko :)

Manish Kumar • 6 years ago

Great article

tometchy • 6 years ago

Hi Manish Kumar , thank you for your comment, I'm pleased you like it ;)

kahmeal • 6 years ago

Great breakdown and explanation Tometchy! I too experienced the same learning journey of copy pasting and the frustrations that come from not truly understanding the purpose behind each statement. Thanks for the post.

tometchy • 6 years ago

kahmeal Thank you very much for the feedback! I'm glad you find it helpful :)