diff --git a/.gitignore b/.gitignore
index cdded28..5e01b1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
+/out
/target
-/bin/
-/targets/
diff --git a/Makefile b/Makefile
index bdd884b..aad0aeb 100644
--- a/Makefile
+++ b/Makefile
@@ -7,30 +7,35 @@ CARGO ?= cargo
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
binpath := $(DESTDIR)/$(PREFIX)/bin/crun-vm
+manpath := $(DESTDIR)/$(PREFIX)/share/man/man1/crun-vm.1.gz
-.PHONY: build
-build:
+all: out/crun-vm out/crun-vm.1.gz
+
+.PHONY: out/crun-vm
+out/crun-vm:
+ mkdir -p $(@D)
$(CARGO) build --release
- mkdir -p bin
- cp target/release/crun-vm bin/crun-vm
+ cp target/release/crun-vm $@
-.PHONY: build-debug
-build-debug:
- $(CARGO) build
- mkdir -p bin
- cp target/debug/crun-vm bin/crun-vm.debug
+out/crun-vm.1.gz: docs/5-crun-vm.1.ronn
+ mkdir -p $(@D)
+ ronn --pipe --roff $< | gzip > $@
.PHONY: clean
clean:
- rm -fr bin target
+ rm -fr out target
.PHONY: install
-install: build
- install ${SELINUXOPT} -D -m 0755 bin/crun-vm $(binpath)
+install: out/crun-vm install-man
+ install ${SELINUXOPT} -D -m 0755 $< $(binpath)
+
+.PHONY: install-man
+install-man: out/crun-vm.1.gz
+ install ${SELINUXOPT} -D -m 0644 $< $(manpath)
.PHONY: uninstall
uninstall:
- rm -f $(binpath)
+ rm -f $(binpath) $(manpath)
.PHONY: lint
lint:
diff --git a/README.md b/README.md
index d384514..1d596b2 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,107 @@
# The crun-vm OCI Runtime
**crun-vm** is an [OCI Runtime] that enables [Podman], [Docker], and
-[Kubernetes] to run QEMU-compatible Virtual Machine (VM) images.
+[Kubernetes] to run QEMU-compatible Virtual Machine (VM) images. This means you
+can:
-- Run **VMs** as easily as you run **containers**.
-- Manage containers and VMs **together** using the **same** standard tooling.
-- **No need** for in-depth knowledge on virtualization technologies like libvirt
- or KubeVirt.
+ - Run **VMs** as easily as you run **containers**.
+ - Manage containers and VMs **together** using the **same** standard tooling.
+
+---
+---
+
+
+
+
+
+### Quick start
+
+Install crun-vm:
+
+```console
+$ dnf install crun-vm
+```
+
+Launch a VM from a disk image packaged in a container:
+
+```console
+$ podman run --runtime crun-vm -it \
+ quay.io/containerdisks/fedora:40
+```
+
+Launch a VM from a disk image under `my-image-dir/`:
+
+```console
+$ podman run --runtime crun-vm -it \
+ --rootfs my-image-dir/
+```
+
+Launch a VM from a [bootable container]:
+
+```console
+$ podman run --runtime crun-vm -it \
+ quay.io/fedora/fedora-bootc:40
+```
+
+Set the password for a VM's default user:
+
+```console
+$ podman run --runtime crun-vm -it \
+ quay.io/containerdisks/fedora:40 \
+ --password pass # for user "fedora"
+```
+
+Exec (ssh) into a VM:
+
+```console
+$ podman exec -it --latest -- --as fedora
+```
+
+
+ |
+
+
### Major features
- - Use it with **Podman**, **Docker**, or **Kubernetes**.
- - Launch VMs from VM **image files** present on the host or packaged into
- **container images**.
- Control VM **CPU** and **memory** allocation.
- - Provide **cloud-init** and **Ignition** configurations to VMs.
- - **Mount directories** into VMs.
+ - Pass **cloud-init** or **Ignition** configs to VMs.
+ - Mount **directories** into VMs.
- Pass **block devices** through to VMs.
- - Expose **qcow2 files** and other **disk images** to VMs as block devices.
+ - Expose additional **disk images** to VMs.
- **Forward ports** from the host to VMs.
- - **`podman exec`**/**`docker exec`**/**`kubectl exec`** into VMs.
+ - **`podman|docker|kubectl exec`** into VMs.
+
+---
### Documentation
1. [Installing crun-vm](docs/1-installing.md)
- 2. [Using crun-vm as a Podman or Docker runtime](docs/2-podman-docker.md)
- 3. [Using crun-vm as a Kubernetes runtime](docs/3-kubernetes.md)
+ 2. [Running VMs with **Podman** or **Docker**](docs/2-podman-docker.md)
+ 3. [Running VMs as **systemd** services](docs/3-systemd.md)
+ 4. [Running VMs in **Kubernetes**](docs/4-kubernetes.md)
+ 5. [**crun-vm(1)** man page](docs/5-crun-vm.1.ronn)
-> [!TIP]
-> See also how you can [combine **crun-vm** and **Podman Quadlet** to easily
-> manage both containers and VMs through **systemd**](/examples/quadlet).
+---
### License
This project is released under the GPL 2.0 (or later) license. See
[LICENSE](LICENSE).
+
+ |
+
+
+
+[bootable container]: https://containers.github.io/bootable
[Docker]: https://www.docker.com/
[Kubernetes]: https://kubernetes.io/
-[Podman]: https://podman.io/
+[KubeVirt]: https://kubevirt.io/
[OCI Runtime]: https://github.com/opencontainers/runtime-spec/blob/v1.1.0/spec.md
+[Podman]: https://podman.io/
+[systemd]: https://systemd.io/
diff --git a/docs/1-installing.md b/docs/1-installing.md
index 44cb689..c607c9d 100644
--- a/docs/1-installing.md
+++ b/docs/1-installing.md
@@ -1,96 +1,156 @@
# 1. Installing crun-vm
-## On Fedora
+There are two steps to setting up crun-vm on a system:
-Run:
+ - Installing the actual `crun-vm` binary;
+ - Configuring Podman, Docker, and/or Kubernetes (whichever you intend to use
+ crun-vm with) to recognize crun-vm as a runtime.
+
+These steps are detailed in the sections below.
+
+
+ Navigation
+
+ 1. **Installing crun-vm**
+ - [**Installing the `crun-vm` binary**](#installing-the-crun-vm-binary)
+ - [On Fedora](#on-fedora)
+ - [From source](#from-source)
+ - [**Making crun-vm available as a runtime**](#making-crun-vm-available-as-a-runtime)
+ - [To Podman](#to-podman)
+ - [To Docker](#to-docker)
+ - [To Kubernetes](#to-kubernetes)
+ 2. [Running VMs with **Podman** or **Docker**](2-podman-docker.md)
+ 3. [Running VMs as **systemd** services](3-systemd.md)
+ 4. [Running VMs in **Kubernetes**](4-kubernetes.md)
+ 5. [**crun-vm(1)** man page](5-crun-vm.1.ronn)
+
+
+
+## Installing the `crun-vm` binary
+
+### On Fedora
```console
$ dnf install crun-vm
```
-Podman will then be able to make use of the crun-vm runtime.
-
-To also set up crun-vm for use with Docker:
+### From source
+
+1. Install crun-vm's build dependencies:
+
+ - [cargo](https://doc.rust-lang.org/stable/cargo/getting-started/installation.html)
+ - [gzip](https://www.gzip.org/)
+ - [libselinux](https://github.com/SELinuxProject/selinux/tree/main/libselinux),
+ including development headers
+ - [ronn-ng](https://github.com/apjanke/ronn-ng)
+
+2. Install crun-vm's runtime dependencies:
+
+ - bash
+ - [coreutils](https://www.gnu.org/software/coreutils/)
+ - [crun](https://github.com/containers/crun)
+ - [crun-krun](https://github.com/containers/crun/blob/main/krun.1.md)
+ - [genisoimage](https://github.com/Distrotech/cdrkit)
+ - grep
+ - [libselinux](https://github.com/SELinuxProject/selinux/tree/main/libselinux)
+ - [libvirtd](https://gitlab.com/libvirt/libvirt) or
+ [virtqemud](https://gitlab.com/libvirt/libvirt)
+ - [passt](https://passt.top/)
+ - [qemu-img](https://gitlab.com/qemu-project/qemu)
+ - qemu-system-x86_64-core, qemu-system-aarch64-core, and/or other [QEMU
+ system emulators](https://gitlab.com/qemu-project/qemu) for the VM
+ architectures you want to support
+ - ssh
+ - [util-linux](https://github.com/util-linux/util-linux)
+ - [virsh](https://gitlab.com/libvirt/libvirt)
+ - [virtiofsd](https://gitlab.com/virtio-fs/virtiofsd)
+ - [virtlogd](https://gitlab.com/libvirt/libvirt)
+
+3. Install crun-vm's binary and man page:
- - Merge the following configuration into `/etc/docker/daemon.json`:
+ ```console
+ $ make install
+ ```
- ```json
- {
- "runtimes": {
- "crun-vm": {
- "path": "/usr/bin/crun-vm"
- }
- }
- }
- ```
+## Making crun-vm available as a runtime
- - Reload the `docker` service for the new configuration to take effect:
+### To Podman
- ```console
- $ service docker reload
- ```
+Nothing to do here, since Podman automatically recognizes crun-vm as a runtime.
+Commands like `podman create` and `podman run` can be made to use the crun-vm
+runtime by passing them the `--runtime crun-vm` option.
-## Build and install from source (on Fedora)
+
-1. Install crun-vm's runtime dependencies:
+See [2. Using crun-vm and **Podman** or **Docker** to run a
+VM](2-podman-docker.md) to get started.
- ```console
- $ dnf install bash coreutils crun crun-krun genisoimage grep libselinux-devel libvirt-client libvirt-daemon-driver-qemu libvirt-daemon-log openssh-clients qemu-img qemu-system-x86-core sed shadow-utils util-linux virtiofsd
- ```
+### To Docker
-2. Install Rust and Cargo if you do not already have Rust tooling available:
+1. Merge the following configuration into `/etc/docker/daemon.json` (creating
+ that directory and file if necessary):
- ```console
- $ dnf install cargo
+ ```json
+ {
+ "runtimes": {
+ "crun-vm": {
+ "path": "/usr/bin/crun-vm"
+ }
+ }
+ }
```
-3. Build crun-vm:
+2. Reload the `docker` service for the new configuration to take effect:
```console
- $ cargo build
+ $ service docker reload
```
-4. Copy the `target/debug/crun-vm` binary to wherever you prefer:
+Commands like `docker create` and `docker run` can then be made to use the
+crun-vm runtime by passing them the `--runtime crun-vm` option.
- ```console
- $ cp target/debug/crun-vm /usr/local/bin/
- ```
+See [2. Using crun-vm and **Podman** or **Docker** to run a
+VM](2-podman-docker.md) to get started.
-5. If you're using Podman:
+### To Kubernetes
- - Merge the following configuration into
- `/etc/containers/containers.conf`:
+For crun-vm to be usable as a runtime in a Kubernetes cluster, the latter must
+be use the [CRI-O] runtime. See the Kubernetes docs on [runtimes] for more
+information.
- > For rootless Podman, you can instead use
- > `${XDG_CONFIG_PATH}/containers/containers.conf`, where
- > `$XDG_CONFIG_PATH` defaults to `${HOME}/.config`.
+1. Install crun-vm on all cluster nodes where pods may be scheduled, using any
+ of the methods [described above](#installing-the-crun-vm-binary).
- ```toml
- [engine.runtimes]
- crun-vm = ["/usr/local/bin/crun-vm"]
- ```
+2. Append the following to `/etc/crio/crio.conf`:
- If you're using Docker:
+ ```toml
+ [crio.runtime.runtimes.crun-vm]
+ runtime_path = "/usr/bin/crun-vm"
+ ```
- - Merge the following configuration into `/etc/docker/daemon.json`:
+3. Create a `RuntimeClass` object in the cluster that references crun-vm:
- ```json
- {
- "runtimes": {
- "crun-vm": {
- "path": "/usr/local/bin/crun-vm"
- }
- }
- }
- ```
+ ```yaml
+ apiVersion: node.k8s.io/v1
+ kind: RuntimeClass
+ metadata:
+ name: crun-vm # a name of your choice
+ handler: crun-vm
+ ```
- - Reload the `docker` service for the new configuration to take effect:
+Pods can then be configured to use this `RuntimeClass` by specifying its name
+under `Pod.spec.runtimeClassName`.
- ```console
- $ service docker reload
- ```
+See [4. Using crun-vm and **Pod YAML** to run a VM with **Podman**, **systemd**,
+or **Kubernetes**](4-pod-yaml.md) to get started.
-With Podman, it is possible to use crun-vm without installing it, *i.e.*,
-performing only steps 1–3 above. In this case, instead of setting the runtime
-with `--runtime crun-vm`, specify an absolute path to the runtime binary:
-`--runtime "$PWD"/target/debug/crun-vm`.
+[runtimes]: https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cri-o
+[CRI-O]: https://cri-o.io/
diff --git a/docs/2-podman-docker.md b/docs/2-podman-docker.md
index afb8e59..a7a70eb 100644
--- a/docs/2-podman-docker.md
+++ b/docs/2-podman-docker.md
@@ -1,39 +1,66 @@
-# 2. Using crun-vm as a Podman or Docker runtime
-
-Here we overview some of the major features provided by crun-vm. The commands
-below use `podman`, but unless otherwise stated you can simply replace it with
-`docker`.
+# 2. Running VMs with **Podman** or **Docker**
+
+Here, we outline how to use crun-vm to run VMs using the Podman or Docker
+container engines. See [crun-vm(1)] for a full reference and additional details
+on crun-vm specific options.
+
+We use `podman` in the example commands below. Unless otherwise noted, the same
+commands also with `docker`.
+
+
+ Navigation
+
+ 1. [Installing crun-vm](1-installing.md)
+ 2. **Running VMs with **Podman** or **Docker****
+ - [**Booting VMs**](#booting-vms)
+ - [From containerdisks](#from-containerdisks)
+ - [From VM image files](#from-vm-image-files)
+ - [From bootable containers](#from-bootable-containers)
+ - [**Configuring VMs on first boot**](#configuring-vms-on-first-boot)
+ - [Default user password](#default-user-password)
+ - [cloud-init](#cloud-init)
+ - [Ignition](#ignition)
+ - [**Interacting with VMs**](#interacting-with-vms)
+ - [Exec'ing into VMs](#execing-into-vms)
+ - [Port forwarding](#port-forwarding)
+ - [**Sharing resources with VMs**](#sharing-resources-with-vms)
+ - [Files](#files)
+ - [Directories](#directories)
+ - [Block devices](#block-devices)
+ 3. [Running VMs as **systemd** services](3-systemd.md)
+ 4. [Running VMs in **Kubernetes**](4-kubernetes.md)
+ 5. [**crun-vm(1)** man page](5-crun-vm.1.ronn)
+
+
## Booting VMs
-### From regular VM image files
+### From containerdisks
-First, obtain a QEMU-compatible VM image and place it in a directory by itself:
+A "containerdisk" is a container image that packages a sole VM image file under
+`/` or `/disk/`. This is how you would boot a VM from the
+quay.io/containerdisks/fedora:40 containerdisk using crun-vm:
```console
-$ mkdir my-vm-image
-$ curl -LO --output-dir my-vm-image https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2
+$ podman run --runtime crun-vm -it quay.io/containerdisks/fedora:40
+Booting `Fedora Linux (6.8.5-301.fc40.x86_64) 40 (Cloud Edition)'
+[...]
```
-Then run:
-
-> This example does not work with Docker, as docker-run does not support the
-> `--rootfs` flag; see the next section for a Docker-compatible way of running
-> VM images.
-
-```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- --rootfs my-vm-image \
- "" # unused, but must specify command
-```
+> Several regularly-updated containerdisks may be found at
+> https://quay.io/organization/containerdisks. You can also easily build your
+> own:
+>
+> ```dockerfile
+> FROM scratch
+> COPY my-vm-image.qcow2 /
+> ENTRYPOINT ["no-entrypoint"]
+> ```
-The VM console should take over your terminal. At this point, the
-qcow2 image does not have any ssh keys, root password, or alternative
-users installed, so although you can interact with the VM's login
-screen, you will be unable to access a command prompt until more
-options are used in later sections. To abort the VM, press `ctrl-]`.
+The VM console should take over your terminal. This VM image has no users that
+you may log in as using a password, so although you can interact with the VM's
+login screen, you will be unable to access a command prompt for now. To abort
+the VM, press `ctrl-]`.
You can also detach from the VM without terminating it by pressing `ctrl-p,
ctrl-q`. Afterwards, reattach by running:
@@ -50,137 +77,131 @@ podman-run, in which case you won't be able to interact with the VM but can
still observe its console. Note that pressing `ctrl-]` will have no effect, but
you can always use the following command to terminate the VM:
-> For this command to work with Docker, you must replace the `--latest` flag
-> with the container's name or ID.
-
```container
$ podman stop --latest
```
-Changes made by the VM to its image are by default not persisted in the original
-image file. This can be changed by passing in the non-standard option
-`--persistent` *after* the `--rootfs` option:
+### From VM image files
+
+> This feature is only supported with Podman.
+
+It is also possible to boot VMs directly from disk image files by using Podman's
+`--rootfs` option to point at a directory containing a sole image file. For
+instance, these commands download and boot a Fedora 40 VM:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- --rootfs my-vm-image \
- --persistent
-```
+$ mkdir my-vm-image/ && curl -LO --output-dir my-vm-image/ https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2
-> [!WARNING]
->
-> When using `--persistent`, make sure that the image file is never
-> simultaneously used by another process or VM, otherwise **data corruption may
-> occur**.
+$ podman run --runtime crun-vm -it --rootfs my-vm-image/
+Booting `Fedora Linux (6.8.5-301.fc40.x86_64) 40 (Cloud Edition)'
+[...]
+```
-### From VM image files packaged into container images
+### From bootable containers
-crun-vm also works with container images that contain a VM image file with
-any name under `/` or under `/disk/`. No other files may exist in those
-directories. Containers built for use as [KubeVirt `containerDisk`s] follow this
-convention, so you can use those here:
+crun-vm can also launch VMs from [bootc bootable container images], which are
+containers that package a full operating system:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- quay.io/containerdisks/fedora:40
+$ podman run --runtime crun-vm -it quay.io/fedora/fedora-bootc:40
+Converting quay.io/fedora/fedora-bootc:40 into a VM image...
+[...]
+Caching VM image as a containerdisk...
+[...]
+Booting VM...
+[...]
```
-You can also use `util/package-vm-image.sh` to easily package a VM image into a
-container image, and `util/extract-vm-image.sh` to extract a VM image contained
-in a container image.
+crun-vm generates a VM image from the bootable container and then boots it. The
+generated VM image is packaged as a containerdisk and cached in the host's
+container storage, so that subsequent runs will boot faster:
-Note that flag `--persistent` has no effect when running VMs from container
-images.
+```console
+$ podman run --runtime crun-vm -it quay.io/crun-vm/example-fedora-bootc:40
+Retrieving cached VM image...
+[...]
+Booting VM...
+[...]
+```
+
+## Configuring VMs on first boot
-### From bootable container images
+### Default user password
-crun-vm can also work with [bootable container images], which are containers
-that package a full operating system:
+In the examples above, you were able to boot a VM but not to log in. An easy way
+to fix this when a VM has [cloud-init] installed is to use the [`--password`]
+option, which sets the password for the VM's "default" user (as determined in
+the image's cloud-init configuration). For quay.io/containerdisks/fedora:40,
+that is the `fedora` user:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- quay.io/crun-vm/example-fedora-bootc:40
+$ podman run --runtime crun-vm -it quay.io/containerdisks/fedora:40 --password pass
+Booting `Fedora Linux (6.8.5-301.fc40.x86_64) 40 (Cloud Edition)'
+[...]
+3b0232a04046 login: fedora
+Password: pass
+[fedora@3b0232a04046 ~]$
```
-Internally, crun-vm generates a VM image from the bootable container and then
-boots it.
-
-By default, the VM image is given a disk size roughly double the size of the
-bootc container image. To change this, use the `--bootc-disk-size [KMGT]`
-option.
-
-## First-boot customization
+Like all crun-vm specific options, [`--password`] must be passed in *after* the
+image specification.
### cloud-init
-In the examples above, you were able to boot the VM but not to log in. To fix
-this and do other first-boot customization, you can provide a [cloud-init]
-NoCloud configuration to the VM by passing in the non-standard option
-`--cloud-init` *after* the image specification:
+You can provide a full [cloud-init] NoCloud configuration to a VM by passing in
+the crun-vm specific option [`--cloud-init`] *after* the image specification:
```console
-$ ls examples/cloud-init/config/
-meta-data user-data vendor-data
+$ ls my-cloud-init-config/
+meta-data user-data
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- quay.io/containerdisks/fedora:40 \
- --cloud-init ~/examples/cloud-init/config # path must be absolute
-```
+$ cat my-cloud-init-config/meta-data # empty
-You should now be able to log in with the default `fedora` username and password
-`pass`.
+$ cat my-cloud-init-config/user-data
+#cloud-config
+write_files:
+ - path: $home/file
+ content: |
+ hello
-Alternatively, you can set the default user's password with the `--password`
-option:
-
-```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- quay.io/containerdisks/fedora:40 \
- --password pass
+$ podman run --runtime crun-vm -it quay.io/containerdisks/fedora:40 \
+ --cloud-init $PWD/my-cloud-init-config/ # path must be absolute
```
### Ignition
-Similarly, you can provide an [Ignition] configuration to the VM by passing in
-the `--ignition` option:
+You can also provide an [Ignition] configuration to a VM using the crun-vm
+specific [`--ignition`] option:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- quay.io/crun-vm/example-fedora-coreos:40 \
- --ignition ~/examples/ignition/config.ign # path must be absolute
+$ cat my-ignition-config.ign
+{
+ "ignition": {
+ "version": "3.0.0"
+ },
+ "passwd": {
+ "users": [
+ {
+ "name": "core",
+ "passwordHash": "$y$j9T$USdd8CBvFNVU1xKwQUnsU/$aE.3arHcRxD0ZT3vkvsSpEsteUj6vC4ZdRHY8eOj1f4"
+ }
+ ]
+ }
+}
+
+$ podman run --runtime crun-vm -it quay.io/crun-vm/example-fedora-coreos:40 \
+ --ignition $PWD/my-ignition-config.ign # path must be absolute
```
-You should now be able to log in with the default `core` username and password
-`pass`.
-
-Note that the `--password` option requires cloud-init support and doesn't work
-if the VM uses Ignition.
-
-## SSH'ing into the VM
+## Interacting with VMs
-Assuming the VM supports cloud-init or Ignition and exposes an SSH server on
-port 22, you can `ssh` into it as root using podman-exec:
+### Exec'ing into VMs
-> For this command to work with Docker, you must replace the `--latest` flag
-> with the container's name or ID.
+Assuming a VM supports cloud-init or Ignition and exposes an SSH server on port
+22, you can `ssh` into it as root using podman-exec:
```console
-$ podman run \
- --runtime crun-vm \
- --detach --rm \
- quay.io/containerdisks/fedora:40
+$ podman run --runtime crun-vm --detach quay.io/containerdisks/fedora:40
8068a2c180e0f4bf494f5e0baa37d9f13a9810f76b361c0771b73666e47ec383
$ podman exec --latest whoami
@@ -188,7 +209,7 @@ Please login as the user "fedora" rather than the user "root".
```
This particular VM image does not allow logging in as root. To `ssh` into the VM
-as a different user, specify its username using the `--as` option immediately
+as a different user, specify its username using the [`--as`] option immediately
before the command (if any). You may need to pass in `--` before this option to
prevent podman-exec from trying to interpret it:
@@ -200,38 +221,30 @@ fedora
If you just want a login shell, pass in an empty string as the command. The
following would be the output if this VM image allowed logging in as root:
-```
+```console
$ podman exec -it --latest ""
[root@8068a2c180e0 ~]$
```
-You can also log in as a specific user:
+You may also log in as a specific user:
-```
+```console
$ podman exec -it --latest -- --as fedora
[fedora@8068a2c180e0 ~]$
```
-When the VM supports cloud-init, `authorized_keys` is automatically set up to
+When a VM supports cloud-init, `authorized_keys` is automatically set up to
allow SSH access by podman-exec for users `root` and the default user as set in
the image's cloud-init configuration. With Ignition, this is set up for users
`root` and `core`.
-> If you want to exec into the container in which the VM is running (probably to
-> debug some problem with crun-vm itself), pass in the `--container` flag
-> immediately before the command (if any).
-
-## Port forwarding
+### Port forwarding
-You can use podman-run's standard `-p`/`--publish` option to set up TCP and/or
+You can use podman-run's standard `-p`/`--publish` option to enable TCP and/or
UDP port forwarding:
```console
-$ podman run \
- --runtime crun-vm \
- --detach --rm \
- -p 8000:80 \
- quay.io/crun-vm/example-http-server:latest
+$ podman run --runtime crun-vm --detach -p 8000:80 quay.io/crun-vm/example-http-server:latest
36c8705482589cfc4336a03d3802e7699f5fb228123d18e693488ac7b80116d1
$ curl localhost:8000
@@ -245,125 +258,73 @@ $ curl localhost:8000
[...]
```
-## Passing things through to the VM
+## Sharing resources with VMs
-### Directories
+### Files
-Bind mounting directories into the VM is supported:
+You can bind mount regular files into a VM:
-> [!WARNING]
->
-> This example recursively modifies the SELinux context of all files under the
-> path being mounted, in this case `./util`, which in the worst case **may cause
-> you to lose access to your files**. This is due to the `:z` volume mount
-> modifier, which instructs Podman to relabel the volume so that the VM can
-> access it.
->
-> Alternatively, you may remove this modifier from the command below and add
-> `--security-opt label=disable` instead to disable SELinux enforcement.
+```console
+$ podman run --runtime crun-vm -it \
+ -v ./README.md:/home/fedora/README.md:z \
+ quay.io/containerdisks/fedora:40
+```
+
+Regular files currently appear as block devices in the VM, but this is subject
+to change.
+
+### Directories
+
+It is also possible to bind mount directories into a VM:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
+$ podman run --runtime crun-vm -it \
-v ./util:/home/fedora/util:z \
- quay.io/containerdisks/fedora:40 \
- --password pass
+ quay.io/containerdisks/fedora:40
```
If the VM supports cloud-init or Ignition, the volume will automatically be
mounted at the given destination path. Otherwise, you can mount it manually with
-the following command, where `` must be the 0-based index of the volume
+the following command, where `` is the 0-based index of the volume
according to the order the `-v`/`--volume` or `--mount` flags where given in:
```console
$ mount -t virtiofs virtiofs- /home/fedora/util
```
-### Regular files
-
-Similarly to directories, you can bind mount regular files into the VM:
-
-> [!WARNING]
->
-> The warning about SELinux relabeling on the command above also applies here.
-
-```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
- -v ./README.md:/home/fedora/README.md:z \
- quay.io/containerdisks/fedora:40 \
- --password pass
-```
-
-Regular files currently appear as block devices in the VM, but this is subject
-to change.
-
### Block devices
-If cloud-init or Ignition are supported by the VM, it is possible to pass block
-devices through to it at a specific path using podman-run's `--device` flag
-(this example assumes `/dev/ram0` to exist and to be accessible by the current
-user):
+If cloud-init or Ignition are supported by a VM, it is possible to pass block
+devices through to it and make them appear at a specific path using podman-run's
+`--device` flag. For instance, assuming `/dev/ram0` exists on the host and is
+accessible by the current user:
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
+$ podman run --runtime crun-vm -it \
--device /dev/ram0:/home/fedora/my-disk \
- quay.io/containerdisks/fedora:40 \
- --password pass
+ quay.io/containerdisks/fedora:40
```
-You can also use the more powerful `--blockdev
-source=,target=,format=` custom option to this effect. This
-option also allows you specify a regular file as the source, and the source may
-be in any disk format known to QEMU (*e.g.*, raw, qcow2; when using `--device`,
-raw format is assumed):
+You can also use the more powerful, crun-vm specific [`--blockdev`]
+`source=,target=,format=` option to this effect. This option
+also allows you to specify a regular file as the source, and the source may be
+in any disk format known to QEMU (*e.g.*, raw, qcow2; when using `--device`, raw
+format is assumed):
```console
-$ podman run \
- --runtime crun-vm \
- -it --rm \
+$ podman run --runtime crun-vm -it \
quay.io/containerdisks/fedora:40 \
- --password pass \
- --blockdev source=~/my-disk.qcow2,target=/home/fedora/my-disk,format=qcow2 # paths must be absolute
+ --blockdev source=$PWD/my-disk.qcow2,target=/home/fedora/my-disk,format=qcow2 # paths must be absolute
```
-## Advanced options
-
-### System emulation
-
-To use system emulation instead of hardware-assisted virtualization, specify the
-`--emulated` flag. Without this flag, attempting to create a VM on a host tbat
-doesn't support KVM will fail.
-
-It's not currently possible to use this flag when the container image is a bootc
-bootable container.
-
-### Inspecting and customizing the libvirt domain XML
-
-crun-vm internally uses [libvirt] to launch a VM, generating a [domain XML
-definition] from the options provided to podman-run. This XML definition can be
-printed by adding the non-standard `--print-libvirt-xml` flag to your podman-run
-invocation.
-
-The generated XML definition can also be customized by specifying an XML file to
-be merged with it using the non-standard option `--merge-libvirt-xml `.
-
-> [!NOTE]
->
-> While `--merge-libvirt-xml` gives you maximum flexibility, it thwarts
-> crun-vm's premise of isolating the user from such details as libvirt domain
-> definitions, and you have instead to take care that your XML is valid *and*
-> that the customized definition is compatible with what crun-vm expects.
->
-> Before using this flag, consider if you would be better served using libvirt
-> directly to manage your VM.
-
-[bootable container images]: https://containers.github.io/bootable/
+[`--as`]: 5-crun-vm.1.ronn#exec-options
+[`--blockdev`]: 5-crun-vm.1.ronn#createrun-options
+[`--cloud-init`]: 5-crun-vm.1.ronn#createrun-options
+[`--ignition`]: 5-crun-vm.1.ronn#createrun-options
+[`--password`]: 5-crun-vm.1.ronn#createrun-options
+[bootc bootable container images]: https://containers.github.io/bootable/
[cloud-init]: https://cloud-init.io/
+[crun-vm(1)]: 5-crun-vm.1.ronn
[domain XML definition]: https://libvirt.org/formatdomain.html
[Ignition]: https://coreos.github.io/ignition/
[KubeVirt `containerDisk`s]: https://kubevirt.io/user-guide/virtual_machines/disks_and_volumes/#containerdisk
diff --git a/docs/3-kubernetes.md b/docs/3-kubernetes.md
deleted file mode 100644
index 7c17b57..0000000
--- a/docs/3-kubernetes.md
+++ /dev/null
@@ -1,153 +0,0 @@
-# 3. Using crun-vm as a Kubernetes runtime
-
-It is possible to use crun-vm as a [Kubernetes] runtime, allowing you to run
-VMs as regular pods.
-
-## Preparation
-
-To enable crun-vm on a Kubernetes cluster, follow these steps:
-
-1. Ensure that the cluster is using the [CRI-O] container runtime. Refer to the
- Kubernetes docs on [container runtimes].
-
-2. Install crun-vm on all cluster nodes where pods may be scheduled. Refer to
- the [installation instructions].
-
-3. Append the following to `/etc/crio/crio.conf` (adjust the `runtime_path` if
- necessary):
-
- ```toml
- [crio.runtime.runtimes.crun-vm]
- runtime_path = "/usr/local/bin/crun-vm"
- ```
-
-4. Create a `RuntimeClass` that references crun-vm:
-
- ```yaml
- apiVersion: node.k8s.io/v1
- kind: RuntimeClass
- metadata:
- name: crun-vm
- handler: crun-vm
- ```
-
-## Using the runtime
-
-> Under [examples/minikube] you can find a script that sets up a local minikube
-> Kubernetes cluster with crun-vm available as a runtime. You can use it to
-> easily try out the examples below.
-
-From then on, you can run VM images packaged in container images by creating
-pods that use this `RuntimeClass`:
-
-```yaml
-apiVersion: v1
-kind: Pod
-metadata:
- name: my-vm
-spec:
- containers:
- - name: my-vm
- image: quay.io/crun-vm/example-http-server:latest
- ports:
- - containerPort: 80
- runtimeClassName: crun-vm
-```
-
-### Logging
-
-The VM's console output is logged:
-
-```console
-$ kubectl logs my-vm
-```
-
-### SSH'ing into the pod/VM
-
-Assuming the VM supports cloud-init or Ignition, you can also SSH into it using
-`kubectl exec`:
-
-```console
-$ kubectl exec my-vm -- --as fedora whoami
-fedora
-
-$ kubectl exec -it my-vm -- --as fedora bash
-[fedora@my-vm ~]$
-```
-
-### Port forwarding
-
-The pod/VM defined above actually exposes an HTTP server on port 80. To talk to
-it, we must first forward a local port to the pod/VM:
-
-```console
-$ kubectl port-forward my-vm 8000:80
-Forwarding from 127.0.0.1:8000 -> 80
-Forwarding from [::1]:8000 -> 80
-```
-
-With this command running, navigate to [`localhost:8000`] on your browser, or
-run the following on a second terminal:
-
-```console
-$ curl localhost:8000
-
-
-
-
-Directory listing for /
-
-
-[...]
-```
-
-### cloud-init and Ignition
-
-When using crun-vm as a Kubernetes runtime, paths given to `--cloud-init` and
-`--ignition` are interpreted in the context of the container/VM, instead of the
-host. This means that config files can be retrieved from mounted volumes. For
-instance, you could store your cloud-init config in a `ConfigMap`:
-
-```yaml
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: my-cloud-init-config
-data:
- meta-data: ""
- user-data: |
- #cloud-config
- runcmd:
- - echo 'Hello, world!' > /home/fedora/hello-world
-```
-
-And pass it to your VMs like so:
-
-```yaml
-apiVersion: v1
-kind: Pod
-metadata:
- name: my-other-vm
-spec:
- containers:
- - name: my-other-vm
- image: quay.io/containerdisks/fedora:40
- args:
- - --cloud-init=/etc/cloud-init
- volumeMounts:
- - name: cloud-init-vol
- mountPath: /etc/cloud-init
- volumes:
- - name: cloud-init-vol
- configMap:
- name: my-cloud-init-config
- runtimeClassName: crun-vm
-```
-
-[container runtimes]: https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cri-o
-[CRI-O]: https://cri-o.io/
-[examples/minikube]: /examples/minikube
-[installation instructions]: 1-installing.md
-[Kubernetes]: https://kubernetes.io/
-[`localhost:8000`]: http://localhost:8000/
-[SSH'ing into the VM]: 2-podman-docker.md#sshing-into-the-vm
diff --git a/docs/3-systemd.md b/docs/3-systemd.md
new file mode 100644
index 0000000..8452c1f
--- /dev/null
+++ b/docs/3-systemd.md
@@ -0,0 +1,130 @@
+# 3. Running VMs as **systemd** services
+
+crun-vm also enables you to define a [systemd] service corresponding to a VM,
+and thus manage it through systemd. This relies on Podman's [Quadlet] feature,
+through which you can define systemd unit files for containers.
+
+> [!TIP]
+>
+> This means that system **containers** and **VMs** can both be deployed and
+> managed **using the same tooling**, *i.e.*, systemd!
+
+Here, we overview how you can create Quadlet-powered systemd services to manage
+VMs. Make sure you have installed both crun-vm and Podman (see [1. Installing
+crun-vm]).
+
+
+ Navigation
+
+ 1. [Installing crun-vm](1-installing.md)
+ 2. [Running VMs with **Podman** or **Docker**](2-podman-docker.md)
+ 3. **Running VMs as **systemd** services**
+ - [**Creating a systemd service for a VM**](#creating-a-systemd-service-for-a-vm)
+ - [**Further information**](#further-information)
+ 4. [Running VMs in **Kubernetes**](4-kubernetes.md)
+ 5. [**crun-vm(1)** man page](5-crun-vm.1.ronn)
+
+
+
+## Creating a systemd service for a VM
+
+The easiest way to do this is using [Podlet], a tool that can generate a systemd
+unit file corresponding to a given podman-run command. (Follow the instructions
+at https://github.com/containers/podlet to install Podlet.) This means we can
+apply it to the podman-run commands we use to launch VMs.
+
+For instance, say you're using this command to launch a VM that runs a web
+service (see [2. Running VMs with **Podman** or **Docker**] to learn how crun-vm
+can be used with Podman):
+
+```console
+$ podman run --runtime crun-vm --detach -p 8000:80 quay.io/crun-vm/example-http-server:latest
+```
+
+To convert this invocation into an equivalent systemd container unit definition,
+you would run:
+
+```console
+$ podlet \
+ --install \
+ --wanted-by default.target \
+ podman run --runtime crun-vm --detach -p 8000:80 quay.io/crun-vm/example-http-server:latest
+#example-http-server.container
+[Container]
+Image=quay.io/crun-vm/example-http-server:latest
+PublishPort=8000:80
+GlobalArgs=--runtime crun-vm
+
+[Install]
+WantedBy=default.target
+```
+
+The `--install`, `--wanted-by default.target` options configure the service to
+run automatically on boot.
+
+Finally, to actually install this unit definition, you would instead run (using
+`sudo` to become root):
+
+```console
+$ sudo podlet \
+ --name my-web-service \
+ --unit-directory \
+ --install \
+ --wanted-by default.target \
+ podman run --runtime crun-vm --detach -p 8000:80 quay.io/crun-vm/example-http-server:latest
+Wrote to file: /etc/containers/systemd/my-web-service.container
+
+$ systemctl daemon-reload # load the new service
+```
+
+With this, your web server VM becomes a systemd service:
+
+```console
+$ sudo systemctl status my-web-service
+○ my-web-service.service
+ Loaded: loaded (/etc/containers/systemd/my-web-service.container; generated)
+ Drop-In: /usr/lib/systemd/system/service.d
+ └─10-timeout-abort.conf
+ Active: inactive (dead)
+
+$ sudo systemctl start my-web-service # start the service without having to reboot
+
+$ sudo systemctl status my-web-service
+● my-web-service.service
+ Loaded: loaded (/etc/containers/systemd/my-web-service.container; generated)
+ Drop-In: /usr/lib/systemd/system/service.d
+ └─10-timeout-abort.conf
+ Active: active (running) since Tue 2024-04-30 21:14:36 WEST; 4s ago
+ Main PID: 1531707 (conmon)
+ Tasks: 48 (limit: 76805)
+ Memory: 1.1G (peak: 1.1G)
+ CPU: 11.768s
+[...]
+
+$ curl localhost:8000
+
+
+
+
+Directory listing for /
+
+
+[...]
+```
+
+## Further information
+
+See [this article] for additional information on Podman Quadlet, and the
+[podman-systemd.unit(5)] man page for the reference format of container unit
+files.
+
+The `podlet` commands provides several options to further customize the
+generated container unit file. Run `podlet -h` to know more.
+
+[1. Installing crun-vm]: 1-installing.md
+[2. Running VMs with **Podman** or **Docker**]: 2-podman-docker.md
+[Podlet]: https://github.com/containers/podlet
+[podman-systemd.unit(5)]: https://docs.podman.io/en/stable/markdown/podman-systemd.unit.5.html
+[Quadlet]: https://docs.podman.io/en/stable/markdown/podman-systemd.unit.5.html
+[systemd]: https://systemd.io/
+[this article]: https://www.redhat.com/sysadmin/quadlet-podman
diff --git a/docs/4-kubernetes.md b/docs/4-kubernetes.md
new file mode 100644
index 0000000..e62a981
--- /dev/null
+++ b/docs/4-kubernetes.md
@@ -0,0 +1,182 @@
+# 4. Running VMs in **Kubernetes**
+
+crun-vm can also be used as a [Kubernetes] runtime, allowing you to run VMs as
+regular pods.
+
+Note that there is already a very featureful project, [KubeVirt], that enables
+using Kubernetes to run VMs with great configurability. However, for simple use
+cases, crun-vm may be a good fit.
+
+
+ Navigation
+
+ 1. [Installing crun-vm](1-installing.md)
+ 2. [Running VMs with **Podman** or **Docker**](2-podman-docker.md)
+ 3. [Running VMs as **systemd** services](3-systemd.md)
+ 4. **Running VMs in **Kubernetes****
+ - [**Setting up**](#setting-up)
+ - [**Creating VMs**](#creating-vms)
+ - [**Interacting with VMs**](#interacting-with-vms)
+ - [Exec'ing into VMs](#execing-into-vms)
+ - [Port forwarding](#port-forwarding)
+ - [**First-boot configuration**](#first-boot-configuration)
+ 5. [**crun-vm(1)** man page](5-crun-vm.1.ronn)
+
+
+
+## Setting up
+
+You can use the [util/minikube-start.sh] script to set up a local [minikube]
+Kubernetes cluster with crun-vm available as a runtime, and use it to easily try
+out the examples below (note that this also points `kubectl` at the minikube
+cluster):
+
+```console
+$ ./minikube-start.sh
+ Compiling crun-vm v0.2.0 (/home/afaria/crun-vm)
+ Finished dev [unoptimized + debuginfo] target(s) in 1.70s
+😄 [crun-vm-example] minikube v1.32.0 on Fedora 40
+[...]
+🏄 Done! kubectl is now configured to use "crun-vm-example" cluster and "default" namespace by default
+runtimeclass.node.k8s.io/crun-vm created
+```
+
+Once you're done, you can delete the cluster with:
+
+```console
+$ minikube -p crun-vm-example delete
+```
+
+To enable crun-vm on a real Kubernetes cluster, follow the instructions in [1.
+Installing crun-vm].
+
+## Creating VMs
+
+To run a VM in your cluster, simply create a pod that references the
+`RuntimeClass` corresponding to crun-vm (here we assume it is named `crun-vm`):
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: my-vm
+spec:
+ containers:
+ - name: my-vm
+ image: quay.io/crun-vm/example-http-server:latest
+ ports:
+ - containerPort: 80
+ runtimeClassName: crun-vm
+```
+
+All the image formats supported by crun-vm when using Podman or Docker are also
+supported here. See [2. Running VMs with **Podman** or
+**Docker**](2-podman-docker.md#booting-vms) to know more.
+
+You can inspect the VM's console output with the standard [`kubectl logs`]
+command:
+
+```console
+$ kubectl logs my-vm
+```
+
+## Interacting with VMs
+
+### Exec'ing into VMs
+
+Assuming a VM supports cloud-init or Ignition, you can `ssh` into it using
+`kubectl exec`:
+
+```console
+$ kubectl exec my-vm -- --as fedora whoami
+fedora
+
+$ kubectl exec -it my-vm -- --as fedora bash
+[fedora@my-vm ~]$
+```
+
+The supported crun-vm specific options like `--as fedora` are the same as when
+using crun-vm with Podman or Docker. See [2. Running VMs with **Podman** or
+**Docker**](2-podman-docker.md#execing-into-vms) to know more.
+
+### Port forwarding
+
+The VM pod defined above actually exposes an HTTP server on port 80. To talk to
+it, we must first forward a local port to the VM:
+
+```console
+$ kubectl port-forward my-vm 8000:80
+Forwarding from 127.0.0.1:8000 -> 80
+Forwarding from [::1]:8000 -> 80
+```
+
+With this command running, navigate to [`localhost:8000`] on your browser, or
+run the following on a second terminal:
+
+```console
+$ curl localhost:8000
+
+
+
+
+Directory listing for /
+
+
+[...]
+```
+
+## First-boot configuration
+
+Options supported when using crun-vm with Podman or Docker, like `--password`,
+`--cloud-init`, and `--ignition`, are also supported here (see [2. Running VMs
+with **Podman** or **Docker**](2-podman-docker.md#execing-into-vms) for more
+information).
+
+However, paths given to `--cloud-init` and `--ignition` are interpreted in the
+context of the VM, instead of the host. This means that first-boot configuration
+files can be retrieved from mounted volumes. For instance, you could store your
+cloud-init configuration in a `ConfigMap`:
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: my-cloud-init-config
+data:
+ meta-data: ""
+ user-data: |
+ #cloud-config
+ runcmd:
+ - echo 'Hello, world!' > /home/fedora/hello-world
+```
+
+And apply it to your VMs like so:
+
+```yaml
+apiVersion: v1
+kind: Pod
+metadata:
+ name: my-other-vm
+spec:
+ containers:
+ - name: my-other-vm
+ image: quay.io/containerdisks/fedora:40
+ args:
+ - --cloud-init=/etc/cloud-init
+ volumeMounts:
+ - name: cloud-init-vol
+ mountPath: /etc/cloud-init
+ volumes:
+ - name: cloud-init-vol
+ configMap:
+ name: my-cloud-init-config
+ runtimeClassName: crun-vm
+```
+
+[`kubectl logs`]: https://kubernetes.io/docs/reference/kubectl/
+[`localhost:8000`]: http://localhost:8000/
+[1. Installing crun-vm]: 1-installing.md
+[Kubernetes]: https://kubernetes.io/
+[KubeVirt]: https://kubevirt.io/
+[minikube]: https://minikube.sigs.k8s.io/
+[util/minikube-start.sh]: ../util/minikube-start.sh
diff --git a/docs/5-crun-vm.1.ronn b/docs/5-crun-vm.1.ronn
new file mode 100644
index 0000000..cffa85d
--- /dev/null
+++ b/docs/5-crun-vm.1.ronn
@@ -0,0 +1,186 @@
+
+
+# 5. crun-vm(1) -- an OCI Runtime that runs VM images
+
+
+ Navigation
+
+ 1. [Installing crun-vm](1-installing.md)
+ 2. [Running VMs with **Podman** or **Docker**](2-podman-docker.md)
+ 3. [Running VMs as **systemd** services](3-systemd.md)
+ 4. [Running VMs in **Kubernetes**](4-kubernetes.md)
+ 5. ****crun-vm(1)** man page**
+ - [**SYNOPSIS**](#synopsis)
+ - [**DESCRIPTION**](#description)
+ - [**QUICK START**](#quick-start)
+ - [**CREATE/RUN USAGE**](#createrun-usage)
+ - [**CREATE/RUN OPTIONS**](#createrun-options)
+ - [**EXEC USAGE**](#exec-usage)
+ - [**EXEC OPTIONS**](#exec-options)
+ - [**ENVIRONMENT**](#environment)
+
+
+
+## SYNOPSIS
+
+`podman|docker` `create|run` --runtime crun-vm [...] [""] [...]
+`podman|docker` `exec` [...] [...] ...`|`""
+
+## DESCRIPTION
+
+**crun-vm** is an OCI Runtime that enables Podman, Docker, and Kubernetes to run
+QEMU-compatible Virtual Machine (VM) images.
+
+This man page enumerates the crun-vm specific options that may be used with
+Podman/Docker engine commands like `podman create` and `docker run`, and how
+they can be specified alongside standard engine options. Visit
+ for additional guides.
+
+## QUICK START
+
+Launch a VM from a "containerdisk" (a disk image packaged in a container):
+
+ $ podman run --runtime crun-vm -it quay.io/containerdisks/fedora:40
+
+Launch a VM from a disk image under *my-image-dir/*:
+
+ $ podman run --runtime crun-vm -it --rootfs my-image-dir/
+
+Launch a VM from a bootable container ():
+
+ $ podman run --runtime crun-vm -it quay.io/fedora/fedora-bootc:40
+
+Set the password for a VM's default user:
+
+ $ podman run --runtime crun-vm -it quay.io/containerdisks/fedora:40 \
+ --password pass # for user "fedora"
+
+Exec (ssh) into a VM:
+
+ $ podman exec -it --latest -- --as fedora
+
+## CREATE/RUN USAGE
+
+`podman|docker` `create|run` --runtime crun-vm [...] [""] [...]
+
+Standard engine options are specified in .
+
+ identifies a container image of one the following kinds:
+
+ 1. A "containerdisk", i.e., a container image with a sole VM image file
+ residing under `/` or `/disk/`, such as *quay.io/containerdisks/fedora:40*;
+
+ 2. The Podman-specific `--rootfs` option pointing at a directory containing a
+ sole VM image file;
+
+ 3. A bootc bootable container, such as *quay.io/fedora/fedora-bootc:40*
+ (see for more information).
+
+crun-vm specific options are specified in , i.e., where the
+command to execute in the container would usually by specified. Since this
+notion does not apply to VMs as it does to regular containers, no command should
+be specified here. However, if you're using Docker and the container you
+specified defines no default entrypoint, you have to also pass in an empty `""`
+argument to satisfy Docker's syntax.
+
+## CREATE/RUN OPTIONS
+
+All crun-vm specific options that may be passed to `podman|docker` `create|run`
+commands are listed here.
+
+These options configure the VM's environment:
+
+ * `--blockdev` source=,target=,format=:
+ Expose the file or block device at path in the VM.
+ and must be absolute paths. specifies the
+ QEMU-compatible image format of , such as *raw* or *qcow2*. When
+ *format=raw*, the same effect can be achieved with the standard
+ `-m`/`--mount`/`-v`/`--volume` Podman/Docker options.
+
+ * `--persistent`:
+ When using `podman|docker` `create|run` with the standard `--rootfs` option,
+ this flag causes writes made by the VM to its disk to be persisted in the
+ user's image file. Make sure that the image is never simultaneously used by
+ another process or VM, otherwise **data corruption may occur**.
+
+ * `--bootc-disk-size` [KMGT]:
+ Set the disk size of the VM image generated from a bootc bootable container.
+ The default is twice the size of the container image.
+
+ * `--emulated`:
+ Emulate the VM in software rather than using KVM for hardware-assisted
+ virtualization. It's not currently possible to use this flag when the
+ container image is a bootc bootable container.
+
+These options control the VM's first-boot customization:
+
+ * `--password` :
+ Set the password of the VM image's default user. Only works when the VM
+ supports cloud-init.
+
+ * `--cloud-init` :
+ Expose the given cloud-init configuration to the VM. must be an
+ absolute path.
+
+ * `--ignition` :
+ Expose the given Ignition configuration to the VM. must be an
+ absolute path.
+
+ * `--random-ssh-key-pair`:
+ By default, when using podman-exec, the host user's ssh key pair (if any) is
+ used to ssh into the VM. This is useful when the VM isn't easily
+ customizable at first boot but already authorizes the user's public key.
+ Otherwise, or if this flag is specified, a new random key pair is always
+ used.
+
+These options are mostly helpful when debugging crun-vm itself:
+
+ * `--merge-libvirt-xml` :
+ Merge the given XML file into the libvirt domain XML generated by crun-vm,
+ prior to using it to launch the VM. must be an absolute path.
+
+ * `--print-libvirt-xml`:
+ Print the libvirt domain XML that would be used to launch the VM, and exit
+ without launching the VM.
+
+ * `--print-config-json`:
+ Print the OCI Runtime config.json file with crun-vm's modifications that was
+ passed to *crun(1)*, and exit without launching the VM.
+
+## EXEC USAGE
+
+`podman|docker` `exec` [...] [--] [...] ...`|`""
+
+Standard engine arguments and options are specified in .
+
+crun-vm specific options are specified in , i.e., as a prefix to
+the command to be executed. To launch a login shell, pass `""` as the command.
+
+When using Podman's `--latest` flag instead of providing a container name or ID,
+you may need pass in `--` to delimit standard options from crun-vm specific
+options.
+
+## EXEC OPTIONS
+
+Options that may be used with `podman|docker` `exec` as a prefix to the actual
+command to run, if any:
+
+ * `--as` :
+ The user to ssh into the VM as. Defaults to *root*.
+
+ * `--timeout` :
+ The timeout, in seconds, to apply to a `podman|docker` `run` command.
+ Defaults to the value of the `CRUN_VM_EXEC_TIMEOUT` environment variable if
+ set, or *0* otherwise, which means no timeout.
+
+These options are mostly helpful when debugging crun-vm itself:
+
+ * `--container`:
+ Exec into the container where the VM hypervisor is running, instead of
+ ssh'ing into the actual VM. Incompatible with `--as`.
+
+## ENVIRONMENT
+
+ * `CRUN_VM_EXEC_TIMEOUT`:
+ The timeout, in seconds, to apply to a `podman|docker` `exec` command.
+ Defaults to *0*, which means no timeout. Is overridden by `--timeout`.
diff --git a/docs/example.gif b/docs/example.gif
index cad1500..7405677 100644
Binary files a/docs/example.gif and b/docs/example.gif differ
diff --git a/examples/cloud-init/README.md b/examples/cloud-init/README.md
deleted file mode 100644
index 957ee2e..0000000
--- a/examples/cloud-init/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Example: cloud-init configuration
-
-Under [config/](config/) you can find the cloud-init NoCloud configuration that
-is used as an example throughout the documentation.
diff --git a/examples/cloud-init/config/meta-data b/examples/cloud-init/config/meta-data
deleted file mode 100644
index 33b62d4..0000000
--- a/examples/cloud-init/config/meta-data
+++ /dev/null
@@ -1 +0,0 @@
-local-hostname: my-vm
diff --git a/examples/cloud-init/config/user-data b/examples/cloud-init/config/user-data
deleted file mode 100644
index d301288..0000000
--- a/examples/cloud-init/config/user-data
+++ /dev/null
@@ -1,4 +0,0 @@
-#cloud-config
-password: pass
-chpasswd:
- expire: False
diff --git a/examples/cloud-init/config/vendor-data b/examples/cloud-init/config/vendor-data
deleted file mode 100644
index e69de29..0000000
diff --git a/examples/ignition/README.md b/examples/ignition/README.md
deleted file mode 100644
index 1350f19..0000000
--- a/examples/ignition/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Example: Ignition configuration
-
-At [config.ign](config.ign) you can find the Ignition configuration that is used
-as an example throughout the documentation.
diff --git a/examples/ignition/config.ign b/examples/ignition/config.ign
deleted file mode 100644
index cc71773..0000000
--- a/examples/ignition/config.ign
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "ignition": {
- "version": "3.0.0"
- },
- "passwd": {
- "users": [
- {
- "name": "core",
- "passwordHash": "$y$j9T$USdd8CBvFNVU1xKwQUnsU/$aE.3arHcRxD0ZT3vkvsSpEsteUj6vC4ZdRHY8eOj1f4"
- }
- ]
- },
- "storage": {
- "files": [
- {
- "path": "/etc/hostname",
- "mode": 420,
- "overwrite": true,
- "contents": {
- "source": "data:,my-vm"
- }
- }
- ]
- }
-}
diff --git a/examples/minikube/README.md b/examples/minikube/README.md
deleted file mode 100644
index 0905d83..0000000
--- a/examples/minikube/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Example: Minikube cluster with crun-vm available as a runtime
-
-You can use the `./minikube-start.sh` script in this directory to create a local
-[minikube] Kubernetes cluster with crun-vm available as a runtime (note that
-this also points `kubectl` at the minikube cluster):
-
-```console
-$ ./minikube-start.sh
- Compiling crun-vm v0.1.3 (/home/afaria/repos/crun-vm)
- Finished dev [unoptimized + debuginfo] target(s) in 1.38s
-😄 [crun-vm-example] minikube v1.32.0 on Fedora 39
-[...]
-🏄 Done! kubectl is now configured to use "crun-vm-example" cluster and "default" namespace by default
-runtimeclass.node.k8s.io/crun-vm created
-```
-
-Try going through the examples at [Using crun-vm as a Kubernetes runtime].
-
-Once you're done, you can delete the cluster with:
-
-```console
-$ minikube -p crun-vm-example delete
-```
-
-[minikube]: https://minikube.sigs.k8s.io/
-[Using crun-vm as a Kubernetes runtime]: /docs/3-kubernetes.md
diff --git a/examples/quadlet/README.md b/examples/quadlet/README.md
deleted file mode 100644
index fb2798a..0000000
--- a/examples/quadlet/README.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# Example: Manage VMs with systemd using Podman Quadlet and crun-vm
-
-[Podman Quadlet] is a feature that allows you to define systemd unit files for
-containers, such that they can be managed like any other systemd service.
-
-crun-vm is fully compatible with Podman Quadlet, meaning that you can also
-launch and manage your VMs through systemd. Here's an example of how to do so:
-
-1. Create file `$HOME/.config/containers/systemd/my-vm.container` with the
- following contents:
-
- ```toml
- [Unit]
- Description=My VM
- After=local-fs.target
-
- [Container]
- PodmanArgs=--runtime crun-vm # make Podman use crun-vm as the runtime
- Image=quay.io/containerdisks/fedora:40 # the container image containing our VM image
- Exec=--password pass # optional crun-vm arguments
-
- [Install]
- WantedBy=multi-user.target default.target # start on boot by default
- ```
-
- The options under `[Container]` in this unit file will effectively translate
- into the following podman invocation:
-
- ```console
- $ podman run --runtime crun-vm quay.io/containerdisks/fedora:40 --password pass
- ```
-
-2. Inform systemd of the new unit file:
-
- ```console
- $ systemctl --user daemon-reload
- ```
-
- This will creates a my-vm.service file based on my-vm.container above.
-
-3. Manage my-vm.service as you would any other service. For instance, we can
- start it up:
-
- ```console
- $ systemctl --user start my-vm.service
- ```
-
- And then check its status:
-
- ```console
- $ systemctl --user status my-vm.service
- ```
-
-See [this article] for additional information on using Podman Quadlet, and
-[podman-systemd.unit(5)] for the reference format for Quadlet systemd units.
-
-[Podman Quadlet]: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html
-[podman-systemd.unit(5)]: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html
-[this article]: https://www.redhat.com/sysadmin/quadlet-podman
diff --git a/examples/minikube/minikube-start.sh b/util/minikube-start.sh
similarity index 94%
rename from examples/minikube/minikube-start.sh
rename to util/minikube-start.sh
index 2a6db1b..0378eba 100755
--- a/examples/minikube/minikube-start.sh
+++ b/util/minikube-start.sh
@@ -3,8 +3,7 @@
set -o errexit -o pipefail -o nounset
-script_dir="$( dirname "$0" | xargs readlink -e )"
-repo_root=$script_dir/../..
+repo_root=$( readlink -e "$( dirname "$0" )/.." )
__minikube() {
minikube -p=crun-vm-example "$@"