Dotnet-docker: Dotnet restore command fails from Dockerfile for a private NuGet feed

Created on 4 Apr 2018  路  25Comments  路  Source: dotnet/dotnet-docker

Dotnet restore command fails from Dockerfile for a private NuGet feed. Note, the private Nuget repository URL is reachable outside docker (i.e. we can restore the project refs using the dotnet restore command localy). Unfortunately the docker dotnet restore fails.

Steps to reproduce the issue

  1. Create a C# Console application (.NET Core) project (not ASP.NET) that references a package from private Nuget repository.

The private Nuget repository shall provide feed v3, i.e. JSON info. We use either TFS package manager or https://github.com/emgarten/Sleet solution

  1. Create Dockerfile in project directory
FROM microsoft/dotnet:2.0-sdk
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
# copy nuget.config
COPY *.config ./

# show files
RUN ls

# Restore using local nuget.config or --source attribute
#RUN dotnet restore
RUN dotnet restore -s http://s900b216/SEM.NuGetServer.v3/feed/index.json -s https://api.nuget.org/v3/index.json --packages packages --ignore-failed-sources

# copy and build everything else
COPY . ./
RUN dotnet publish -c Release -o out
ENTRYPOINT ["dotnet", "out/Core.DR-Readout.Create.FromSensor.dll"]
  1. Create nuget.config file
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="kbciot" value="http://private-repository/SEM.NuGetServer.v3/feed/index.json" protocolVersion="3" />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  </packageSources>
</configuration>
  1. Run docker build
docker build -t kapsch/sem-iot/microservice/core/dr-readout-create-from-sensor:0.0.1 .

Expected behavior

Docker image is build

Actual behavior

For RUN dotnet restore in Dockerfile

Step 1/10 : FROM microsoft/dotnet:2.0-sdk
 ---> f29a4c01c987
Step 2/10 : WORKDIR /app
 ---> Using cache
 ---> 80437412b8e2
Step 3/10 : COPY *.csproj ./
 ---> a60776999021
Step 4/10 : COPY *.config ./
 ---> 263a35fbde94
Step 5/10 : RUN ls
 ---> Running in e3f9398fbeec
    Directory: C:\app
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        3/21/2018   1:47 PM           1691 Core.DR-Readout.Create.FromSen
                                                 sor.csproj
-a----         4/4/2018  11:27 AM            424 nuget.config
Removing intermediate container e3f9398fbeec
 ---> 1f7731c6763d
Step 6/10 : RUN dotnet restore
 ---> Running in 4de60bf1fa5e
  Restoring packages for C:\app\Core.DR-Readout.Create.FromSensor.csproj...
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error : Unable to load the service index for source http://private-repository/SEM.NuGetServer.v3/feed/index.json. [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error :   An error occurred while sending the request. [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error :   The server name or address could not be resolved [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
ERROR: Service 'core-dr-readout-create-fromsensor' failed to build: The command 'powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; dotnet restore' returned a non-zero code: 1

For RUN dotnet restore -s ...

Step 1/9 : FROM microsoft/dotnet:2.0-sdk
 ---> f29a4c01c987
Step 2/9 : WORKDIR /app
 ---> Using cache
 ---> 80437412b8e2
Step 3/9 : COPY *.csproj ./
 ---> Using cache
 ---> a60776999021
Step 4/9 : COPY *.config ./
 ---> Using cache
 ---> 263a35fbde94
Step 5/9 : RUN ls
 ---> Using cache
 ---> 1f7731c6763d
Step 6/9 : RUN dotnet restore -s http://private-repository/SEM.NuGetServer.v3/feed/index.json -s https://api.nuget.org/v3/index.json --packages packages --ignore-failed-sources
 ---> Running in 156d4c4cf7cb
  Restoring packages for C:\app\Core.DR-Readout.Create.FromSensor.csproj...
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error : Unable to load the service index for source http://s900b216/SEM.NuGetServer.v3/feed/index.json. [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error :   An error occurred while sending the request. [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
C:\Program Files\dotnet\sdk\2.1.101\NuGet.targets(104,5): error :   The server name or address could not be resolved [C:\app\Core.DR-Readout.Create.FromSensor.csproj]
ERROR: Service 'core-dr-readout-create-fromsensor' failed to build: The command 'powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; dotnet restore -s http://s900b216/SEM.NuGetServer.v3/feed/index.json -s https://api.nuget.org/v3/index.json --packages packages --ignore-failed-sources' returned a non-zero code: 1

Additional information (e.g. issue happens only occasionally)

  • The referenced Nuget package is a C# Class library (.NET Core) processed by dotnet pack command and pushed to the private Nuget repository. The repository URL is reachable from the local PC (not blocked by firewall etc.)

Output of docker version

Client:
 Version:       18.03.0-ce
 API version:   1.37
 Go version:    go1.9.4
 Git commit:    0520e24
 Built: Wed Mar 21 23:06:28 2018
 OS/Arch:       windows/amd64
 Experimental:  false
 Orchestrator:  swarm

Server:
 Engine:
  Version:      18.03.0-ce
  API version:  1.37 (minimum version 1.24)
  Go version:   go1.9.4
  Git commit:   0520e24
  Built:        Wed Mar 21 23:21:06 2018
  OS/Arch:      windows/amd64
  Experimental: false

Output of docker info

Containers: 10
 Running: 0
 Paused: 0
 Stopped: 10
Images: 17
Server Version: 18.03.0-ce
Storage Driver: windowsfilter
 Windows:
Logging Driver: json-file
Plugins:
 Volume: local
 Network: ics l2bridge l2tunnel nat null overlay transparent
 Log: awslogs etwlogs fluentd gelf json-file logentries splunk syslog
Swarm: inactive
Default Isolation: hyperv
Kernel Version: 10.0 15063 (15063.0.amd64fre.rs2_release.170317-1834)
Operating System: Windows 10 Enterprise
OSType: windows
Architecture: x86_64
CPUs: 8
Total Memory: 7.446GiB
Name: N051B006
ID: 53O4:UEB2:MAK7:STF3:TGSB:3A7E:YRRZ:644W:6PWT:JHK3:ZWVC:CA7C
Docker Root Dir: C:\ProgramData\Docker
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: -1
 Goroutines: 27
 System Time: 2018-04-04T14:13:58.0225934+02:00
 EventsListeners: 1
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

Output for local dotnet --info

.NET Command Line Tools (2.1.102)

Product Information:
 Version:            2.1.102
 Commit SHA-1 hash:  8d409357db

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.15063
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.102\

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.6
  Build    : 74b1c703813c8910df5b96f304b0f2b78cdf194d

Output VS info

Microsoft Visual Studio Community 2017 
Version 15.6.3
VisualStudio.15.Release/15.6.3+27428.2011
Microsoft .NET Framework
Version 4.7.02046

Installed Version: Community

Visual C++ 2017   00369-60000-00001-AA962
Microsoft Visual C++ 2017

Visual F# Tools 10.1 for F# 4.1   00369-60000-00001-AA962
Microsoft Visual F# Tools 10.1 for F# 4.1

AnyStatus   1.0
AnyStatus Detailed Info

Application Insights Tools for Visual Studio Package   8.11.10212.1
Application Insights Tools for Visual Studio

ASP.NET and Web Tools 2017   15.0.40314.0
ASP.NET and Web Tools 2017

ASP.NET Core Razor Language Services   1.0
Provides languages services for ASP.NET Core Razor.

ASP.NET Web Frameworks and Tools 2017   5.2.51214.0
For additional information, visit https://www.asp.net/

Azure App Service Tools v3.0.0   15.0.40215.0
Azure App Service Tools v3.0.0

C# Tools   2.7.0-beta3-62707-11. Commit Hash: 75dfc9b33ed624dff3985c7435c902c3c58c0e5c
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Common Azure Tools   1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

JavaScript Language Service   2.0
JavaScript Language Service

JavaScript Project System   2.0
JavaScript Project System

JavaScript UWP Project System   2.0
JavaScript UWP Project System

Microsoft Azure Tools   2.9
Microsoft Azure Tools for Microsoft Visual Studio 2017 - v2.9.51212.2

Microsoft Continuous Delivery Tools for Visual Studio   0.3
Simplifying the configuration of continuous build integration and continuous build delivery from within the Visual Studio IDE.

Microsoft JVM Debugger   1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft MI-Based Debugger   1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards   1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio Tools for Containers   1.1
Develop, run, validate your ASP.NET Core applications in the target environment. F5 your application directly into a container with debugging, or CTRL + F5 to edit & refresh your app without having to rebuild the container.

Microsoft Visual Studio VC Package   1.0
Microsoft Visual Studio VC Package

NuGet Package Manager   4.6.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit http://docs.nuget.org/.

ProjectServicesPackage Extension   1.0
ProjectServicesPackage Visual Studio Extension Detailed Info

SQL Server Data Tools   15.1.61801.210
Microsoft SQL Server Data Tools

TypeScript Tools   15.6.20202.3
TypeScript Tools for Microsoft Visual Studio

Visual Basic Tools   2.7.0-beta3-62707-11. Commit Hash: 75dfc9b33ed624dff3985c7435c902c3c58c0e5c
Visual Basic components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Visual Studio Code Debug Adapter Host Package   1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Tools for Universal Windows Apps   15.0.27428.01
The Visual Studio Tools for Universal Windows apps allow you to build a single universal app experience that can reach every device running Windows 10: phone, tablet, PC, and more. It includes the Microsoft Windows 10 Software Development Kit.

```

area-samples question

Most helpful comment

that's terrible... I need to download a 2GB image just to do a nuget sources add.... should be easier... =/

All 25 comments

@krakorj - How do you authenticate to the private NuGet feed when running locally? Where are your credentials being stored/how are they specified? These will need to be setup within the Docker container. It would be similar to setting up a new dev or build machine.

Do you mean the authentication to the Nuget server via the nuget.config? We do it for TFS, the https://github.com/emgarten/Sleet solution the server is without authentication.

Yes, how do you authenticate to the NuGet server? Can you explain what you mean by "we do it for TFS"?

We use command

nuget config -configFile ./nuget.config -set http_proxy=https://proxy.server.com:8080 -set http_proxy.user=example\myname -set http_proxy.password=PWD

nuget.config is as follows:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="kbciot" value="http://s900b216/SEM.NuGetServer.v3/feed/index.json" protocolVersion="3" />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
  </packageSources>
  <config>
    <add key="http_proxy" value="https://proxy.server.com:8080" />
    <add key="http_proxy.user" value="example\myname" />
    <add key="http_proxy.password" value="AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAJayVH7h9MEmfhGubg0dzngAAAAACAAAAAAADZgAAwAAAABAAAABiEH5MLxRtR/BKciw/krndAAAAAASAAACgAAAAEAAAAAmdvBMUqYd152qdnLhyWfcQAAAAO6CxXIcd9V664OoHw/4u5xQAAACqvEj0eupJUNkJTMuTVHgxEK87Pg==" />
  </config>
</configuration>

@krakorj - You are going to need to do the same within your Dockerfile. You can use the ARG instruction to pass secrets in necessary depending on your scenario.

@MichaelSimons Can you give me a hint how to use the ARGs? The secrets are already in the nuget.config , we copy the file to workspace directory (in Dockerfile COPY *.config ./). Why shall I use the arguments?

We found a workaround since the nuget repository is not reachable from the build docker image process:

  • build solution via msbuild *.sln /t:build
  • publish via msbuild *.sln /t:publish /p:PublishWithAspNetCoreTargetManifest=false
  • make docker image using simple Dockerfile:
    ```
    FROM microsoft/dotnet:2.0-sdk
    WORKDIR /app

copy published

COPY /folder/where/published/. ./

make entry point

ENTRYPOINT ["dotnet", "target.dll"]
````

@krakorj - I wouldn't consider that a great workaround as you are not getting the full benefits or dockerizing your build. I will create a sample and post it here.

@krakorj聽- The underlying cause of the issue you encountered is that the NuGet CLI cmds that set the pwds in the config file encrypt the passwords (e.g. nuget config -configFile ./nuget.config -set http_proxy=https://proxy.server.com:8080 -set http_proxy.user=example\myname -set http_proxy.password=PWD). This makes the resulting config files machine specific. To address this, you would have to run the NuGet cmd inside your Dockerfile/container. Unfortunately there are two problems that make this difficult. The first is that the NuGet CLI (which is based on the .NET Full FX) doesn't support NanoServer. The other problem is that the Nuget config cmd doesn't support a -StorePasswordInClearText option.

I have put included a couple samples that illustrate how to work-around these issue depending on your scenario.

How to set NuGet.config packageSourceCredentials in NanoServer Dockerfile

Build cmd: docker build -t test --build-arg MY_PRIVATE_NUGET_SOURCE_PWD=secret_pwd .

# escape=`

# NuGet config image - NuGet CLI has to be run in a WindowsServerCore container, as a result, PWD must be stored in clear text in order to be used in a later stage.  The NuGet config won't be in the runtime image so this shouldn't be an issue.
FROM microsoft/windowsservercore:1709 AS nuget-config
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
RUN Invoke-WebRequest -OutFile nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
ARG MY_PRIVATE_NUGET_SOURCE_PWD
COPY NuGet.config ./
RUN c:\nuget.exe source update -ConfigFile .\NuGet.config -Name my-private-nuget-source-name -username my-private-nuget-source-username -StorePasswordInClearText -password $env:MY_PRIVATE_NUGET_SOURCE_PWD


# Builder image
FROM microsoft/dotnet:2.0-sdk AS build

WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
COPY --from=nuget-config NuGet.config ./
RUN dotnet restore

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

FROM microsoft/dotnet:2.0-runtime AS runtime
WORKDIR /app
COPY --from=publish /app/out ./
ENTRYPOINT ["dotnet", "my-assembly.dll"]

How to set NuGet.config proxy in NanoServer Dockerfile

Build cmd: docker build -t test --build-arg MY_PROXY_PWD=secret_pwd .

# escape=`
# NuGet config image - NuGet CLI has to be run in a WindowsServerCore container, as a result, PWD must be stored in clear text in order to be used in a later stage. The NuGet config won't be in the runtime image so this shouldn't be an issue.
FROM microsoft/windowsservercore:1709 AS nuget-config
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
RUN Invoke-WebRequest -OutFile nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
ARG MY_PROXY_PWD
COPY NuGet.config ./
RUN c:\nuget.exe config -configFile ./nuget.config -set http_proxy=https://proxy.server.com:8080 -set http_proxy.user=my-proxy-user -set x_http_proxy.password=$env:MY_PROXY_PWD; `
    # Workaround nuget config limitation for not supporting -StorePasswordInClearText option
    (Get-Content NuGet.config) | ForEach-Object { $_ -replace 'x_http_proxy.password', 'http_proxy.password' } | Set-Content NuGet.config


# Builder image
FROM microsoft/dotnet:2.0-sdk AS build

WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.csproj ./
COPY --from=nuget-config NuGet.config ./
RUN dotnet restore

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

FROM microsoft/dotnet:2.0-runtime AS runtime
WORKDIR /app
COPY --from=publish /app/out ./
ENTRYPOINT ["dotnet", "my-assembly.dll"]

@MichaelSimons Can you provide an way to do the same using docker-compose.
Because I cannot use docker build -t test --build-arg MY_PROXY_PWD=secret_pwd .

@MichaelSimons can you give an example for linux container?

@MichaelSimons can you give an example for linux container?

Nuget cmd will generate a configuration file like this

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="http_proxy" value="http://my_repo:8080" />
    <add key="http_proxy.user" value="my_repo_user" />
    <add key="x_http_proxy.password" value="my_repo_password" />
  </config>
  <packageSources>
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    ...
  </packageSources>
</configuration>

So you can populate this file manually and pass to dotnet restore --configfile your_config_file

that's terrible... I need to download a 2GB image just to do a nuget sources add.... should be easier... =/

@GersonDias I essentially do this:

RUN echo "<configuration><packageSources><add key=\"dotnet-core\" value=\"https://dotnet.myget.org/F/dotnet-core/api/v3/index.json\" /></packageSources></configuration>" > nuget.config

And make sure the that the credentials etc needed for the source are in that echo statement (passed into the docker build using --build-arg var=val

No need to download the world to do this. Tested as working on an netcore alpine image as part of a multi-stage build.

In Docker for Windows, you can use @GersonDias solution, but you have to escape the "<" characters with "^" (https://stackoverflow.com/a/7308614/189429).

... and you may have problems passing build-args: https://github.com/docker/for-win/issues/542

Azure devops thread about similar question, but in a context of Azure DevOPS (VSTS) https://github.com/Microsoft/azure-pipelines-tasks/issues/6135

I'm not sure if I'm stupid or it's just insane complexity (or both).

How does anyone expect adoption of Docker for small enterprise apps when it's so difficult to do something really simple?

We recently published Managing NuGet Credentials in Docker Scenarios. Let us know if it is helpful. If not, tell us about your scenario.

With this scenario
https://github.com/dotnet/dotnet-docker/blob/master/samples/snippets/nuget-credentials.md#using-the-azure-artifact-credential-provider

Should I need to actually set access token / creds for local testing? Is this something I'd specifically need to change token stuff in the context of a image build in azure devops pipeline?

Seems to me like scenarios like this should be part of visual studio docker tools. Best I've been able to achieve thus far, is a 401 trying to connect to my azure devops hosted feed locally.

I know that article section states I need to set FEED_ACCESSTOKEN, but does this mean I need to go get a PAT and set this manually before I start trying to build locally?

As per
https://stackoverflow.com/questions/48821991/dockerfile-cant-see-local-file-or-private-nuget-server/54017310#54017310

you can do following :

1) copy your system's NuGet.Config in project folder at same root level where .csproject is.

2) now in docker file put these statements just before you try to restore package:

COPY ./NuGet.Config ./
3) after that , append the config file location in dotnet restore command like this :

RUN dotnet restore <CS_project_name>.csproj --configfile ./NuGet.Config
4) Now do rest of the thing which you wanted to do .

5) just at the end before entry point or before copying to other container(in case of multistage build) , it is good idea to remove NuGet.Config,as we don鈥檛 want that to be available in pod/container to be seen

RUN rm ./NuGet.Config

@ppatidar-apttus - In regards to the following:

just at the end before entry point or before copying to other container(in case of multistage build) , it is good idea to remove NuGet.Config,as we don鈥檛 want that to be available in pod/container to be seen

You must utilize a multi-stage build in this scenario otherwise the NuGet.Config will be in the layers of the resulting image even though you deleted it in a later layer. This is obviously not what you want if your NuGet.config has secrets stored in it.

The above solutions, ignoring the authentication issues, assume even the private nuget feed is reachable via an http url. But nuget supports a simple file based private repository as well and this will still fail.
Essentially, if my repository is at C:\dev\nuget-packages this works just fine for all scenarios except issuing a dotnet restore from within the Dockerfile. Even with the Nuget.Config copied, the docker build process sets the repository path as /src/C:\dev\nuget-packages. This use-case seems to leave no other option except as @krakorj mentioned to simply use a pre-published set of source files and not get the advantage of the docker build pipeline...

A few more steps are also possible:
run dotnet restore _before_ running the docker-compose command, and use the --packages option to save the restored packages to the solution folder
e.g. dotnet-restore C:\slnfolder\myproj\myapp.csproj --packages C:\slnfolder\packages
then in the Dockerfile, assuming context is the solution folder and WORKDIR is '/src'
COPY packages/. packages/.
and in the Dockerfile restore line
RUN dotnet restore "myproj/myapp.csproj" -s /src/packages -s https://api.nuget.org/v3/index.json

@MichaelSimons great work, thanks a lot :)

Don't know if this still applies, but since .NET Core 3.1.200, Microsoft has added the ability to add nuget sources directly from dotnet CLI via
dotnet nuget add source see https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-add-source

Was this page helpful?
0 / 5 - 0 ratings