Skip to content

Commit

Permalink
Support running from a container
Browse files Browse the repository at this point in the history
Unlike on macOS and Windows, on Linux `podman machine` isn't a
requirement for running containers given that... well, you can already
run containers directly. So setting up a podman machine would purely be
for the benefit of `podman-bootc`.

OTOH, the alternative of using bootc-image-builder is much more flexible
but requires root and is not as streamlined a process if one wants to
either just kick the tires or want a faster iteration loop on bootable
containers.

Let's support running `podman-bootc` from a container. This allows users
to get to a functional environment in one command:

```
podman run -ti --device /dev/kvm quay.io/podman/podman-bootc
```

This will bring up the 'bootstrap' podman machine, and give users a
shell. Caching is also supported by mounting to `/cache`:

```
podman run -ti -v ~/.cache/podman-bootc:/cache:z --device /dev/kvm \
  quay.io/podman/podman-bootc run <image>
```

There is also a one-shot mode for the `run` command. This allows users
to boot a bootable container with a *single* command:

```
podman run -ti --device /dev/kvm quay.io/podman/podman-bootc run <image>
```

As opposed to b-i-b, all this works fine in rootless podman. The only
main requirement is `/dev/kvm`, which is of course not new.

Another way to look at this is that it de-emphasizes podman machine
and focuses on the image building, caching, and booting aspects of
podman-bootc, which is where the most value is for Linux users.
  • Loading branch information
jlebon committed May 6, 2024
1 parent 74172ae commit 92096bd
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 1 deletion.
19 changes: 19 additions & 0 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM quay.io/fedora/fedora:40 as build
RUN dnf install --setopt=install_weak_deps=0 -y \
golang libvirt-devel git-core && \
dnf clean all
COPY . /src
WORKDIR /src
RUN make

FROM quay.io/fedora/fedora:40
RUN dnf install --setopt=install_weak_deps=0 -y \
podman gvisor-tap-vsock qemu-img qemu-kvm-core openssh-clients \
libvirt-client libvirt-daemon-driver-qemu libvirt-daemon-driver-storage-disk && \
dnf clean all
COPY --from=build /src/bin/podman-bootc /usr/bin/
COPY --from=build /src/entrypoint /usr/bin/
RUN useradd podman-bootc -d /cache
# nuke polkit tty agent to silence virsh warnings
RUN rm /usr/bin/pkttyagent
ENTRYPOINT ["/usr/bin/entrypoint"]
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,39 @@ Even after you close the SSH connection, the machine continues to run.
- `podman-bootc ssh`: Connect to a VM
- `podman-bootc rm`: Remove a VM

### Architecture
## Running as a container (Linux)

There is also a container image available at `quay.io/podman/podman-bootc` that
makes it more convenient to run podman-bootc on Linux. It can run under rootless
podman. The only requirement is that `/dev/kvm` must be passed through.

In this model, the underlying `podman machine` infrastructure is automatically
brought up on startup and brought down on exit. This allows booting a bootc
container in a single command:

```shell
podman run --rm -ti --device /dev/kvm quay.io/podman/podman-bootc run <image>
```

You can also run the image without passing any command. In that case, you will
be given a shell in which the environment is set up and ready for `podman-bootc`
invocations.

### Caching

You likely will want to enable caching to avoid having to redownload/rederive
artifacts every time. To do this, mount a volume at `/cache`. For example:

```shell
# from a volume
podman volume create podman-bootc
podman run --rm -v podman-bootc:/cache --device /dev/kvm quay.io/podman/podman-bootc run <image>

# from a mountpoint
podman run --rm -v ~/.cache/podman-bootc:/cache:z --device /dev/kvm quay.io/podman/podman-bootc
```

## Architecture

At the current time the `run` command uses a
[bootc install](https://containers.github.io/bootc/bootc-install.html)
Expand Down
74 changes: 74 additions & 0 deletions entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash
set -euo pipefail

if [ "$(id -u)" = 0 ]; then
# this is normally created by the authentication stack
rundir=/run/user/"$(id -u podman-bootc)"
# shellcheck disable=SC2174
mkdir -m 700 -p "${rundir}"
chown -R podman-bootc:podman-bootc "${rundir}"

rc=0
mountpoint -q /cache || rc=$?
if [ $rc = 0 ]; then
chown -R podman-bootc:podman-bootc /cache
elif [ $rc = 32 ]; then
echo "Note: /cache is not a mountpoint" >&2
echo "Consider mounting a volume on /cache to cache artifacts" >&2
else
echo "Warning: failed checking if /cache is a mountpoint" >&2
fi

# re-exec ourselves as the podman-bootc user
# control flow continues below
exec sudo -u podman-bootc "$0" "$@"
fi

# When hard killing VMs (e.g. by hard killing the container), disk overlays
# can remain; libvirt will choke if they already exist when trying to bring
# up new VMs from the same image. Those files should probably not be under
# XDG_CACHE_HOME in the first place.
if [ -d /cache/.cache/podman-bootc ]; then
find /cache/.cache/podman-bootc -name '*.TRANSIENT-*' -type f -exec rm {} \;
fi

if [ $# -gt 0 ] && [ "$1" != run ]; then
echo "Only the 'run' command is supported in this mode" >&2
echo "To get a shell, do not pass a command" >&2
exit 1
fi

stop() {
podman machine stop bootstrap
touch /cache/.clean-bootstrap-stop
}

trap 'stop' EXIT

# create or recreate or start the bootstrap VM
init_args=(--rootful --timezone UTC --now bootstrap)
if podman machine ls -q | grep -q bootstrap; then
if [ ! -f /cache/.clean-bootstrap-stop ]; then
# to be safe, we recreate the bootstrap node if it wasn't shut down cleanly
podman machine rm bootstrap -f
podman machine init "${init_args[@]}"
else
rm /cache/.clean-bootstrap-stop
podman machine start bootstrap
fi
else
podman machine init "${init_args[@]}"
fi

if [ $# = 0 ]; then
echo "You can now run podman-bootc commands; e.g.:" >&2
echo >&2
echo -e "\tpodman-bootc run --rm quay.io/centos-bootc/centos-bootc:stream9" >&2
echo >&2
bash
elif [ "$1" = run ]; then
podman-bootc "$@"
else
echo "unreachable" >&2
exit 1
fi

0 comments on commit 92096bd

Please sign in to comment.