From c4d39fcf00365c8ff609cd4a4f711d4343a76c1a Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 17 Mar 2024 09:09:44 +0530 Subject: [PATCH 1/4] docs/concepts: Improve grammar and fix typos for the build process --- content/docs/concepts/build-process.mdx | 56 ++++++++++++------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/content/docs/concepts/build-process.mdx b/content/docs/concepts/build-process.mdx index ade4eb21..cd5069ac 100644 --- a/content/docs/concepts/build-process.mdx +++ b/content/docs/concepts/build-process.mdx @@ -1,53 +1,51 @@ --- title: Build Process description: | - Learn how Unikraft is generally organized and the steps that are performed by - Unikraft's build system which generate a unikernel. + Learn about Unikraft's general organization and the steps its build system + performs to generate a unikernel. --- -Unikraft is designed to build ultra-lightweight VM images. For that matter, the -build system is designed to take only the absolute necessary pieces of code and -bind them togheter. +Unikraft is designed to build ultra-lightweight VM images. For that matter, the +build system takes only the crucial pieces of code and binds them together. -The lifecycle of the construction of a Unikraft unikernel includes several -distinct steps: +The lifecycle of a Unikraft unikernel construction includes several distinct +steps: -1. Configuring the Unikraft unikernel application with compile-time options; +1. Configuring the compile-time options for the Unikraft unikernel application; 2. Fetching and preparing the source code for external libraries; -3. Compiling the libraries and the core Unikraft code; +3. Compiling the libraries and core Unikraft code; 4. Linking the final unikernel image. ## GNU Make-based build system -Unikraft is a configurable operating system, where each component can be -modified, configured, according to the user’s needs. This configuration is done -using a version of Kconfig, through the Config.uk files. In these files, options -are added to enable libraries, applications and different components of the -Unikraft core. The user can then apply those configuration options, using make -menuconfig, which generates an internal configuration file that can be -understood by the build system, .config. Once configured, the Unikraft image can -be built, using make, and run, using the appropriate method (Linux ELF loader, -qemu-kvm, xen, others). +Unikraft is a configurable operating system where we can tune each component to +our liking. To achieve this, Unikraft utilises a Kconfig-based configuration +system through `Config.uk` files. These files include options to enable +libraries, applications, and different components of the Unikraft core. We can +apply these configuration options using `make menuconfig` which generates an +internal configuration file (`.config`) understood by the build system. Once +configured, we can run `make` to build the Unikraft image and run it using any +method of our choice, i.e., Linux ELF loader, qemu-kvm, xen, etc. \ No newline at end of file +/> + From 1d883ed556683a24b47f586a5c40279dc3bd20cd Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 17 Mar 2024 09:10:39 +0530 Subject: [PATCH 2/4] docs/concepts: Improve grammar and fix typos for design principles --- content/docs/concepts/design-principles.mdx | 312 ++++++++++---------- 1 file changed, 155 insertions(+), 157 deletions(-) diff --git a/content/docs/concepts/design-principles.mdx b/content/docs/concepts/design-principles.mdx index 0cbfecd9..708f6ec4 100644 --- a/content/docs/concepts/design-principles.mdx +++ b/content/docs/concepts/design-principles.mdx @@ -1,209 +1,207 @@ --- title: Design Principles description: | - Unikraft is designed to highly modular, enabling the best-in-class performance - and security guarantees for your application. To discover the right approach - and achieve these goals, understanding the limitations modern OSes was - necessary. + Unikraft is highly modular and provides best-in-class performance and + security guarantees for your application. To discover the right approach + and achieve these goals, understanding the limitations modern operating + systems was necessary. --- -The problem we want to solve is to enable developers to create a specialized OS -for every single application to ensure the best performance possible, security -guarantees or desired target KPI. The requirement of enabling such high -modularity across multiple system boundaries has led to a number of key design -decisions: +We wanted to give developers the ability to create specialized operating systems +(OS) for every application to ensure the best-possible performance, security +guarantees, or desired target key performance indicator (KPI). The need to +enable such high modularity across multiple system boundaries has led to some +key design decisions: -* **Single address space**: Target single application scenarios, with possibly +- **Single address space**: Target single application scenarios with possibly different applications talking to each other through networked communications. - -* **Fully modular system**: All components, including operating system - primitives, drivers, platform code and libraries should be easy to add and - remove as needed; even APIs should be modular. - -* **Single protection level**: There should be no user-/kernel-space separation - to avoid costly processor mode switches. This does not preclude - compartmentalization (e.g., of micro-libraries), which can be achieved at - reasonable cost. - -* **Static linking**: Enable compiler features, e.g., Dead-Code Elimination and - Link-Time-Optimization (LTO), to automatically get rid of unneeded code. - -* **POSIX support**: In order to support existing or legacy - applications and programming languages while still allowing for +- **Fully modular system**: Make all components, including OS primitives, + drivers, platform code, and libraries, easy to add or remove as required. Even + the APIs should have modularity. +- **Single protection level**: Do away with user-/kernel-space separation to + avoid costly processor mode switches, while still allowing + compartmentalization (e.g., of micro-libraries) at a reasonable cost. +- **Static linking**: Enable compiler features such as dead code elimination and + link time optimization (LTO) to automatically get rid of unneeded code. +- **POSIX support**: Have POSIX support built-in to cater to existing or legacy + applications and programming languages, while still allowing for specialization under that API. +- **Platform abstraction**: Effortlessly generate images for a variety of + hypervisors and virtual machine managers (VMMs). -* **Platform abstraction**: Seamless generation of images for a range of - different hypervisors/VMMs. +## Problems with Monolithic OSs +To derive Unikraft's core design principles, it makes sense to analyze the +features and (heavyweight) mechanisms of traditional OSs that do not fit in +single application use cases: -## Problems with Monolithic OSes - -To derive the core design principles of Unikraft, it is worth analyzing the -features and (heavyweight) mechanisms of traditional OSes that are unnecessary -or ill-suited to single application use cases: - -* Protection-domain switches between the application and the kernel might be - redundant in a virtualization context because isolation is ensured by the - hypervisor, and result in measurable performance degradation. - -* Multiple address spaces may be useless in a single application domain, but - removing such support in standard OSes requires a massive reimplementation +- Protection-domain switches between the application and the kernel might be + redundant in a virtualization context because the hypervisor ensures isolation + and this could result in measurable performance degradation. +- Multiple address spaces may be useless in a single application domain, but + removing such support in standard OSs requires a massive reimplementation effort. - -* For RPC-style server applications, threading is not needed, with a single, - run-to-completion event loop sufficing for high performance. This would remove - the need for a scheduler within the VM and its associated overheads, as well - as the mismatch between the guest and hypervisor schedulers. - -* For performance-oriented UDP-based apps, much of the OS networking stack is - useless: the app could simply use the driver API, much like DPDK-style - applications already do. There is currently no way to easily remove just the - network stack but not the entire network sub-system from standard OSes. - -* Direct access to NVMe storage from apps removes the need for file descriptors, - a VFS layer and a filesystem, but removing such support from existing OSes, - built around layers of the storage API, is very difficult. - -* Memory allocators have a large impact on application performance, and general - purpose allocators have been shown to be suboptimal for many apps. It would - therefore be ideal if each app could choose its own allocator; this is however - very difficult to do in today's operating systems because the allocators that - kernels use are baked in. +- RPC-style server applications do not require threading as a single + run-to-completion event loop suffices for high performance. This removes the + need for a scheduler within the VM, its associated overheads, as well as the + mismatch between the guest and hypervisor schedulers. +- Performance-oriented UDP-based applications utilise only a part of the OS + networking stack. They could simply use the driver API like any other + [DPDK][dpdk]-style application. At the time of writing, stardard OSs do not + provide a way to remove the network stack alone without removing the entire + network sub-system. +- Direct access to NVMe storage from applications removes the need for file + descriptors, a virtual filesystem layer, and a filesystem. But removing such + support from existing OSs, built around layers of the storage API, is + challenging. +- Memory allocators heavily impact application performance, and research has + demonstrated general-purpose allocators to be suboptimal for many + applications. Thus, ideally, an application should have the ability to choose + its own allocator. But this is challenging to do in today's OSs as the kernels + come with built-in allocators. This admittedly non-exhaustive list of application-specific optimizations implies that for each core functionality that a standard OS provides, there -exists at least one or a few applications that do not need it. Removing such +exist at least one or more applications that do not need it. Removing such functionality would reduce code size and resource usage but would often require an important re-engineering effort. - ## Approaches to building a unikernel Given these design decisions, the question thus stems of how to implement such a -system, either: by minimizing an existing general-purpose OS; by starting from -an existing unikernel project; or, starting from scratch. Existing work has -taken three directions in tackling this problem. +system. Existing work has taken three directions in tackling this problem: +- Minimizing an existing general-purpose OS +- Bypassing the OS +- Starting from scratch ### Minimizing an existing general-purpose OS -The first direction takes existing OSes and adds or removes functionality. Key -examples add support for a single address space and remove protection domain -crossings: [OSv](#) and [RUMP Kernel](#) which adopt parts of [the BSD -kernel](#) and re-engineer it to work in a unikernel context. [Lupine Linux](#) -relies on a minimal, specialized configuration of the Linux kernel with [Kernel -Mode Linux (KML) patches](#). +This approach takes existing OSs and adds or removes functionality. Key examples +that add support for a single address space and remove protection domain +crossings include: -These approaches make application porting easy because they provide binary -compatibility or POSIX compatibility, but the resulting kernel is monolithic. +- [OSv][osv] and [rumpkernel][rump] which adopt parts of [the NetBSD + kernel][netbsd] and re-engineer it to work in a unikernel context. +- [Lupine Linux][lupine] which relies on a minimal, specialized configuration of + the Linux kernel via the [Kernel Mode Linux (KML) patch][kml-patch]. -Existing monolithic OSes do have APIs for each component, but most APIs are -quite rich as they have evolved organically, and component separation is often -blurred to achieve performance (e.g., sendfile short circuits the networking and -storage stacks). The Linux kernel, for instance, [historically featured highly -inter-dependent subsystems](https://dl.acm.org/doi/10.1145/302405.302691). +These approaches ease application porting because they provide binary or POSIX +compatibility but they result in a monolithic kernel. + +Existing monolithic OSs do have APIs for each component but these APIs have +become quite rich as they have evolved organically. These OSs often blur +component separation to achieve performance (e.g., [`sendfile`][sendfile] short +circuits the networking and storage stacks). The Linux kernel, for instance, has +[historically featured highly inter-dependent subsystems](https://dl.acm.org/doi/10.1145/302405.302691). To better quantify this API complexity, we analyzed dependencies between the main components of the Linux kernel. As a rough approximation, we used the subdirectories in the kernel source tree to identify (broad) components. [We used `cscope` to extract all function calls from the sources of all kernel -components](https://github.com/unikraft/eurosys21-artifacts/tree/master/experiments/fig_01_linux-deps), -and then for each call checked to see if the function is defined in the same -component or a different one; in the latter case, we recorded a dependency. We -plot the dependency graph in Figure 1, the annotations on the edges show the -number of dependencies between nodes. This dense graph makes it obvious that -removing or replacing any single component in the Linux kernel requires -understanding and fixing all the dependencies of other components, a daunting -task. +components][linux-deps-exp]. For each function call, we checked if the function +definition existed in the same component or a different one. In the latter case, +we recorded a dependency. We plot the dependency graph in Figure 1 where the +annotations on the edges show the number of dependencies between nodes. This +dense graph makes it obvious that removing or replacing any single component in +the Linux kernel requires understanding and fixing all the dependencies of other +components, a daunting task indeed. -While full modularization is difficult, modularizing certain parts of a -monolithic kernel has been done succesfully by Rump. There, the NetBSD kernel -was split into base layers (which must be used by all kernels), functions -provided by the host (scheduling, memory allocation,etc) and so-called factions -that can be run on their own (e.g. network or filesystem support). Rump goes -some way towards achieving our goals, however there are still many dependencies -left which require that all kernels have the base and hypercall layers. -Additionally, the dependencies on the host are limiting in the context of a VM, -which is our target deployment. - +While full modularization is difficult, rumpkernel has modularized certain parts +of a monolithic kernel. They split the NetBSD kernel into base layers (used by +all kernels), functions provided by the host (scheduling, memory allocation, +etc.), and independently executable "factions" (e.g., network or filesystem +support). rumpkernel goes some way towards achieving our goals. Still, many +dependencies remain that require the kernel to have the base and hypercall +layers. In the context of a VM, which is our deployment target, this limits the +extent of modularity that we can achieve. -### By-passing the OS - -The second direction is to bypass the OS altogether, mostly for I/O performance, -while leaving the original stack in place -- wasting resources in the process. -Even here, porting effort is required as apps must be coded against the new -network ([DPDK](https://www.dpdk.org/), -[Netmap](https://github.com/luigirizzo/netmap) or [Linux's `io_uring` -subsystem](https://unixism.net/loti/what_is_io_uring.html)) or storage (SPDK) -API. +### Bypassing the OS +This involves bypassing the OS altogether, mostly for I/O performance, while +leaving the original stack in place -- wasting resources in the process. Even +this approach requires porting effort as applications must conform to the new +network (DPDK, [netmap] or [Linux's `io_uring` subsystem][linux-io-uring]) or +storage ([SPDK][spdk]) APIs. ### Starting from scratch -The third direction is to add the required OS functionality from scratch for -each target application, possibly by reusing code from existing operating -systems. This is the approach taken by -[ClickOS](https://github.com/sysml/clickos) to support [Click modular -routers](https://github.com/kohler/click), [MirageOS](https://mirage.io/) to -support OCaml applications, and [MiniCache](#) to implement a web cache, to name -a few. The resulting images are very lean, have great performance and have -small boot times; the big problem is that the porting effort is huge, and that -it has to be mostly repeated for every single application or language. - -In sum, starting from an existing project is suboptimal since none of the -projects in the three directions mentioned were designed to support the key -principles we have outlined. We opt for a clean-slate API design approach, -though we do reuse components from existing works where relevant. Course -borrowing parts of code from existing projects, where relevant, in order not to -reinvent the wheel (eg x86_64 KVM boot). +In this approach, we add the required OS functionality for each target +application from scratch, possibly reusing code from existing OSs. Many projects +utilise this approach. For example, [ClickOS][clickos] uses it in their [modular +routers][click-routers], [MirageOS][mirage-os] uses it to support OCaml +applications, and [MiniCache][minicache] uses it for implementing a web cache. +This results in lean and performant images that have small boot times. But, it +demands huge porting efforts per application and repeating this for every +application or language becomes problematic. +To summarize, starting from an existing project is suboptimal since none of the +projects mentioned above conform to the key principles we have outlined. We opt +for a clean-slate API design approach. Though, we do reuse components from +existing works when relevant (e.g., x86_64 KVM boot). -## Unikraft's approach +## Our approach Unikraft consists of three basic components: -* **Library Components.** Unikraft modules TODO, each of which provides some - piece of functionality. As is expected of a library, they are the core - building blocks of an application. Libraries can be arbitrarily small (e.g., a - small library providing a proof-of-concept scheduler) or as large as standard - libraries like libc. However, libraries in Unikraft often wrap pre-existing - libraries, such as openssl, and as such existing applications can still make - use of relevant, existing systems without having to re-work anything. - -* **Configuration.** Inspired by [Linux's KConfig - system](https://www.kernel.org/doc/html/next/kbuild/kconfig-language.html), - Unikraft uses this approach to quickly and easily allow users to pick and - choose which libraries to include in the build process, as well as to - configure options for each of them, where available. Like KConfig, the menu - keeps track of dependencies and automatically selects them where applicable. - -* **Build Tools.** To seamlessly build and manage Unikraft, its components, - configuration and its execution is a suite of tools ... core of Unikraft is a - suite of tools which aid in the creation of the final unikernel image. Based - on [GNU Make](https://www.gnu.org/software/make/), it takes care of compiling - and linking all the relevant modules and of producing images for the different - platforms selected via the configuration menu. - - -Unikraft libraries are grouped into two large groups: core (or internal) -libraries, and external libraries. Core libraries generally provide -functionality typically found in operating systems. Such libraries are grouped -into categories such as memory allocators, schedulers, filesystems, network -stacks and drivers, among others. Core libraries are part of the main Unikraft -repo which also contains the build tool and configuration menu. +- **Libraries**: Unikraft consists of multiple modules, called (micro)libraries. + They form the core building blocks of an application. They can be arbitrarily + small (e.g., a proof-of-concept scheduler) or as large as standard libraries + like `libc`. Still, libraries in Unikraft often wrap pre-existing libraries + like `openssl`. This enables existing applications to make use of relevant, + existing systems without having to re-work anything. +- **Configuration**: Unikraft employs a configuration system inspired by Linux's + [KConfig][linux-kconfig]. It allows users to pick which libraries to include + in the builds and provides an interface to configure their options in a + hassle-free manner. Like KConfig, the menu keeps track of dependencies and + automatically selects them where applicable. +- **Build tools**: At its core, Unikraft contains a suite of tools that aid in + the creation of the final unikernel image. This suite helps seamlessly build + and manage Unikraft, its components, configuration, and its execution. Based + on [GNU Make][gnu-make], it takes care of compiling and linking all the + relevant modules and producing images for the different platforms selected via + the configuration menu. + +Unikraft groups libraries into two classes: core (or internal) libraries and +external libraries. Core libraries generally provide functionality typically +found in operating systems. Such libraries fall into categories such as memory +allocators, schedulers, filesystems, network stacks, and drivers, among others. +The main Unikraft repository houses these libraries, alongwith the build tool +and configuration. External libraries consist of existing code not specifically meant for Unikraft. -This includes standard libraries such as libc or openssl, but also run-times +This includes standard libraries such as `libc` or `openssl`, but also runtimes like Python. -Whether core or external, from a user’s perspective these are indistinguishable: they simply show up as libraries in the menu. +To the user, the distinction between core and external libraries is irrelevant +as the configuration menu does not classify them. + +[osv]: https://osv.io/ +[rump]: https://wiki.netbsd.org/rumpkernel/ +[netbsd]: https://www.netbsd.org/docs/kernel/ +[lupine]: https://github.com/hckuo2/Lupine-Linux +[kml-patch]: https://github.com/hckuo2/Lupine-Linux/blob/master/kml_4.0_001.diff +[sendfile]: https://man7.org/linux/man-pages/man2/sendfile.2.html +[dpdk]: https://www.dpdk.org/ +[netmap]: https://github.com/luigirizzo/netmap +[linux-io-uring]: https://unixism.net/loti/what_is_io_uring.html +[spdk]: https://spdk.io/doc/ +[linux-kconfig]: + https://www.kernel.org/doc/html/next/kbuild/kconfig-language.html +[clickos]: https://github.com/sysml/clickos +[click-routers]: https://github.com/kohler/click +[mirage-os]: https://mirage.io/ +[minicache]: https://github.com/sysml/minicache +[gnu-make]: https://www.gnu.org/software/make/ +[linux-deps-exp]: + https://github.com/unikraft/eurosys21-artifacts/tree/master/experiments/fig_01_linux-deps From 61276be88c28d3ca6c9780bd9e6d990a2d927978 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 17 Mar 2024 09:10:59 +0530 Subject: [PATCH 3/4] docs/concepts: Improve grammar and fix typos for virtualization --- content/docs/concepts/virtualization.mdx | 138 ++++++++++++----------- 1 file changed, 72 insertions(+), 66 deletions(-) diff --git a/content/docs/concepts/virtualization.mdx b/content/docs/concepts/virtualization.mdx index 2d15f04a..664455f8 100644 --- a/content/docs/concepts/virtualization.mdx +++ b/content/docs/concepts/virtualization.mdx @@ -1,89 +1,95 @@ --- title: Virtualization description: | - Through virtualization, multiple operating systems (OSes) are able to run on - the same hardware, independently, thinking that each one of them controls the - entire system. + Through virtualization, the same hardware can run multiple operating systems + independently, making them think that each one of them controls the + entire system. --- -Virtualization can be done using a hypervisor, which is a low-level software -that virtualizes the underlying hardware and manages access to the real -hardware, either directly or through the host Operating System. There are 2 main -virtualized environments: virtual machines and containers, each with pros and -cons regarding complexity, size, performance and security. Unikernels come -somewhere between those 2. +Virtualization requires a hypervisor which is a low-level software that +virtualizes the underlying hardware and manages access to the real hardware, +either directly or through the host operating system (OS). Virtual machines +(VMs) and containers form the two main virtualized environments. Both have their +trade-offs based on complexity, size, performance, and security. Unikernels fall +somewhere between the two. -## Virtual Machines +## Virtual machines -A virtual machine represents an abstraction of the hardware, over which an -operating system can run, thinking that it is alone on the system and that it -controls the hardware below it. Virtual machines rely on hypervisors to run -properly. +A VM represents an abstraction of the hardware on which an OS can run. The VM +tricks the OS into thinking that it alone has access to the system and that it +can control the underlying hardware. To achieve this, VMs rely on hypervisors +that run on the host. A hypervisor incorporates hardware-enabled multiplexing and segmentation of -compute resources in order to better utilize, better secure and better -facilitate the instantenous runtime of user-defined programs. By the -means of a virtual machine, an operating system is unaware of the multiplexing -which happens to facilitate its existence. The hypervisor emulates devices on -behalf of the guest OS, including providing access to virtual CPUs, virtual -Interrupt Controllers and virtual NICs, which are segmented from the underlying -hardware. - -The hypervisors can be classified in 2 categories: Type 1 and Type 2: - -* The **Type 1 hypervisor**, also known as **bare-metal hypervisor**, has direct - access to the hardware and controls all the operating systems that are running - on the system. The guest OSes have access to the physical hardware, and the - hypervisor arbiters this accesses. KVM is an example of Type 1 hypervisor. - -* The **Type 2 hypervisor**, also known as **hosted hypervisor**, has to go - through the host operating system to reach the hardware. Access to the - hardware is emulated, using software components that behave in the same way - as the hardware ones. An example of Type 2 hypervisor is VirtualBox. +compute resources to use, secure, and ease the instantaneous runtime of +user-defined programs in a better manner. Inside the VM, the OS does not get to +know of the multiplexing which brings about its existence. The hypervisor +emulates devices by on behalf of the guest OS by segmenting them from the +underlying hardware. These devices include virtual CPUs, interrupt controllers +and network interface cards (NICs), etc. + +Hypervisors generally fall into the following categories: + +- **Type 1**: Also known as **bare-metal hypervisors**, these hypervisors have + direct access to the hardware and control all the OSs that run on the host. + The guest OSs have access to the physical hardware and the hypervisor + arbitrates this access. + + Example: [Kernel Virtual Machine (KVM)][kvm] + +- **Type 2**: Also known as **hosted hypervisors**, these hypervisors have to go + through the host operating system to reach the hardware. They emulate hardware + access using software components that behave like their hardware counterparts. + + Example: [VirtualBox][virtualbox] -In Figure 1 a comparison between different virtualization systems is illustrated -and demonstrates how the degree of separation between a "guest application" and -the hardware and “host” becomes further removed. The defined job of the host OS -and kernel or hypervisor became that of 1). to juggle the runtime of multiple -applications and environments; 2). to present a subset or non-contiguous -representation of hardware resources virtually and translate operations, and -provide emulation and compatibility between guest and host; and, 3). to -ultimately guard access to them to prevent corruption or malicious attacks. +Figure 1 demonstrates how the degree of separation between a guest application, +the host OS, and the hardware becomes further removed as we go from (c) to (a). +The sole job of the host OS and kernel or hypervisor becomes that of: +- juggling multiple application runtimes and environments. +- presenting a subset or non-contiguous representation of hardware resources + virtually, translating operations, and providing emulation and compatibility + between the guest and the host. +- ultimately guarding access to them to prevent corruption or malicious attacks. ## Supported platforms -Unikraft is usually run in 2 ways: +We can run Unikraft images in the following ways: -* As a virtual machine, using [**QEMU-KVM**](/docs/operations/plats/kvm/) or - [**Xen**](/docs/operations/plats/xen/). It acts as an operating system, having +- Inside a VM using [QEMU-KVM][qemu-kvm] or [Xen][xen]: It acts as an OS, having the responsibility to configure the hardware components that it needs (clocks, - additional processors, etc). This mode gives Unikraft direct and total control - over hardware components, allowing advanced functionalities. -* As a [**linuxu**](/docs/operations/plats/linuxu/) build, in which it behaves - as a Linux user-space application. This severely limits its performance, as - everything Unikraft does must go through the Linux kernel, via system calls. - This mode should be used only for development and debugging. - -When Unikraft is running using **QEMU-KVM**, it can either be run on an emulated -system or a (para)virtualized one. Technically, **KVM** means virtualization -support is enabled. If using **QEMU** in emulated mode, **KVM** is not used. - -Emulation is slower, but it allows using CPU architectures different from the -local one (you can run ARM code on a x86 machine). Using (para)virtualisation, -aka hardware acceleration, greater speed is achieved and more hardware -components are visible to Unikraft. - + more processors, etc.). This mode gives Unikraft direct and total control over + hardware components, allowing advanced functionalities. +- As a [linuxu][linuxu] build: It behaves as a Linux user-space application. + This severely limits its performance, as everything Unikraft does must go + through the Linux kernel, via system calls. We recommend using this for + development alone. + +Unikraft supports both (para-)virtualized and emulated modes of QEMU. +Virtualized mode uses KVM while emulated mode does not. Using +(para-)virtualization, or hardware acceleration, yields greater performance and +allows Unikraft to see more hardware components. Emulation performs slower, but +allows using CPU architectures different from the host (e.g., we can run ARM +code on an x86 machine). ## Future virtualization support -Unikraft is planned to be able to run on **Hyper-V** and **VMWare**, in the near -future. +We plan to support running Unikraft on [Hyper-V][hyper-v] and [VMWare][vmware]. + +[kvm]: https://linux-kvm.org/page/Main_Page +[virtualbox]: https://www.virtualbox.org/ +[qemu-kvm]: /docs/operations/plats/kvm/ +[xen]: /docs/operations/plats/xen/ +[linuxu]: /docs/operations/plats/linuxu/ +[hyper-v]: + https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/hyper-v-technology-overview +[vmware]: https://www.vmware.com/ From 52cedd4235a6823cc510ebdb6de792163e3b4bb4 Mon Sep 17 00:00:00 2001 From: Utkarsh Verma Date: Sun, 17 Mar 2024 09:11:33 +0530 Subject: [PATCH 4/4] guides: Add podman instructions to buildkit guide --- ...ilding-dockerfile-images-with-buildkit.mdx | 65 ++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/content/guides/building-dockerfile-images-with-buildkit.mdx b/content/guides/building-dockerfile-images-with-buildkit.mdx index 9550268e..41bb532d 100644 --- a/content/guides/building-dockerfile-images-with-buildkit.mdx +++ b/content/guides/building-dockerfile-images-with-buildkit.mdx @@ -2,39 +2,72 @@ title: Building Dockerfile Images with Buildkit description: | - This guide shows how to install buildkit to allow you to build Dockerfile images with Unikraft. + This guide shows how to install Buildkit for building Dockerfile images with + Unikraft. --- -Unikraft uses [BuildKit](https://docs.docker.com/build/buildkit/), along with [Dockerfiles](https://docs.docker.com/reference/dockerfile/), to construct the root filesystem used by applications. +Unikraft uses [BuildKit][buildkit], along with [Dockerfiles][dockerfiles], to +construct the root filesystem used by applications. -You can install BuildKit by either running it natively via systemd or in a container. -Please refer to [BuildKit's installation instructions](https://github.com/moby/buildkit) for more information. +We can install BuildKit either by running it natively via `systemd` or inside a +container. Please refer to [BuildKit's installation +instructions][buildkit-installation] for more information. For convenience, we +recommend running it inside a container. -To use BuildKit with Docker on your system, you first need to install Docker following the [official instructions](https://docs.docker.com/engine/install/). -This can be either [Docker Engine](https://docs.docker.com/engine/) or [Docker Desktop](https://docs.docker.com/desktop/). +We will also need a [container engine][container-engine] on our host. Popular +choices include [Docker][docker], [podman], and [containerd]. Please follow +their respective documentation to get them up and running. For the rest of this +article, we will assume Docker to be the installed container engine. -After installing Docker, you can run BuildKit in a container via: +After installing the container engine, we can go ahead and run BuildKit. ```bash docker run -d --name buildkitd --privileged moby/buildkit:latest ``` -Now instruct `kraft` to use the BuildKit instance from the `buildkitd` container by either setting the environmental variable: +We can check if the container launched by doing: ```bash -export KRAFTKIT_BUILDKIT_HOST=docker-container://buildkitd +$ docker container ps | grep buildkitd ``` -Or edit KraftKit's configuration file at `~/.config/kraftkit/config.yaml` and set the `buildkit_host` attribute. - -To check that it worked you can run the following command: - ```bash -docker container ps | grep buildkit +b146031cd4db moby/buildkit:latest "buildkitd" About a minute ago Up About a minute buildkit ``` -You should see output similar to: +Now, we instruct `kraft` to use the BuildKit instance we launched. We can do it +in the following ways: + +- `KRAFTKIT_BUILDKIT_HOST` environment variable: + ```bash + export KRAFTKIT_BUILDKIT_HOST=docker-container://buildkitd + ``` +- KraftKit's configuration file (`~/.config/kraftkit/config.yaml`): + ```yaml + buildkit_host: docker-container://buildkitd + ``` +- Passing the `--buildkit-host` CLI flag to `kraft`: + ```bash + kraft --buildkit-host=docker-container://buildkitd + ``` + +> A container's URI depends on its name and the container engine. For example, a +> container managed by `podman` will have `podman-container://buildkitd` as its +> URI. + +Since we gave a name to our container, we can use the `start` and `stop` +subcommands to spawn/stop our BuildKit instance on demand. ```bash -b146031cd4db moby/buildkit:latest "buildkitd" About a minute ago Up About a minute buildkit +docker stop buildkitd # Start the container +docker start buildkitd # Stop the container ``` + +[buildkit]: https://docs.docker.com/build/buildkit/ +[Dockerfiles]: https://docs.docker.com/reference/dockerfile/ +[buildkit-installation]: https://github.com/moby/buildkit +[container-engine]: + https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction#h.6yt1ex5wfo3l +[docker]: https://www.docker.com/ +[podman]: https://docs.podman.io/en/latest/ +[containerd]: https://containerd.io/