IncludeOS: a minimal unikernel operating system for C++ services
includeos.org
includeos.org
> IncludeOS is a minimal unikernel operating system for C++ services running in the cloud and on real hardware.
Unlike some other methods for reducing carbon emissions, which require subsidies to be competitive, massively reducing server infrastructure footprint often improves the absolute economics through radical reductions in OpEx/CapEx for data intensive businesses.
That said, if your goal is reducing expenditures, reducing your carbon footprint is a great cherry on top.
1- Yes, optimizing for lowering this consumption by an app-developer can definitely be an ill-advised endeavor economically (you're saving 0.1-10% of your cost.. by adding a huge investment of time, possibly larger than the application development itself) 2- Optimizing across all deployments, can definitely move the needle, in a very significant way, against the effort required, since you're automatically deployed on 1000-1M places.
It's the same reason library developers (especially system/langugage/heavily-used-libraries) have a very good reason economically (and therefore ecologically as well) to optimize. Competition here is a huge benefit to everyone, including the environment.
If you want to see what real computing energy looks like, look at Bitcoin.
If you're using runtime languages on the backed (node, python) then you're already failing the environment. An efficient compiled language can perform the same functions much more efficiently.
Not necessarily. If you make a living running a typical CRUD software-as-a-service offering, your code may really just be glue mapping HTTP requests to database requests. There, your choice of language doesn't count for much; your code isn't doing heavy lifting, the DBMS is.
It's quite possible your hardware requirements could be lower by writing in Python and tuning your database, rather than spending the same time writing non-performance-critical code in C++.
Frameworks like Tornado, for Python, are able to quite efficiently handle highly concurrent workloads, despite using a single-threaded, interpreted, language.
For computationally intensive code, then sure, a language like Python will need far more hardware horsepower to get the job done than C++ would.
This post is about an optimized environment for C++ services though - not node or python services.
> more minimal
Which carries other benefits: boot time, memory overhead, etc. You could probably treat IncludeOS VMs like containers.
Technical speaking, a clean slate solution always offer better quality for the targeted usage scenario.
The problem however, is how much users would be willing to pay for the difference in quality.
Being able to share the kernel safely means potentially better utilization. (The progression is dedicated machines -> hypervisor-based VMs -> multiple customers sharing the Linux kernel. gVisor exists for that last step, but I don't see anyone willing to sell me the ability to run my random container next to their mission-critical security-sensitive app, whereas people are perfectly happy to share CPUs with me if there is a hypervisor in the middle. But we're certainly moving in that direction.)
It is also intriguing to imagine a world that moves the other direction; just have a giant computer with thousands of power-efficient CPUs in it and no virtualization. When a request comes in to your app, your CPU is just powered on, your app boots in a millisecond, handles the request, and shuts down. I am not sure even the big cloud providers have solved the time-of-day utilization problems; being able to turn most of the computers off at night has some potential to save money. (I would turn my workstation off at night if it booted in 1 millisecond in the morning, for example. I can also imagine some power savings for mobile devices if they could go hard off for 59 seconds out of every minute.)
Do AWS spot prices fall at night? That would be one way of increasing utilization - assuming, of course, that there’s sufficient demand at any viable price. There most only be so many jobs people are willing to run unobserved overnight in order to save money.
Or perhaps AWS (and others) are actually powering systems up and down to meet demand? That makes a lot more sense, I suppose.
There's no reason to believe Spectre and Meltdown were a one time thing, especially since the response has been to apply ad-hoc fixes just good enough to break the proofs-of-concept. On the contrary, they demonstrate that such vulnerabilities are possible and we should expect to see them again.
Even barring CPU bugs, the kernel is one giant attack surface, all written in C, all running with full ring 0 privileges. Find ONE hole to pwn.
> A longer list of features and limitations can be found on our documentation site.
But unfortunately it looks like the linked page doesn't actually talk about limitations :) Unless you consider a warning about hlt-ing yourself in the foot a list of limitations I guess.
- You can't just port anything to IncludeOS. Since you have direct hardware control and you can schedule work directly to numbered CPUs you can take advantage of things, but if you don't do that then you are just living in a limited C++ environment.
- The network stack hasn't been built with multiprocessing in mind, and some parts need to be rebuilt because of that
- There are codepaths that could lead to C++ exceptions, such as being out of memory, which trounces performance.
- There is a paging and memory allocation system in the OS which doesn't have to be there (for example paging can be "burned in" to the image for the most part, while only leaving room for adding pages for stacks. Memory can be handled by donating everything to the C standard library) - the goal being to keep the attack surface lower.
- Debugging is hard - you will have to connect to GDB while pausing somewhere in the OS.
This is really just me thinking out loud. Add salt.
I don't know whether things have improved since then.
Also a big collection of info on unikernels: https://github.com/cetic/unikernels
Am I missing something obvious?
The bigger risk is DDoS attacks but that’s risk when writing sloppy code in any language, runtime and hosting environment.
The alternative for people using this approach is running in a kernel module, or a kernel-bypass setup with root permissions. Grown-up stuff. Eliminating most of the kernel, and using C++ not C is a very substantial improvement over status quo.
This is a really weird hill to die on; I see you've made the same comment several times in this thread. C and C++ fit hand in glove, and lots of folks use them in conjunction. I don't think anybody here has the misconception that C/C++ is a single language, unless perhaps they don't know either.
Equating the two is extremely common, even by people who are certainly equipped to know better. When you feel a need to tar C++ as if it were C, you signal the weakness of your argument before you have even expressed it.
Please turn down your flamethrower, that style of conversation is not welcome here.
It is fine when talking about ABI or object-code generation.
The failure modes of Rust code are very different from C's, but calling C libraries, as is usually a practical necessity in production, exposes you to all of them.
Switching to modern C++ nets 90% of the benefit (plus other benefits Rust lacks, and may always lack) for 10% of the cost and 0% of the hump.
So, is it C/Rust and C/C++, or Rust and C++?
The "/" symbol is an infinitely extensible shorthand for a union.
Two ways to address those concerns:
- Your app runs on bare metal and security is implemented on the network layer. For example, something external to app handles authentication and you have something in front of the bare metal box examining and approving requests (like other apps).
- Your app runs in a VM and the hypervisor handles security.
The local user-based security model has been insufficient on the server end of things ever since publicly widely accessible cluters of HTTP servers with load balancers became the norm. Of course you want to protect the local server but we're much more interested in authenticating and applying security beyond the boundaries of any individual OS. There is LDAP and numerous standards but they require implementation beyond the OS - your own or reliance on a third party like Google or Microsoft. If you have to reimplement this with microservices then who cares about the local OS?
A microservice that is only spoken to via HTTP GET or POST requests could get away with removing a lot of things in a traditional OS, such as shells, TTYs, console support, all drivers unrelated to CPU features or networking (no SCSI, floppy, etc.), all drivers unrelated to sending/receiving data through a NIC (no xtables support, no NAT/routing, no weird TCP options no one uses, no weird protocols no one users, no conntrack), no dnotify/inotify support, and maybe even go so far as to remove code behind syscalls that the app doesn't actually use. No TTY support means no one's logging in, so who cares about users at this point?
A non-microservice app, like CGI scripts invoked via Apache, is probably a poor choice for unikernel, but a front-end caching webserver may not be.
https://news.ycombinator.com/item?id=10661746
https://news.ycombinator.com/item?id=10741350
2016: https://news.ycombinator.com/item?id=11154168
2017: https://news.ycombinator.com/item?id=13975994
Memory and thread safety properties can be achieved in C++ by operating at a higher level than C with mature, well-debugged, well-optimized libraries. No pointers means no pointer errors.
Integer overflows are equally possible in Rust and C++. Both offer debug build modes that can watch for those.
Eh, not to the extent that Rust does. It’s still reasonably easy to get use-after-frees by using a value that has been moved or destroyed.
> Integer overflows are equally possible in Rust and C++. Both offer debug build modes that can watch for those.
In Rust the behavior is defined regardless of signedness.
I have the same discussion with people who insist unsigned types in C++ or C are safer than signed types because of the UB boogeyman. They only demonstrate their own limited understanding.
Use after free can be perfectly well expressed with C++ references, or invalidated iterators to standard library containers.
> Integer overflows are equally possible in Rust and C++.
In C++, unsigned integer overflows can often be leveraged into out-of-bounds access; in safe Rust, they cannot.
The first commits to IncludeOS were 2014, when Rust was in a high state of flux; before the 1.0 release. So I'm certainly not surprised given the historical context of the two projects.
Rust has some cool features, but believe it or not, C++ is still a popular language and people continue to develop projects that are older than Rust. So even if you're of the opinion that C++ is entirely deprecated by Rust, we're not going to stop the entire world and rewrite every C++ project in Rust.
But good news! You can run your Rust apps in a Rust-based unikernel OS [1]. Since these OSs are meant to run in containers, the ecosystem is big enough for both and we don't need such shedpainting conversations.
Anyone else have a unikernel recommendation besides IncludeOS + rpi 4?
> Node.js-style callback-based programming - everything happens in one efficient thread with no I/O blocking or unnecessary guest-side context switching.
Unless I'm missing something.
Then asserts that the retail price for the paper edition is the point ebooks should undercut by, oh, 25%.
This ignores the fact that publishers are not retailers, they're manufacturers; the retail sector takes 50-70% of the price the customer pays for a book, and this includes Amazon's kindle store. In actual fact, the physical cost of goods for a paper book is less than 10% of the price the customer pays. Another 10% is editorial/typesetting costs which are exactly the same for the ebook, maybe 10% goes to the author, and 50-70% to Jeff Bezos and co.
Great technology, top tier team. Although I believe their distance to Silicone Valley and relatively cheap capital causes their difficulty.
I'm thinking as an alternative to CoreOS or COS. These OSs will likely have a relatively high overhead in comparison to IncludeOS should such an OS exists.
Advantage over embedded being you don't need jtag hardware.
What you are describing is an embedded system, which is done, very commonly. This thing is effectively running like an embedded system within a larger system.
So I stick to ./configure ; make ; make install
As for context swicthing etc I need some unixy bases. Instead of reinventing everything, I've found in practice that the linux kernel running my programs on baremetal (no virtualization) keeps the overhead to an acceptable minimum.
All this is well-documented and -understood. The overhead is in no way imaginary.
Unikernels don’t need to do context switches, by virtue of not having processes.