Doing a Self-Contained Deployment (SCD) of a .NET Core Application on Ubuntu
In this article, it's assumed that you have basic knowledge of .NET Core and application development targeting .NET Core.
Now let’s see how we can do a Self-Contained Deployment (SCD) on an Ubuntu machine where there is no .NET Core SDK installed.
So basically that’s the most important aspect of doing a SCD, we are no longer dependent on a machine-wide framework. The framework is bundled with the application (and third party dependencies, if any) and it will get run on top of that. Where as in FDD (Framework-Dependent Deployment), we are deploying only the application (and third party dependencies if any). The application will get run on top of the framework which is installed on the machine.
Here let’s start by creating a Console Application targeting .NET Core and Visual Studio 2015 Update 3 is being used.
(You need to note that for this demo, the latest stable versions of tools and frameworks as of today (6th January, 2017) is being used. There is a possibility that some of this will get changed in the future. For instance, we will be using project.json and it will get removed in Visual Studio 2017. But all we really need to do is understand the concept.)
https://lh3.googleusercontent.com/-GRWLppHIEHg/WG35vZ7cztI/AAAAAAAAETE/ZjHWGvr9PeU/image_thumb%25255B8%25255D.png?imgmax=800 |
Console Application (.NET Core) |
Having said that, now the project is created. This is what the default project.json looks like (this may be different from yours and it is based on the version of .NET Core tools that you have installed).
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
}
},
"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50"
}
}
}
Here let's remove the imports section and instead of targeting .NET Core 1.0, let's target .NET Core 1.1 as it’s the latest as of 6th January, 2017.
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
},
"frameworks": {
"netcoreapp1.1": {
}
}
}
Now let’s do the changes required to make this application be deployed as SCD.
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"runtimes": {
"ubuntu.16.04-x64": {}
},
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0"
}
},
"frameworks": {
"netcoreapp1.1": {
}
}
}
First thing we did was remove the type=”platform” element. That is what specifies whether this is going to be a SCD or FDD. Here we have also specified the Ubuntu runtime (our Ubuntu installation is 16.04.1) as it’s mandatory when doing a SCD. You can find the list of .NET Core Runtime IDentifiers (RID) here).
Now we have modified Program.cs to print "Hello World" to the console. Nothing fancy over there.
public class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine("Hello World");
}
}
Now let’s move into dotnet CLI, and do the build and release. We are not going to run dotnet restore, as we we are using Visual Studio and it was doing the package restoration upon project.json changes for us. If you are on VS Code or another editor, run dotnet restore to restore the packages.
To build the application against our targeted runtime, let's run the following command.
dotnet build -r ubuntu.16.04-x64
https://lh3.googleusercontent.com/-XIzI4FiG224/WG35wv1cpyI/AAAAAAAAETM/j3LEDipFQus/image_thumb%25255B4%25255D.png?imgmax=800 |
Result: Build |
Now to create the release package, let's run the following command.
dotnet publish -c Release -r ubuntu.16.04-x64
https://lh3.googleusercontent.com/-liiCu1WWPBM/WG35yHGl1WI/AAAAAAAAETU/66wUfEg6xiM/image_thumb%25255B7%25255D.png?imgmax=800 |
Result: Release |
You can see that a folder named publish has been created under {project}\bin\Release\netcoreapp1.1\ubuntu.16.04-x64.
Now you just need to copy/move the publish folder into a Ubuntu machine and here it is.
https://lh3.googleusercontent.com/-XiV-LUZWskU/WG35z-ay_UI/AAAAAAAAETc/fLs7rDT9uz4/image_thumb%25255B11%25255D.png?imgmax=800 |
Published folder on Ubuntu |
Now open up a terminal. You can see that we have not installed .NET Core over there.
https://lh3.googleusercontent.com/-7OYK71aR2q0/WG3509VbG5I/AAAAAAAAETk/byqZTTT-7ew/image_thumb%25255B17%25255D.png?imgmax=800 |
dotnet |
Now let’s try to run the application.
https://lh3.googleusercontent.com/-zMIFz45gXQE/WG3515_0DfI/AAAAAAAAETs/arQJtrrBjwo/image_thumb%25255B15%25255D.png?imgmax=800 |
Running the application |
Here we are thrown with an error “Failed to initialize CoreCLR, HRESULT: 0x8007001F”. And it is caused by a permission issue.
Let’s try giving all the permission to the executable and try back again.
https://lh3.googleusercontent.com/-9OkJL0nvRI8/WG353eVuNQI/AAAAAAAAET0/k9v7vgSdpcE/image_thumb%25255B23%25255D.png?imgmax=800 |
Running the application |
Everything is working great!
Some important thing to note here, in .NET Core Application Deployment documentation under SCD it says, "Creating an SCD does not, however, include the native dependencies of .NET Core itself on various platforms (for example, OpenSSL on macOS) so these need to be installed before running the application.". So there is a list of dependencies for Ubuntu and is not manually installed in the demo Ububtu machine. If you are confused about that, -dev packages contain headers that allows one to recompile software that depend on these libraries. If you need to only run such software, the package without -dev may be installed. For example, **libicu/libicu{somenumber} **may be already installed. That's why your application runs fine. You'll need *-dev packages if you want to compile dotnet itself.
Happy Coding.