I have a bunch of Windows SERVICES with ServiceStack which I have to migrate to Docker on LINUX. I guess I have to rewrite some of my code to be .NET core compatible. Since I have to keep Windows servers, I guess that in fact I have to code and build all my DLL projects compatible with .NET Standard 2.0, correct?
In the past I used MSVS with ReSharper to build my Windows code against .NET 4.6.1. For Docker on Linux I have a CentOS 7 VM with JetBrains Rider IDE. The idea is to have build which produces a Docker image instad of .EXE and .DLL files on Windows.
I am reading the ServiceStack .NET Core documentation and installed NodeJS on my CentOS box to have npm. I then installed servicestack/cli. I also have JetBrains Rider running with Mono, msbuild etc, ready to build .NET core stuff. Now I have a few confusions:
- The linux equivalent of a Windows service is a deamon. Is this selfhost in ServiceStack terminology or what kind of project do I need to create?
- In the ServiceStack doc I read somewhere that it is recommended to use ASPDOTNETCORE for docker since it is faster and has a smaller memory footprint than .NET Core 2.0. Does this mean I should use selfhost-corefx template for a project?
- All my current Windows servers are built very modular which means I put almost everything in DLLs. The EXE file is usually a project containing the Program.cs, AppHost.cs, WinService.cs and WinServiceInstaller.cs files as well as configurations and packages. Do I need complete new versions of these projects for Docker based services?
- I just noticed that I have a lot of compatibility issues with libs I have loaded from NuGet on .NET core. (Not all libs I use seem to support .NET core 2.0 yet, some stuff like a reporting server is based on GDI which will never run on Linux) Do you have any hints how to port my running Windows code to .NET core? Good documentation, best practice, traps to avoid.....
Many thanks for some kick-start infos that help me get started with porting my code to docker and LINUX ...
ok you're confusing a lot of things here and are misunderstanding a lot of core assumptions. I recommend starting with small well-defined goals when trying to learn new technologies to help build understanding of what you're using.
It sounds like you want to deploy your App in Docker on Linux so just focus on that first. I'd recommend changing the least about your existing environment to minimize the number of new products/technologies you need to learn and use. If you're used to using VS.NET/R# just use that. .NET Core Apps are cross-platform so you can develop with what you're comfortable with on Windows and just build and deploy that. e.g. all our .NET Core Apps are developed on Windows and deployed to Linux.
In which case you don't need any IDE's installed in your Linux server, you just need to install the .NET Core SDK on your Linux Server. To create a Docker version of your App on Linux you just need a copy of your Source code (e.g. git clone) and run a bash script to build (e.g. docker build) your Docker App from a
DockerFile. Many of our .NET Core Apps contains
Dockerfile in the root of every project. We have a guide on deploying .NET Core Apps with Docker to AWS EC2 which uses Travis CI to build the .NET Core Docker App so we don't even to use our own Linux server to create the Docker build.
The Docker Apps which don't have Dockerfile's are built on Windows, deployed with rsync and run with supervisord which you may want to consider, especially during development since you can build/debug on Windows and run a single bash script with WSL to deploy your App to a remote Linux Server. This is what I do when I want to quickly deploy/test a local .NET Core App on linux.
Publish a Release build of your App with
dotnet publish, e.g:
c:\> dotnet publish -c Release
Which generates a build of your .NET Core App which can be run on any OS with .NET Core installed, e.g. you can test it in Windows by going to the publish output folder and running your Project .dll, e.g:
Then to deploy I just run a bash script with WSL:
deploy.sh just copies the incremental changes to the publish folder with rsync and restarts the monitored supervisor process, e.g:
rsync -avz -e 'ssh' bin/Release/netcoreapp2.0/publish/ firstname.lastname@example.org/deploy/path
ssh email@example.com "sudo supervisorctl restart my-supervisor-task"
You can find some info on setting up supervisor, nginx in Deploying Web Apps.
Forget about this, a deamon is just a background process. All .NET Core Apps are Console Apps, if you're deploying in a Docker container you just need to run your .NET Core App as the Entry point in your Docker App.
Please always quote and link to the ServiceStack docs you're referring to, this inference is inaccurate, the docs don't say anything like this. There's only 1 .NET Core platform your .NET Core App targets which can be run on the .NET Core runtime of each supported OS (e.g. Win/OSX/Linux). I have no idea where you got the
ASPDOTNETCORE token from, the ALL CAPS makes it look like an Environment variable, although it's not one that I've seen before.
The only thing I can assume you're referring to is that we changed our .NET Core Apps to use multi stage Docker builds. This just means that we use the
microsoft/aspnetcore-build:2.0 Docker Image to build our App and deploy the published outputs to run in the leaner
microsoft/aspnetcore:2.0 Docker container. This is similar to needing the .NET SDK to build your .NET Framework App and the .NET Runtime to run it.
Please refer to the Microsoft's docs on Your first ASP.NET Core Docker app. If you haven't already, please go through this step-by-step guide to deploy a .NET 2.0 Docker App. There is no "ServiceStack specific" steps or configuration for running in Docker which is just a generic container technology used for encapsulating and running any process, of which your .NET Core App is just a process that runs when the Container is started. A ServiceStack .NET Core App is also just a .NET Core App with ServiceStack configured to run as a single .NET Core middleware in its Request pipeline - any docs for deploying .NET Core Apps to Docker is relevant to all .NET Core Apps, since that's all it is.
No, it has no bearing of what .NET Core template you start with, any of them can run on .NET Core and by extension in a Docker container.
This is irrelevant, you can continue to modularize your App as you wish. Most ServiceStack templates follow the recommended Physical Project structure where your Host project is a thin layer containing your
AppHost its configuration and concrete dependencies. In .NET Core this includes the
Program.cs containing the Console App's Entry point and
Startup.cs which is akin to
AppHost in ServiceStack where your .NET Core App's dependencies and middleware/plugins are registered and configured.
The templates ending with
-corefx means ASP.NET Core App running on the .NET Framework, which refers to .NET Framework v4.6.2+ which means Windows only (ignoring Mono in all this). Only .NET Core Apps are cross-platform and can run on Linux. ASP.NET Core Apps can run on .NET Framework in Windows (i.e. ServiceStack templates ending with
-corefx) or on (Windows/OSX/Linux) with .NET Core. If you wish to run in Docker on Linux you need to run on .NET Core which means any project template in ServiceStack .NET Core 2.0 Templates
Note: .NET Core 2.0 templates don't have any
What you need is to ensure you're building a .NET Core App which is what's required for your App to run cross-platform on the .NET Core runtime. Docker is irrelevant since it can run any process and by extension any .NET Core App.
This is a blocker, your App needs to run on .NET Core which means you can't use anything that doesn't run on .NET Core. So all your packages/dependencies need to have either .NET Standard or .NET Core App builds. Since ServiceStack v5 nearly all of ServiceStack NuGet packages have both .NET v4.5 and .NET Standard 2.0 builds, the .NET Standard 2.0 builds are what's used when running in .NET Core.
The only real tip is to target .NET Standard 2.0 in all your libraries which has the broadest and most compatible Surface area of .NET that can be used in .NET Core. ServiceStack-only Apps are trivial to port to .NET Core courtesy of being able to seamlessly integrate your ServiceStack AppHost in .NET Core Apps and most of ServiceStack packages including .NET Standard 2.0 builds which are used in .NET Core. The main difference is having separate WebRootPath and ContentRootPath, which is effectively the main change we needed to do when porting our ServiceStack .NET Framework Live demos to .NET Core - as we're effectively able to use the existing Service Implementations as-is.
You can't run anything with .NET Framework-only dependencies on .NET Core so you're going to need to plan on how you're going to handle remove that functionality from your App or rewrite it to use replacement deps which does run on .NET Core. For System.Drawing there is CoreCompat.System.Drawing which does run on .NET Core and is what we used in our .NET Core port of Imgur, although we've had some load/perf issues with it, so it's more for compatibility until you can replace it with something more robust. I'd personally use SkiaSharp for new projects since it's a well maintained wrapper over Google's SKIA library used in Chrome.
My recommendation would be to go through the Your first ASP.NET Core Docker App so you can get familiar with .NET Core and Docker. Than after you're comfortable start with one one of ServiceStack's .NET Core Templates, you probably want to start with the web template since it's an empty ASP.NET Core Web App then slowly copy over functionality from your existing App whilst verifying your App still builds.
Sounds like your biggest issue is going to be how you're going to handle functionality that's not available in .NET Core, so I would first look at identifying all dependencies which don't support .NET Core and workout how you plan to work around it with your .NET Core port. This may potentially be a blocker for being able to port your App, so it's better to try identify it upfront and save any potential wasted effort. When no replacements are possible you may need to extract that functionality behind a generic .NET Framework Micro Service on Windows which your .NET Core Apps call when it needs to execute functionality not available in .NET Core.
Thanks A LOT for this much information! Looks like I will start with kind of a 'Hello .NET core' service and adding stuff I need step by step. I was using VS 2015 and it worked more or less stable if you did not open more than four instances (it is still 32bit). VS 2017 is crap! It crashes a lot, is slower and the community edition has reduced functionality. Since I was developing C++ and Java for almost 20 years I was always happy with older VS vor native C++, Eclipse and later IntelliJ for Java. So I am moving step-by-step to Jetbrains Rider for all my server code.
There are three backend / middleware infrastructures I absolutely need for .NET core:
- Redis (I am using ServiceStack libs, so this should work just fine)
- MongoDB is the main datastore I use. I think this should work as well, but need to verify again. I think last time I was looking it had support for .NET core 1.3 only
- RabbitMQ. The latest native C# client (V 5) seems to support .NET core 2.0 only. I am using EasyNetQ, a library on top of the C# lib for Rabbit. I need to verify if this supports .NET core 2 already, otherwise I need to get rid of it and use the less convenient low level API.
For logging, validating etc I ususally use what ServiceStack is offering and therefore it should mostly work. There are a couple of other things such as the QUARTZ scheduler library which I need to upgrade to Version 3 to get .NET standard 2.0 support.
OK, looks like some testing sessions ahead but I guess it should be doable but need some time.
You can check to see if a NuGet package supports .NET Core by going to the NuGet page and click on Dependencies, e.g. for https://www.nuget.org/packages/EasyNetQ it shows:
- .NET Framework 4.5.1
- .NET Standard 1.5
If it has a .NET Standard build, it supports .NET Core. From ServiceStack v5 all .NET Core packages were upgraded to target .NET Standard 2.0 which means it needs .NET Core 2+ to run, which supports running all <= 2.0 .NET Standard builds.
Yeah I've had a lot of stability issues with VS as well. For small .NET Core Apps I prefer to just use VS Code since it has great multiple terminal window support where you can assign short-cuts to switch between each terminal. For larger .NET Core Apps I'm now using Rider for the back-end (C# Services) and using VS Code for all front-end UI (split in 2 Windows on my 27" iMac). I run
dotnet watch run in Rider's Terminal which saves me from building the App manually since it watches for changes and automatically builds/restarts the Web App which lets me make changes in VS Code and Rider - I use either for small changes to existing code, but Rider for any new development since its intelli-sense/refactoring is better.
But yeah I don't use VS .NET for any .NET Core Apps, just some .NET Framework Projects.
Ok, thanks again. Looks like I should get my stuff ported without too big rewriting efforts.
Yeah I like what JetBrains was doing over the past years, really good stuff. Moved from Jira to You Track and am very happy as well.
As a former 'Java Guy' I am also having an eye on Kotlin. I had a team of developers coding a large project in Groovy (which was an answer to Ruby for the JVM). But Kotlin looks a little bit like the C# for the JVM now, lots of concepts are kind of 'stolen from C#'. So maybe I will port my Reporting server from c# to Kotlin.
Can you say anything regarding performance and stability of .NET core servers on Docker? Is it slower than a Windows service running on a Windows server box? What about memory consumption? Do you have any experience comparing these environments?
Stability and Performance of .NET Core has been great. The only real issue perf/stability issues I've experienced is with the CoreCompat.System.Drawing I mentioned above, mainly because System.Drawing is not a good server graphics library and the CoreCompat.System.Drawing is an immature port of Mono's System.Drawing and locking issues with older version of SQLite in.NET Core, although I haven't noticed recently. But both these cases aren't reflective of .NET Core stability/performance since they're interops over native libraries.
We've got different .NET Core benchmarks at SSvsWebApi with v5 getting ~40k reqs /sec for a basic Hello ServiceStack Service on my iMac. I haven't performed a comparative benchmark with classic ASP.NET on equivalent hardware but it would be much less. But YMMV as throughput is highly dependent on type of workload and any I/O has significant impact on RPS marginalizing gains in raw request overhead. But in general performance is a primary goal for .NET Core so should generally perform better.
Docker as an abstraction is quite efficient, but there's not a simple % overhead you can apply as a lot is determined on the configuration used.
Thanks, that sounds good. Maybe I can post some details, once I have ported my services. Since my apps are based on MongoDB and Redis, the hardware is optimized for these kinds of workloads: lots of RAM and NVMe based SSDs. We will see how it rocks!