diff --git a/.github/contributors.yaml b/.github/contributors.yaml index ee3ba7e4a..14024fca5 100644 --- a/.github/contributors.yaml +++ b/.github/contributors.yaml @@ -1,4 +1,7 @@ users: + Akarshkushwaha: + name: Akarsh Kushwaha + email: akarshkushwaha593@gmail.com kastakhov: name: Kostiantyn Astakhov email: me@lvfrfn.in.ua diff --git a/docs/package/index.md b/docs/package/index.md index cafba952f..9d4f5d3b8 100644 --- a/docs/package/index.md +++ b/docs/package/index.md @@ -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: @@ -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). @@ -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: diff --git a/docs/package/pre-built.md b/docs/package/pre-built.md index 582c14881..0ea69d84e 100644 --- a/docs/package/pre-built.md +++ b/docs/package/pre-built.md @@ -43,7 +43,7 @@ kernel: from: local path: network.hvt -cmdline: "" +cmd: [] ``` In the above file we specify the following: diff --git a/docs/package/reuse.md b/docs/package/reuse.md index 4d678c1ec..9b270d766 100644 --- a/docs/package/reuse.md +++ b/docs/package/reuse.md @@ -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: diff --git a/docs/package/rootfs.md b/docs/package/rootfs.md index 08689ef78..9bfdadf92 100644 --- a/docs/package/rootfs.md +++ b/docs/package/rootfs.md @@ -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 @@ -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: @@ -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. @@ -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: @@ -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: diff --git a/docs/tutorials/existing-container-linux.md b/docs/tutorials/existing-container-linux.md index 0dde898de..62f276be2 100644 --- a/docs/tutorials/existing-container-linux.md +++ b/docs/tutorials/existing-container-linux.md @@ -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 @@ -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 @@ -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 @@ -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 @@ -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: