Base Runtime architecture overview
Disclaimer: Note this document is a work in progress. Although it presents some ideas we have and we’re currently implementing, nothing is set in stone and any aspect of this work can change at any given time.
This documents attempts to explore several approaches we can take while developing Base Runtime, either as a module or built and composed in the traditional manner. Both as part of the Generational Core or as a standalone, feature-rich module stack.
Note the team might be focusing on several approaches at once to determine which is the most suitable for our needs.
Base Runtime as part of the Generational Core
One of the approaches is to consider the Base Runtime module stack being part of another, larger module stack, the Generational Core.
Generational Core is a module stack that provides base system environment similar to today’s minimal installations with possibly several additional services, libraries and utilities on top. It’s meant to represent the platform core that is usable in itself but mainly serves as the enablement layer for additional applications, either provided by Fedora Project, Red Hat or third parties. This additional software would typically run in containers, therefore Generational Core also needs to provide container enablement tools.
The current idea is that Generational Core would consists of three large module module stacks that, to a degree, depend on each other, namely:
- Base Runtime — The hardware enablement layer + minimal runtime environment
- System Runtime — Enhanced runtime environment; provides several common, generally expected system services; my provide dynamic language runtimes as well; may provide system management and container enablement utilities
- Shared Components — Common libraries and utilities needed as dependencies for the two abovementioned module stacks
What components define these stacks is a task for the Base Runtime and Modularity teams to figure out — the Base Runtime team should focus on the Base Runtime stack and cooperate with the Modularity team on development of the latter two. However, in the beginning it will be the Base Runtime team who defines what the initial structure of Generational Core looks like. Later on the Modularity team will be responsible for enhancing this minimal set with additional features.
Another question is where the build dependencies of the Generational Core would be placed. There’s a couple of options how to approach this. We could either make the Generational Core self-hosting, i.e. it would include the entire build dependency chain for all of its components, we could create another module stack that would provide these named, for instance, Generational Core Build Environment, or we could do a little of both.
Note that components being included in a module doesn’t necessarily mean they are supported, guaranteed not to break, change or being removed any time. That is a question of the module API.
In the following subsections we briefly go through what components could be part of which parts of the Generational Core. While these decisions have certain engineering implications, they don’t re-define what Generational Core is and are mostly about labels.
Minimal Base Runtime
One way to do this is to keep the Base Runtime stack as minimal as possible. In this scenario it would provide hardware support, where applicable, i.e. kernel, kernel headers, distribution supported out-of-tree drivers, and a minimal userland runtime environment, i.e. glibc and gcc (or libgcc at least). Additionally, various tools closely tied to kernel, for example kexec or kmod, may also be included.
Minimal Base Runtime would be, in this case, defined by the combination of kernel, glibc and gcc ABIs. All three have a proven history of stability.
Any other components would live higher in the Generational Core stack — in System Runtime or Shared Components.
Pros:
- A small module with easy to keep API/ABI promises
- Quick and easy to rebuild on component updates
Cons:
- Not bootable or usable by itself; can only be experienced through other modules
Feature-rich Base Runtime
Another way would be keeping a considerably larger set of components in the Base Runtime module stack itself, providing, for example, several commonly used POSIX utilities, components from Red Hat LSB and possibly also whatever utilities required for module management. In this scenario the Generational Core would merely extend the base Base Runtime installation with additional, non-essential services and system management tools, enriching the platform experience.
Pros:
- Base Runtime is bootable and usable in itself without relying on additional modules
Cons:
- Maintaining the API/ABI promise is complicated
- Extending hardware support requires all the components to be re-built / re-tested, slowing down the release pipeline
Base Runtime without the Generational Core
This is the original proposal, similar to the Feature-rich Base Runtime described in the previous section. The idea behind this approach is to include the whole minimal installation in the Base Runtime module stack. Internally the stack would be composed of numerous smaller modules, much like the Generational Core is.
Since the main difference between this approach and the Generational Core is how we label things, this idea hasn’t been really explored much.
General concerns
No matter what direction we decide to take, the effort relies heavily on the ideas behind Modularity and implementation of Factory 2.0. Unfortunately, there are still many unknowns and several Modularity architecture aspects remain unaddressed to this day.
These impact the Base Runtime development effort and need to resolved before Base Runtime or Generational Core could be released. These include (the list is not exhaustive):
- How are modules going to be delivered in practice
- How are application modules going to be delivered?
- How is Base Runtime / Generational Core going to be delivered?
- Is it different from how application modules are going to be delivered?
- Clear ideas what it means for modules to depend on each other and how that would be implemented, from runtime perspective
- Clear ideas what it means for modules to depend on each other and how that would be implemented, from build time perspective
- Is this the same as including modules are additional content?
- Does there have to be a distinction?
- How is non-RPM content going to be built?
- Potentially included modules would be first non-RPM content
- Could different types of module content be combined in a single module?
- How would these be built?
- How would installation / runtime conflicts be resolved?
- What is the granularity of the API/ABI promise?
- Per-SRPM: Same as in Fedora and EL today
- Per-RPM: Broken down by binary sub-packages
- Per-symbol: Based entirely on exposed symbols and/or public headers
Given that Base Runtime / Generational Core are the first to be ever built and released, it’s likely the team will focus, in cooperation with Modularity and Factory 2.0, on resolving many of the abovementioned points. It’s important to keep this in mind and understand how general architecture design work could impact timely delivery of the core modules.