Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/contributors.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
users:
Akarshkushwaha:
name: Akarsh Kushwaha
email: akarshkushwaha593@gmail.com
kastakhov:
name: Kostiantyn Astakhov
email: me@lvfrfn.in.ua
Expand Down
73 changes: 42 additions & 31 deletions docs/package/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,23 @@ allowing us to create OCI images from any type of file. Currently [bunny](https:
process two formats of files: a) the typical Dockerfile-like syntax files and b)
`bunnyfile`, a specialized YAML-based file.

When using Dockerfile-like files, [bunny](https://github.com/nubificus/bunny)
can only package pre-built unikernel images; it cannot build them. This format
is primarily retained for compatibility with pun and bima, which are no longer
maintained. Currently, [bunny](https://github.com/nubificus/bunny)
can handle the following *instructions*:

- `FROM`: Specify an existing OCI image to use as a base.
- `COPY`: this works as in Dockerfiles. At this moment, only a single copy
operation per *instruction* (think one copy per line). These files are copied
inside the container's image rootfs.
- `LABEL`: all LABEL *instructions* are added as annotations to the container's
image. They are also added to a special `urunc.json` inside the container's image
rootfs.

To further extend the functionality and provide a common interface to facilitate
unikernel building, we defined `bunnyfile`. It is a YAML-based special file that
[bunny](https://github.com/nubificus/bunny) transforms to LLB with all the
necessary steps to build the respective unikernel. Apart from building
unikernels, [bunny](https://github.com/nubificus/bunny) can also be used to build or append files in the unikernel's
rootfs.
Bunny supports standard Containerfile/Dockerfile syntax, including `RUN`,
`ENV`, `ENTRYPOINT`, `CMD`, multi-stage builds and `COPY --from=`. It adds
`urunc` annotations and a `urunc.json` file to the resulting OCI image.

For Containerfile input, bunny also supplies the following defaults:

- The guest is Linux over QEMU unless the corresponding `com.urunc.unikernel.*`
labels specify otherwise.
- If `com.urunc.unikernel.binary` is not set, bunny adds a kernel selected for
the configured monitor (QEMU, Firecracker or Cloud Hypervisor).
- For Linux guests, bunny copies `/urunit` into the image and prepends it to
the image's entrypoint. Set `LABEL bunny.urunit=false` to disable this when
providing your own init process.

The YAML-based `bunnyfile` provides explicit fields for the platform, kernel,
rootfs and application configuration. The automatic kernel and urunit defaults
above apply to Containerfile input; a bunnyfile specifies those files explicitly.

The current syntax of `bunnyfile` is the following one:

Expand All @@ -131,21 +128,35 @@ platforms: # [3] The target platform for bu
monitor: qemu # [3c] The hypervisor/VMM or any other kind of monitor.
architecture: x86 # [3d] The target architecture.

rootfs: # [4] (Optional) Specifies the rootfs of the unikernel.
from: local # [4a] (Optional) The source of the rootfs.
path: initrd # [4b] (Required if from is not scratch) The path in the source, where the prebuilt rootfs file resides.
type: initrd # [4c] (optional) The type of rootfs (e.g. initrd, raw, block)
include: # [4d] (Optional) A list of local files to include in the rootfs
- src:dst
rootfs: # [4] (Optional) Rootfs configuration.
from: scratch # [4a] scratch, local, or an OCI image reference.
type: initrd # [4b] initrd, block, or raw, subject to framework support.
include: # [4c] Files to copy into the rootfs.
- config.txt:/etc/app.conf # Local source:destination shorthand.
- from: nginx:alpine # Copy from another OCI image.
source: /usr/share/nginx/html/index.html
destination: /www/index.html

kernel: # [5] Specify a prebuilt kernel to use
from: local # [5a] Specify the source of a prebuilt kernel.
path: kernel # [5b] The path where the kernel image resides.
kernel: # [5] Prebuilt kernel configuration.
from: local # [5a] local or an OCI image reference.
path: kernel # [5b] Path to the kernel in that source.

cmdline: hello # [6] The cmdline of the app.
envs: # [6] Environment variables as KEY=VALUE strings.
- MESSAGE=hello
cmd: ["hello"] # [7] Application command/arguments, like CMD.
entrypoint: ["/app"] # [8] Entrypoint, like ENTRYPOINT.

```

For an existing rootfs file, use `rootfs.from: local` (or an OCI image
reference) and `rootfs.path` to select the file. The `include` shorthand copies
local files; the mapping form selects a source with `from`, `source` and
`destination`. Use `from: local` in that mapping for the local build context.

`cmd` and `entrypoint` are lists, so each argument is a separate item. `envs`
is a list of `KEY=VALUE` strings. The old `cmdline` string is accepted for
backward compatibility when `cmd` is empty; use `cmd` in new files.

For more information regarding the `bunnyfile` please take a look at the
respective section of [bunny's
README](https://github.com/nubificus/bunny?tab=readme-ov-file#the-bunnyfile).
Expand Down Expand Up @@ -215,7 +226,7 @@ kernel:
from: local
path: nginx-qemu-x86_64-initrd_qemu-x86_64

cmdline: nginx -c /nginx/conf/nginx.conf
cmd: ["nginx", "-c", "/nginx/conf/nginx.conf"]
```

and we can build it with a docker command:
Expand Down
2 changes: 1 addition & 1 deletion docs/package/pre-built.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ kernel:
from: local
path: network.hvt

cmdline: ""
cmd: []
```

In the above file we specify the following:
Expand Down
2 changes: 1 addition & 1 deletion docs/package/reuse.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ kernel:
from: unikraft.org/nginx:1.15
path: /unikraft/bin/kernel

cmdline: "nginx -c /nginx/conf/nginx.conf"
cmd: ["nginx", "-c", "/nginx/conf/nginx.conf"]
```

In the above file we specify the following:
Expand Down
22 changes: 15 additions & 7 deletions docs/package/rootfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,17 @@ Therefore, the users have the following options:
the unikernel.
2. Directly copy all the files to the container's rootfs and use devmapper
snapshotter or shared-fs to pass the container's rootfs to the unikernel.
3. Let [bunny](https://github.com/nubificus/bunny) and [bunix](https://github.com/nubificus/bunix) create the rootfs file.

> **NOTE**: For the time being, [bunny](https://github.com/nubificus/bunny) supports the creation of initrd files and [bunix](https://github.com/nubificus/bunix) does not provide any support for creating the rootfs.
3. Use [bunny](https://github.com/nubificus/bunny) to build a rootfs with a bunnyfile or a standard Containerfile.

Bunny supports `initrd`, `block` and `raw` rootfs types, depending on the guest
framework. An `initrd` is a CPIO archive; a `block` rootfs is a disk image;
`raw` copies files directly into the OCI image for shared-fs or a block-based
snapshotter. Bunny can create an initrd or assemble a raw rootfs from an
`include` list, including files from other OCI images. In a bunnyfile,
`type: block` packages an existing image selected by `rootfs.from` and
`rootfs.path`; it does not generate the filesystem. A standard Containerfile
can create a block filesystem using tools in a build stage.
Bunix packages existing files but does not create the rootfs.

## Creating an initrd file

Expand Down Expand Up @@ -63,7 +71,7 @@ kernel:
from: local
path: redis-qemu-x86_64-initrd_qemu-x86_64

cmdline: "redis-server /conf/redis.conf"
cmd: ["redis-server", "/conf/redis.conf"]
```

In the above file we specify the following:
Expand All @@ -72,7 +80,7 @@ In the above file we specify the following:
x86 architecture.
- We want to create from `scratch` a rootfs with `initrd` as its type. In
particular, we want an initrd file that contains the file `redis.conf` in
`/data/conf/redis.conf`. In that way, [bunny](https://github.com/nubificus/bunny) creates the initrd file for us
`/conf/redis.conf`. In that way, [bunny](https://github.com/nubificus/bunny) creates the initrd file for us
and sets up the respective `urunc` annotations to attach this initrd file
when we boot the unikernel.
- We want to use the `redis-qemu-x86_64-initrd_qemu-x86_64` binary from the local build context as the unikernel to boot.
Expand Down Expand Up @@ -137,7 +145,7 @@ kernel:
from: local
path: redis.hvt

cmdline: "redis-server /data/conf/redis.conf"
cmd: ["redis-server", "/data/conf/redis.conf"]
```

In the above file we specify the following:
Expand Down Expand Up @@ -282,7 +290,7 @@ kernel:
from: local
path: app-elfloader-qemu-x86_64-initrd_qemu-x86_64

cmdline: "/chttp"
cmd: ["/chttp"]
```

In the above file we specify the following:
Expand Down
124 changes: 54 additions & 70 deletions docs/tutorials/existing-container-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,28 @@ In this case preparing the container image involves two key steps:
1. Append the Linux kernel binary to the container image.
2. Set the appropriate `urunc` annotations.

These tasks can be easily automated with [bunny](https://github.com/nubificus/bunny).
Bunny's Containerfile frontend performs these steps automatically and also
adds urunit. For example, save this as `Containerfile`:

Let's use as an example the `redis:alpine` container image using the Linux
kernel from `harbor.nbfc.io/nubificus/urunc/linux-kernel-qemu:v6.14`. The
respective `bunnyfile` would look like:
```Dockerfile
#syntax=harbor.nbfc.io/nubificus/bunny:latest
FROM redis:alpine
```

Bunny defaults to Linux over QEMU, selects a kernel, copies `/urunit` into the
image and prepends it to the existing entrypoint. The base image's `CMD` is
preserved, so Redis does not need a manual urunit wrapper. Build it with:

```bash
docker build -f Containerfile -t redis/apline/linux/qemu:latest .
```

To select a different monitor, set the `com.urunc.unikernel.hypervisor` label.
To supply a kernel yourself, copy it into the image and set
`com.urunc.unikernel.binary`. Set `LABEL bunny.urunit=false` only when providing
your own init process.

Alternatively, a bunnyfile makes the kernel and init setup explicit:

```yaml
#syntax=harbor.nbfc.io/nubificus/bunny:latest
Expand All @@ -176,59 +193,29 @@ platforms:
rootfs:
from: redis:alpine
type: raw
include:
- from: harbor.nbfc.io/nubificus/urunit:latest
source: /urunit
destination: /urunit

kernel:
from: harbor.nbfc.io/nubificus/urunc/linux-kernel-qemu:v6.14
path: /kernel

cmdline: "/usr/local/bin/redis-server"
entrypoint: ["/urunit"]
cmd: ["/usr/local/bin/redis-server"]
```

We can build the container with:
Unlike the Containerfile frontend, the bunnyfile does not add urunit
automatically. Its `include` mapping copies the binary directly from its OCI
image. Build with:

```bash
docker build -f bunnyfile -t redis/apline/linux/qemu:latest .
```

Alternatively, if the Linux kernel was built locally, we can update the kernel
section of the bunnyfile to reference the local binary:

```yaml
kernel:
from: local
path: bzImage
```

By default, this setup will run redis-server as the init process. To include
[urunit](https://github.com/nubificus/urunit) in the redis:alpine image, we can
use the following Containerfile:

```
FROM harbor.nbfc.io/nubificus/urunit:latest AS init

FROM redis:alpine

COPY --from=init /urunit /urunit
```

> **NOTE**: We are working towards enabling the addition of extra files from the
> `bunnyfile`. We will update this page once this feature is supported.

After building the above container, make sure to specify it in the `from` field
of rootfs in `bunnyfile`:

```yaml
rootfs:
from: redis/urunit:alpine
type: raw
```

At last we need to modify the `cmdline` section of `bunnyfile` to execute
[urunit](https://github.com/nubificus/urunit):

```yaml
cmdline: "/urunit /usr/local/bin/redis-server"
```
To use a locally built kernel instead, set `kernel.from: local` and
`kernel.path: bzImage`.

#### Running the container

Expand Down Expand Up @@ -318,16 +305,22 @@ just to demonstrate how to manually define the required annotations for `urunc`:
FROM scratch

COPY vmlinux /kernel
COPY nginx_rootfs.ext2 /rootfs.ext2
COPY rootfs.ext2 /rootfs.ext2

LABEL "com.urunc.unikernel.binary"="/kernel"
LABEL "com.urunc.unikernel.unikernelType"="linux"
LABEL "com.urunc.unikernel.block"="/rootfs.ext2"
LABEL "com.urunc.unikernel.blkMntPoint"="/"
LABEL "com.urunc.unikernel.hypervisor"="firecracker"
CMD ["/urunit", "/usr/sbin/nginx", "-g", "daemon off;error_log stderr debug;"]
LABEL bunny.urunit=false
ENTRYPOINT ["/urunit"]
CMD ["/usr/sbin/nginx", "-g", "daemon off;error_log stderr debug;"]
```

Here `/urunit` is already inside the block image, so `bunny.urunit=false`
prevents the frontend from adding another copy and prepending it again. The
entrypoint selects the init process inside the guest's block rootfs.

We can build the container with:

```bash
Expand Down Expand Up @@ -387,27 +380,11 @@ image to use as the root filesystem. To demonstrate this, we will use the

#### Preparing the container image.

First let's create the initrd:

```bash
mkdir tmp_rootfs
docker export $(docker create traefik/whoami) | tar -C tmp_rootfs/ -xvf -
wget -O tmp_rootfs/urunit https://github.com/nubificus/urunit/releases/download/v0.1.0/urunit_x86_64 # If we want urunit as init
chmod +x tmp_rootfs/urunit
cd tmp_rootfs
find . | cpio -H newc -o > ../rootfs.initrd
```

> **NOTE**: We are working towards enabling the creation of the initrd directly
> from [bunny](https://github.com/nubificus/bunny). We will update this page
> once this feature is supported.

Now we have an initrd `rootfs.initrd` generated from `traefik/whoami` and with
[urunit](https://github.com/nubificus/urunit) that we got from its [latest
release](https://github.com/nubificus/urunit/releases/tag/v0.1.0). In order to
pack everything together, we can use the following `bunnyfile`:
Bunny can create the initrd directly from an include list. Copy the
application's rootfs and urunit from their OCI images, then select urunit as
the entrypoint:

```
```yaml
#syntax=harbor.nbfc.io/nubificus/bunny:latest
version: v0.1

Expand All @@ -417,15 +394,22 @@ platforms:
architecture: x86

rootfs:
from: local
from: scratch
type: initrd
path: rootfs.initrd
include:
- from: traefik/whoami:latest
source: /
destination: /
- from: harbor.nbfc.io/nubificus/urunit:latest
source: /urunit
destination: /urunit

kernel:
from: harbor.nbfc.io/nubificus/urunc/linux-kernel-firecracker:v6.14
path: /kernel

cmdline: "/urunit /whoami"
entrypoint: ["/urunit"]
cmd: ["/whoami"]
```

We can build the container with:
Expand Down