diff --git a/README.md b/README.md index e44a878..479dbbf 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Turning containers into bootable VMs # Build the container podman build ./example/alpine -t slim-alpine -# Make the container bootable by extracing initrd and vmlinuz (initial ramdisk and kernel) -slim build slim-alpine +# Make the container bootable by extracing initrd (initial ramdisk) +slim build qcow2 slim-alpine --init=/init # Boot the image using QEMU, `./example/alpine/init` will drop you into an interactive shell. slim run slim-alpine diff --git a/example/alpine/init b/example/alpine/init index 6166119..c29378f 100644 --- a/example/alpine/init +++ b/example/alpine/init @@ -11,7 +11,6 @@ mount -t sysfs sysfs /sys # Networking echo slim > /proc/sys/kernel/hostname -modprobe virtio_net ip link set lo up 2>/dev/null ip link set eth0 up 2>/dev/null udhcpc -i eth0 -f -q # Get DHCP lease diff --git a/example/archlinux/init b/example/archlinux/init index b00d629..7529f57 100644 --- a/example/archlinux/init +++ b/example/archlinux/init @@ -8,7 +8,6 @@ mount -t sysfs sysfs /sys # Networking echo slim > /proc/sys/kernel/hostname -modprobe virtio_net ip link set lo up 2>/dev/null ip link set eth0 up 2>/dev/null # udhcpc -i eth0 -f -q # Get DHCP lease diff --git a/src/build.rs b/src/build.rs index b758fda..af7d951 100644 --- a/src/build.rs +++ b/src/build.rs @@ -5,6 +5,7 @@ use anyhow::{Context, Result, bail}; use clap::{Args, ValueEnum}; use flate2::write::GzEncoder; use std::fs::{self, File}; +use std::io; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use tempfile::NamedTempFile; @@ -75,10 +76,11 @@ fn to_raw_ext4(dir: &Path) -> Result { .parse() .context("failed to parse du output")?; let used = used_kb * 1024; - let mb = 1024 * 1024; + let gb = 1024 * 1024 * 1024; let size = used + (used / 10) // Add 10% - + 64 * mb; // Add some margin + // TODO: make configurable + + 64 * gb; // Add some spare capacity for activities let size = size.to_string(); let raw_file = NamedTempFile::new()?; @@ -124,33 +126,13 @@ fn build_qcow2(image: &str, mount_path: &Path) -> Result<()> { fn build_initrd(image: &str, mount_path: &Path) -> Result<()> { let mount_path = mount_path.to_str().context("mount path is not UTF-8")?; - let vmlinuz_src = format!("{mount_path}/vmlinuz"); - - // The rootless overlay mount only exists inside podman unshare's user - // namespace, so every read of the rootfs must run there; pipes still - // cross the namespace boundary. - let _has_kernel = cmd(&["podman", "unshare", "--", "test", "-f", &vmlinuz_src]) - .context("Image missing required /vmlinuz. Place kernel at /vmlinuz in Containerfile.")?; let reg_dir = registry_dir(image)?; fs::create_dir_all(®_dir)?; println!("Registry: {}", reg_dir.display()); - let vmlinuz_dst = reg_dir.join("vmlinuz"); - cmd(&[ - "podman", - "unshare", - "--", - "cp", - &vmlinuz_src, - vmlinuz_dst.to_str().context("registry path is not UTF-8")?, - ]) - .context("Failed to copy vmlinuz out of the image mount")?; - println!("Copied vmlinuz -> {}", vmlinuz_dst.display()); - - // Pack the rootfs as a gzipped newc cpio archive; vmlinuz is excluded - // because QEMU loads the kernel separately via -kernel. The cpio - // pipeline runs inside the namespace, its stdout is compressed here. + // Pack the rootfs as a gzipped newc cpio archive. The cpio pipeline + // runs inside the namespace, its stdout is compressed here. let initrd_path = reg_dir.join("initrd"); let script = r#"cd "$1" && find . -not -path ./vmlinuz | cpio -o -H newc"#; let mut cpio = Command::new("podman") @@ -162,7 +144,7 @@ fn build_initrd(image: &str, mount_path: &Path) -> Result<()> { let initrd_file = File::create(&initrd_path).context("Failed to create initrd file")?; let mut encoder = GzEncoder::new(initrd_file, flate2::Compression::default()); let cpio_stdout = cpio.stdout.take().context("cpio stdout was not piped")?; - let copied = std::io::copy(&mut std::io::BufReader::new(cpio_stdout), &mut encoder); + let copied = io::copy(&mut io::BufReader::new(cpio_stdout), &mut encoder); let stream_result = copied .and_then(move |_| encoder.finish().map(|_| ())) .context("Failed to write the gzipped initrd");