You are missing the point I think: Running a setup like this allows developing and testing the environment only once for the first app you develop with these dependencies. You basically get deployment as well as the development environment for further projects based on this environment for 'free'. Having Docker between VirtualBox and Mono adds almost no overhead while giving you a nice clean slate with no environment properties from other projects that could somehow influence the runtime behavior.
Now, the question for me is whether this is worth it for .Net - is Mono so good, that one would want to lock himself into a Linux-only environment like this?
VirtualBox: the author is using a Windows machine so needs to run Linux in order to experiment with Docker.
Docker: well, this is the subject of the post.
Mono: Mono is an application runtime (specifically an open-source implementation of the CLR) just like the JVM (yes, a 'Virtual Machine' but not virtualization, I would argue, in the sense that you are stating there is too much of).
Obviously if you had .Net apps and a Windows server environment you would just deploy .Net apps to it. But there might be scenarios in which this is useful. Perhaps migrating away from Windows servers to Linux, but not wanting to rewrite the C#/.Net apps in a new platform. Although whether Mono would be able to run those apps satisfactorily (the coverage of the SDK is not complete) is of course up for debate.
The answer to your latter question is: no. Only pretty trivial stuff is portable to Mono. I've tried it on every project I've worked on over the last 6 years to no avail. Show stopper every time.
Mix of both. The killer on the server-side is always stuff like missing WCF features, odd bugs with DI containers, missing API calls, slight behavioural differences etc.
Client-side. No WPF and WinForms is dreadfully incomplete.
It's a no go. If you start on Mono and deploy to .Net I imagine it'd work but no-one realistically does that these days. If they were going to do that, Java would be a better choice for the product.
This is nonsense. You just have to dev with Mono in mind from the start. Basically, don't use WPF and WCF and you're all set.
I'm currently in a web app team with a C# backend. Two devs run Windows, one has a Mac, and one runs Ubuntu. It works great. And yes, we deploy to Linux using Docker.
"You just have to dev with Mono in mind from the start."
You say that like it's the most trivial thing in the world. Most people attempting Mono have been loyal Windows-based .NET developers for years. Mono only has value for them if they can port their legacy apps from Windows and .NET to Mono.
> You just have to dev with Mono in mind from the start.
then it cannot replace .net .You can put it every ways you want serious C# and .net development is windows only.
Mono doesnt run every C# library out there.
The people pushing mono here dont have to face the consequences of that choice.
It's easy for them to say "it just works", they wont be around when one realises it doesnt work. Dont use mono thinking it really works.It's an experiment.
It is abstraction layers all the way down. We all find our level of comfort in the stack, somewhere between the most abstract thing currently achievable and CPU microcode.
In this particular case it makes something otherwise tedious much simpler, which is what adding abstraction is always about.
I experimented wih docker a few month ago and made a docker image for the .NET kooboo CMS running on monofastcgi/nginx as an exercise. Here's the link if someone is interested: https://github.com/guillaume86/KoobooCMS
After some careful thought, I can't see a place anymore for virtualization in a development workflow. If your hosting provider uses it, sure, whatever, but ideally you shouldn't be using it in development or working your production environment around it.
Code should be written portably, it should depend on the language runtime, vendored libraries and nothing else. Finicky OS/language combos should be avoided, like Ruby on Windows. If you have to use virtualization to ensure that your dev/prod environments are the same, then that's a code smell. It should work the same on Ruby 2.1.0 on OSX in rbenv as it does on Ubuntu using the 2.1.0 BrightBox PPA install.
The most important thing about 12 factor, in my opinion, is the separation of code and configuration. Everything that varies between environments and deploys should be considered configuration and off-loaded to a configuration management system. The VagrantFile embeds configuration directly into your code and makes your application less portable, not more.
Configuration management should provide encapsulation at the level of a particular version of an operating system. You should be able to, by only changing your CM scripts, change your OS between different versions of Ubuntu, or even between Ubuntu and Red Hat. If you can't, that's a code smell.
Your hosting provider should also be abstracted over and encapsulated as well. Changing hosting providers from Linode to Amazon should not require changing your OS scripts.
All of this can and should be done without Big Design Up Front, it should not take you any longer to do this than to configure your app to support Docker.
What this buys you is real robustness. Virtualization to me is a crutch that protects lazy programmers, it's fixing the wrong problem. If you find yourself relying on snapshots, it's a code smell and it will come back to bite you in the ass.
If you think Docker is going to solve all your portability woes, you'll be in for a shock the first time your OS stops being supported by the vendor and you have to move to a new one. If you've done it the way I've described, then you can copy your CM script for the old OS to the new OS, try a cold deploy, and fix the small number of issues that will come up.
If not, then you'll be in for a long weekend. Or worse, you won't do it at all, like the last five guys that came before me at my job.
> The most important thing about 12 factor, in my opinion, is the separation of code and configuration.
Nothing to do with configuration. Sometimes you need an envirronment where components of that env are not available on your system. For instance redis or nginx used to be linux only.
Also it's easier to pass around images in a team,than installing manually every components or libraries one needs. No time is lost in setting up and configuring this or that.
Further more virtualisation == 0 consequences on your machine.You can screw up stuff and experiment without worrying about doing something wrong,it doesnt matter.
So no side-effects,no configuration,os independent,easy to share images => better development env. You dont have to use docker ,i dont, but cirtualisation really helps.
> Also it's easier to pass around images in a team,than installing manually every components or libraries one needs.
You're right, Bundler in Ruby seems to have spoiled the hell out of me. I don't think nginx belongs in your development environment. If something's not available for your system, virtualization can be used effectively, if you run one machine per service you're depending on, as it would be done in production. Or architecture your app so that you can use dummy services in development. With thin interfaces and continuous integration this shouldn't introduce any problems.
But really, you should be picking mature services to depend on. One of the signs of a mature software project is that it is available for multiple environments and the configuration remains mostly similar. External service configuration should be considered code and committed to your repo. All that's in your project config should be where the service is at and what port it's running on. You could make the argument that depending on something that's not available for all the development environments you're working with is a smell.
> Further more virtualisation == 0 consequences on your machine.
Personally, I treat my development machine as "crash-only software". If something goes wrong with it, I'll wipe it, re-install it, then git pull and bundle install. All important files are kept elsewhere and my development workflow is streamlined enough so that I can reinstall everything pretty quickly. All of my tools are in my dock. Chrome, Sublime, Sequel Pro, iTerm, and an SSH Tunnel Manager, the latter I consider an ugly hack and am working to get rid of. Service dependencies are painless to install with Homebrew.
>Personally, I treat my development machine as "crash-only software". If something goes wrong with it, I'll wipe it, re-install it, then git pull and bundle install. All important files are kept elsewhere and my development workflow is streamlined enough so that I can reinstall everything pretty quickly.
Hmm, you seem to basically be describing Vagrant, but with the added complexity of resetting the rest of your computer as well.
Do you install and run Chrome, Sublime Text and the like on Vagrant? I've never actually had to do that, because I don't think you should need to, these software packages shouldn't mess up your system, if they are then you're doing something wrong.
22 comments
[ 3.4 ms ] story [ 86.7 ms ] threadNow, the question for me is whether this is worth it for .Net - is Mono so good, that one would want to lock himself into a Linux-only environment like this?
Docker: well, this is the subject of the post.
Mono: Mono is an application runtime (specifically an open-source implementation of the CLR) just like the JVM (yes, a 'Virtual Machine' but not virtualization, I would argue, in the sense that you are stating there is too much of).
Obviously if you had .Net apps and a Windows server environment you would just deploy .Net apps to it. But there might be scenarios in which this is useful. Perhaps migrating away from Windows servers to Linux, but not wanting to rewrite the C#/.Net apps in a new platform. Although whether Mono would be able to run those apps satisfactorily (the coverage of the SDK is not complete) is of course up for debate.
Client-side. No WPF and WinForms is dreadfully incomplete.
It's a no go. If you start on Mono and deploy to .Net I imagine it'd work but no-one realistically does that these days. If they were going to do that, Java would be a better choice for the product.
Not that I want to use any of them myself :)
I wish one day microsoft will be forced to port/support .NET (at least server components) to linux but I'm not holding my breath...
I'm currently in a web app team with a C# backend. Two devs run Windows, one has a Mac, and one runs Ubuntu. It works great. And yes, we deploy to Linux using Docker.
I agree with you but I wouldn't do it myself.
You say that like it's the most trivial thing in the world. Most people attempting Mono have been loyal Windows-based .NET developers for years. Mono only has value for them if they can port their legacy apps from Windows and .NET to Mono.
then it cannot replace .net .You can put it every ways you want serious C# and .net development is windows only.
Mono doesnt run every C# library out there.
The people pushing mono here dont have to face the consequences of that choice.
It's easy for them to say "it just works", they wont be around when one realises it doesnt work. Dont use mono thinking it really works.It's an experiment.
In this particular case it makes something otherwise tedious much simpler, which is what adding abstraction is always about.
Code should be written portably, it should depend on the language runtime, vendored libraries and nothing else. Finicky OS/language combos should be avoided, like Ruby on Windows. If you have to use virtualization to ensure that your dev/prod environments are the same, then that's a code smell. It should work the same on Ruby 2.1.0 on OSX in rbenv as it does on Ubuntu using the 2.1.0 BrightBox PPA install.
The most important thing about 12 factor, in my opinion, is the separation of code and configuration. Everything that varies between environments and deploys should be considered configuration and off-loaded to a configuration management system. The VagrantFile embeds configuration directly into your code and makes your application less portable, not more.
Configuration management should provide encapsulation at the level of a particular version of an operating system. You should be able to, by only changing your CM scripts, change your OS between different versions of Ubuntu, or even between Ubuntu and Red Hat. If you can't, that's a code smell.
Your hosting provider should also be abstracted over and encapsulated as well. Changing hosting providers from Linode to Amazon should not require changing your OS scripts.
All of this can and should be done without Big Design Up Front, it should not take you any longer to do this than to configure your app to support Docker.
What this buys you is real robustness. Virtualization to me is a crutch that protects lazy programmers, it's fixing the wrong problem. If you find yourself relying on snapshots, it's a code smell and it will come back to bite you in the ass.
If you think Docker is going to solve all your portability woes, you'll be in for a shock the first time your OS stops being supported by the vendor and you have to move to a new one. If you've done it the way I've described, then you can copy your CM script for the old OS to the new OS, try a cold deploy, and fix the small number of issues that will come up.
If not, then you'll be in for a long weekend. Or worse, you won't do it at all, like the last five guys that came before me at my job.
Nothing to do with configuration. Sometimes you need an envirronment where components of that env are not available on your system. For instance redis or nginx used to be linux only.
Also it's easier to pass around images in a team,than installing manually every components or libraries one needs. No time is lost in setting up and configuring this or that.
Further more virtualisation == 0 consequences on your machine.You can screw up stuff and experiment without worrying about doing something wrong,it doesnt matter.
So no side-effects,no configuration,os independent,easy to share images => better development env. You dont have to use docker ,i dont, but cirtualisation really helps.
You're right, Bundler in Ruby seems to have spoiled the hell out of me. I don't think nginx belongs in your development environment. If something's not available for your system, virtualization can be used effectively, if you run one machine per service you're depending on, as it would be done in production. Or architecture your app so that you can use dummy services in development. With thin interfaces and continuous integration this shouldn't introduce any problems.
But really, you should be picking mature services to depend on. One of the signs of a mature software project is that it is available for multiple environments and the configuration remains mostly similar. External service configuration should be considered code and committed to your repo. All that's in your project config should be where the service is at and what port it's running on. You could make the argument that depending on something that's not available for all the development environments you're working with is a smell.
> Further more virtualisation == 0 consequences on your machine.
Personally, I treat my development machine as "crash-only software". If something goes wrong with it, I'll wipe it, re-install it, then git pull and bundle install. All important files are kept elsewhere and my development workflow is streamlined enough so that I can reinstall everything pretty quickly. All of my tools are in my dock. Chrome, Sublime, Sequel Pro, iTerm, and an SSH Tunnel Manager, the latter I consider an ugly hack and am working to get rid of. Service dependencies are painless to install with Homebrew.
Hmm, you seem to basically be describing Vagrant, but with the added complexity of resetting the rest of your computer as well.