NuGet is the .NET package manager. By default, the .NET Core SDK will use packages from the nuget.org website.
In this article, you'll learn how to deploy a NuGet server on Red Hat OpenShift Container Platform (RHOCP). We'll use it as a caching server and see that it speeds up our builds. Before we get to that, we’ll explore some general NuGet concepts and see why it makes sense to use a local NuGet server.
NuGet
NuGet packages are .NET's libraries: they allow us to package compiled code and use it in different applications. To share these packages, we make them accessible via HTTP. When we consume packages from nuget.org, for example, we are using packages from the NuGet feed at https://api.nuget.org/v3/index.json.
The SDK dotnet restore
command retrieves the packages needed to build a project. To override the default of using nuget.org, we can use a NuGet.config file or specify the --source
argument to the restore
command.
We can use multiple feeds when performing a restore. For example, one feed could be the public repository at nuget.org, while another feed can point to a local NuGet server that hosts packages which are developed in-house.
That is a first use-case: hosting private packages. Note that a single NuGet server can host multiple distinct feeds. This allows different teams/projects to have their own feeds. You can also use this capability to have separate feeds for development builds and release builds.
A second use-case is caching packages. In this case, a feed is a cached instance of an upstream feed. By caching packages locally, we can reduce the time to restore the project. We are also no longer dependent on the availability of the upstream server. If the upstream server allows deleting packages, we will still have those in our cache. The caching server also reduces the number of packages that are fetched from the Internet.
Local hosting options
Microsoft's NuGet server is open source, but it doesn't run on Linux. Repository managers like JFrog Artifactory and Sonatype Nexus are feature-rich package managers that also support NuGet feeds.
If we are looking for a lightweight, NuGet-only option that we can run in a Linux container, BaGet is an interesting choice. It's an open source NuGet server that supports the v3 protocol, and it is implemented using ASP.NET Core.
RHOCP and NuGet
RHOCP can build our .NET Core application. The .NET Core builder accepts a number of environment variables to control its behavior. We're interested in DOTNET_RESTORE_SOURCES
, which does the following:
Specifies the space-separated list of NuGet package sources used during the restore operation. This overrides all of the sources specified in the NuGet.config file.
So, to use a local NuGet server, we can set this variable to the feed URL. If you are using Microsoft NuGet Server, JFrog Artifactory, or Sonatype Nexus, have a look at the product documentation for creating a NuGet feed. In the next section, we'll explain how to deploy BaGet on RHOCP and use it as a caching NuGet server for nuget.org.
Using BaGet with RHOCP
For the following steps, I assume .NET Core support has been added to your RHOCP installation, as described in Installing Image Streams. The DOTNET_NAMESPACE
variable used in the steps should be set to the Kubernetes namespace that contains the .NET Core builder images.
Using the RHOCP CLI (oc
), import the BaGet template in your RHOCP project:
$ oc create -f https://raw.githubusercontent.com/redhat-developer/s2i-dotnetcore/master/templates/community/dotnet-baget.json template.template.openshift.io/dotnet-baget-persistent created template.template.openshift.io/dotnet-baget-ephemeral created
As we can see, this creates two templates: one for a persistent and one for an ephemeral deployment of BaGet.
These templates accept a number of parameters. For example, to see the parameters from dotnet-baget-persistent
execute:
$ oc process --parameters dotnet-baget-persistent
Parameter Name | Description | Default |
---|---|---|
NAME |
The name assigned to all of the front-end objects defined in this template. | nuget |
MIRROR_PACKAGESOURCE |
Packages that are not found locally will be retrieved from this server. | https://api.nuget.org/v3/index.json |
NUGET_API_KEY |
Set this to a password required to push packages. | |
DELETION_BEHAVIOR |
Set this to -Unlist to make packages undiscoverable, or to HardDelete to remove packages from storage. |
Unlist |
MEMORY_LIMIT |
Maximum amount of memory the .NET Core container can use. | 512Mi |
VOLUME_CAPACITY |
Volume space available for data, e.g. 512Mi, 2Gi | 512Mi |
DOTNET_IMAGE_STREAM_TAG |
The image stream tag that is used to build the code. | dotnet:2.2 |
NAMESPACE |
The RHOCP namespace where the .NET builder ImageStream resides. | openshift |
SOURCE_REPOSITORY_URL |
The URL of the repository with your application source code. | https://github.com/loic-sharma/BaGet.git |
SOURCE_REPOSITORY_REF |
Set this to a branch name, tag, or other reference for your repository if you are not using the default branch. | v0.1.29-prerelease |
DOTNET_STARTUP_PROJECT |
Set this to a project file (for example, csproj ) or a folder containing a single project file. |
src/BaGet |
We see that the service by default will mirror packages from nuget.org (MIRROR_PACKAGESOURCE
). Our container is assigned 512MiB of RAM (MEMORY_LIMIT
). We provision 512MiB (VOLUME_CAPACITY
) for persistent storage. The NuGet service will be built from https://github.com/loic-sharma/BaGet.git v0.1.29-prerelease
(SOURCE_REPOSITORY_URL
and SOURCE_REPOSITORY_REF
). The NUGET_API_KEY
is empty: no key is required to push packages to this server. The hostname for our service is nuget
.
We'll now deploy the server in our project:
$ oc new-app dotnet-baget-ephemeral -p NAMESPACE=$DOTNET_NAMESPACE
RHOCP will build BaGet from source. We can see the progress of the build:
$ oc logs -f bc/nuget
When the build finishes, the NuGet service will be deployed and can be used internally in the project via the URL http://nuget:8080/v3/index.json
.
Let's see how this local NuGet service affects build times.
We'll deploy the dotnet-example template and trigger a number of builds:
$ oc new-app dotnet-example -p NAMESPACE=$DOTNET_NAMESPACE $ oc start-build dotnet-example;oc start-build dotnet-example; oc start-build dotnet-example
In the OpenShift Console, we get an overview of the build times without the local NuGet server:
Now we'll deploy the same application and use the local NuGet server as a cache:
$ oc new-app dotnet-example -p NAMESPACE=$DOTNET_NAMESPACE -p NAME=dotnet-example-nuget -p DOTNET_RESTORE_SOURCES=http://nuget:8080/v3/index.json $ oc start-build dotnet-example-nuget; oc start-build dotnet-example-nuget; oc start-build dotnet-example-nuget; oc start-build dotnet-example-nuget
As we can see from the graphs, using the local NuGet server significantly reduces the build time. The builds using nuget.org directly have a huge variation between build times, which is gone with the local server. We see our first build with the local server took a bit longer. During this build, packages were retrieved from nuget.org and cached locally. Those packages were then re-used for the successive builds.
Conclusion
In this article, we’ve looked at options to deploy a NuGet server locally. We then saw how you can use a local NuGet server to speed up .NET Core builds on Red Hat OpenShift Container Platform.
Additional .NET Core articles on the Red Hat Developer blog
- Building .NET Core container images using S2I
- Locating special folders in cross-platform .NET applications
- Using Kubernetes readiness and liveness probes for health checks with ASP.NET Core 2.2 on OpenShift
- Announcing .NET Core 2.2 for Red Hat Platforms
- Running Microsoft SQL Server on Red Hat OpenShift
- Securing .NET Core on OpenShift using HTTPS
- Improving .NET Core Kestrel performance using a Linux-specific transport