Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests/env.sh: Add aarch64 support #61

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
10 changes: 6 additions & 4 deletions .packit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ jobs:
skip_build: true
enable_net: true
targets:
# TODO: Replace these three with fedora-all-x86_64 once Fedora 38 is gone.
- fedora-rawhide-x86_64
- fedora-40-x86_64
- fedora-39-x86_64
- fedora-stable-x86_64
# TODO: Looks like we need Armv8.3-A CPUs for nested virt, and QEMU and
# kernel support is also very recent. Testing Farm is using AWS Graviton3,
# which is ARMv8.4-A, so hopefully things work once the software stack
# catches up and we can enable this.
- fedora-stable-aarch64
identifier: docker
tmt_plan: /tests/docker

Expand Down
2 changes: 1 addition & 1 deletion docs/1-installing.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ To also set up crun-vm for use with Docker:
1. Install crun-vm's runtime dependencies:

```console
$ dnf install bash coreutils crun genisoimage grep libselinux-devel libvirt-client libvirt-daemon-driver-qemu libvirt-daemon-log openssh-clients qemu-img qemu-system-x86-core shadow-utils util-linux virtiofsd
$ 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
```

2. Install Rust and Cargo if you do not already have Rust tooling available:
Expand Down
23 changes: 23 additions & 0 deletions docs/2-podman-docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ in a container image.
Note that flag `--persistent` has no effect when running VMs from container
images.

### From bootable container images

crun-vm can also work with [bootable container images], which are containers
that package a full operating system:

```console
$ podman run \
--runtime crun-vm \
-it --rm \
quay.io/crun-vm/example-fedora-bootc:40
```

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 <size>[KMGT]`
option.

## First-boot customization

### cloud-init
Expand Down Expand Up @@ -320,6 +339,9 @@ 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
Expand All @@ -340,6 +362,7 @@ be merged with it using the non-standard option `--merge-libvirt-xml <file>`.
> 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/
[cloud-init]: https://cloud-init.io/
[domain XML definition]: https://libvirt.org/formatdomain.html
[Ignition]: https://coreos.github.io/ignition/
Expand Down
88 changes: 88 additions & 0 deletions embed/bootc/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"ociVersion": "1.0.0",
"process": {
"terminal": true,
"user": { "uid": 0, "gid": 0 },
"args": ["/output/entrypoint.sh", "<IMAGE_NAME>"],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [],
"effective": [],
"inheritable": [],
"permitted": [],
"ambient": []
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 262144,
"soft": 262144
}
],
"noNewPrivileges": true
},
"root": {
"path": "<ORIGINAL_ROOT>",
"readonly": false
},
"hostname": "bootc-install",
"mounts": [
{
"type": "bind",
"source": "<PRIV_DIR>/root/crun-vm/bootc",
"destination": "/output",
"options": ["bind", "rprivate", "rw"]
},
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
}
],
"linux": {
"namespaces": [
{ "type": "pid" },
{ "type": "network" },
{ "type": "ipc" },
{ "type": "uts" },
{ "type": "cgroup" },
{ "type": "mount" }
],
"maskedPaths": [
"/proc/acpi",
"/proc/asound",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
"readonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
59 changes: 59 additions & 0 deletions embed/bootc/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-or-later

set -e

image_name=$1

# monkey-patch loopdev partition detection, given we're not running systemd
# (bootc runs `udevadm settle` as a way to wait until loopdev partitions are
# detected; we hijack that call and use partx to set up the partition devices)

original_udevadm=$( which udevadm )

mkdir -p /output/bin

cat >/output/bin/udevadm <<EOF
#!/bin/sh
${original_udevadm@Q} "\$@" && partx --add /dev/loop0
EOF

chmod +x /output/bin/udevadm

# default to an xfs root file system if there is no bootc config (some images
# don't currently provide any, for instance quay.io/fedora/fedora-bootc:40)

if ! find /usr/lib/bootc/install -mindepth 1 -maxdepth 1 | read; then
# /usr/lib/bootc/install is empty

cat >/usr/lib/bootc/install/00-crun-vm.toml <<-EOF
[install.filesystem.root]
type = "xfs"
EOF

fi

# build disk image using bootc-install

# TODO: `bootc install to-disk` currently fails when using docker-archive. Fix
# the underlying issue to avoid this skopeo-copy command.
skopeo copy --quiet \
docker-archive:/output/image.docker-archive \
oci-archive:/output/image.oci-archive

rm /output/image.docker-archive

PATH=/output/bin:$PATH bootc install to-disk \
--source-imgref oci-archive:/output/image.oci-archive \
--target-imgref "$image_name" \
--skip-fetch-check \
--generic-image \
--via-loopback \
--karg console=tty0 \
--karg console=ttyS0 \
--karg selinux=0 \
/output/image.raw

# communicate success by creating a file, since krun always exits successfully

touch /output/bootc-install-success
139 changes: 139 additions & 0 deletions embed/bootc/prepare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later

set -o errexit -o pipefail -o nounset

engine=$1
container_id=$2
original_root=$3
priv_dir=$4
disk_size=$5

__step() {
printf "\033[36m%s\033[0m\n" "$*"
}

bootc_dir=$priv_dir/root/crun-vm/bootc

mkfifo "$bootc_dir/progress"
exec > "$bootc_dir/progress" 2>&1

# this blocks here until the named pipe above is opened by entrypoint.sh

# get info about the container *image*

image_info=$(
"$engine" container inspect \
--format '{{.Config.Image}}'$'\t''{{.Image}}' \
"$container_id"
)

image_name=$( cut -f1 <<< "$image_info" )
# image_name=${image_name#sha256:}

image_id=$( cut -f2 <<< "$image_info" )

# determine disk size

if [[ -z "$disk_size" ]]; then
container_image_size=$(
"$engine" image inspect --format '{{.VirtualSize}}' "$image_id"
)

# use double the container image size to allow for in-place updates
disk_size=$(( container_image_size * 2 ))

# round up to 1 MiB
alignment=$(( 2**20 ))
disk_size=$(( (disk_size + alignment - 1) / alignment * alignment ))
fi

truncate --size "$disk_size" "$bootc_dir/image.raw"
disk_size=$( stat --format %s "$bootc_dir/image.raw" )

# check if VM image is cached

container_name=crun-vm-$container_id

cache_image_labels=(
"crun-vm.from=$image_id"
"crun-vm.size=$disk_size"
)

cache_image_id=$(
"$engine" images \
"${cache_image_labels[@]/#/--filter=label=}" \
--format '{{.ID}}' --no-trunc
)

if [[ -n "$cache_image_id" ]]; then

# retrieve VM image from cached containerdisk

__step "Retrieving cached VM image..."

trap '"$engine" rm --force "$container_name" >/dev/null 2>&1 || true' EXIT

"$engine" create --quiet --name "$container_name" "$cache_image_id" </dev/null >/dev/null
"$engine" export "$container_name" | tar -C "$bootc_dir" -x image.qcow2
"$engine" rm "$container_name" >/dev/null 2>&1

trap '' EXIT

else

__step "Converting $image_name into a VM image..."

# save container *image* as an archive

echo -n 'Preparing container image...'

"$engine" save --output "$bootc_dir/image.docker-archive" "$image_id" </dev/null 2>&1 \
| sed -u 's/.*/./' \
| stdbuf -o0 tr -d '\n'

echo

# adjust krun config

__sed() {
sed -i "s|$1|$2|" "$bootc_dir/config.json"
}

__sed "<IMAGE_NAME>" "$image_name"
__sed "<ORIGINAL_ROOT>" "$original_root"
__sed "<PRIV_DIR>" "$priv_dir"

# run bootc-install under krun

trap 'krun delete --force "$container_name" >/dev/null 2>&1 || true' EXIT
krun run --config "$bootc_dir/config.json" "$container_name" </dev/ptmx
trap '' EXIT

[[ -e "$bootc_dir/bootc-install-success" ]]

# convert image to qcow2 to get a lower file size

qemu-img convert -f raw -O qcow2 "$bootc_dir/image.raw" "$bootc_dir/image.qcow2"

# cache VM image file as containerdisk

__step "Caching VM image as a containerdisk..."

id=$(
"$engine" build --quiet --file - "${cache_image_labels[@]/#/--label=}" "$bootc_dir" <<-'EOF'
FROM scratch
COPY image.qcow2 /
ENTRYPOINT ["no-entrypoint"]
EOF
)

echo "Stored as untagged container image with ID $id"

fi

rm "$bootc_dir/image.raw"

__step "Booting VM..."

touch "$bootc_dir/success"
18 changes: 18 additions & 0 deletions scripts/entrypoint.sh → embed/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ trap 'exit 143' SIGTERM

set -o errexit -o pipefail -o nounset

is_bootc_container=$1

# clean up locks that may have been left around from the container being killed
rm -fr /var/lock

Expand Down Expand Up @@ -53,6 +55,22 @@ virsh --connect "qemu+unix:///session?socket=$socket" "\$@"
EOF
chmod +x /crun-vm/virsh

# wait until VM image is generated from bootable container (if applicable)

if (( is_bootc_container == 1 )) && [[ ! -e /crun-vm/image/image ]]; then

fifo=/crun-vm/bootc/progress
while [[ ! -e "$fifo" ]]; do sleep 0.2; done
cat "$fifo"
rm "$fifo"

[[ -e /crun-vm/bootc/success ]]

mkdir -p /crun-vm/image
mv /crun-vm/bootc/image.qcow2 /crun-vm/image/image

fi

# launch VM

function __bg_ensure_tty() {
Expand Down
1 change: 0 additions & 1 deletion scripts/exec.sh → embed/exec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ if [[ ! -e /crun-vm/ssh-successful ]]; then
"Connection closed by remote host"
"Connection refused"
"Connection reset by peer"
"Pseudo-terminal will not be allocated because stdin is not a terminal"
"System is booting up"
)

Expand Down
File renamed without changes.
Loading