Introduction
bcvk (bootc virtualization kit) runs bootc containers as virtual machines and creates bootable disk images.
Features
- Ephemeral VMs: Launch temporary VMs from bootc containers without root
- Disk Images: Create bootable disk images in various formats
- libvirt Integration: Manage persistent VMs with full lifecycle control
- Image Management: Discover and list bootc container images
Use Cases
- Testing bootc images quickly in VM environments
- Creating disk images for cloud or bare-metal deployment
- CI/CD integration for automated testing
- Development with isolated VM environments
See the Quick Start Guide to get started.
Installation
From Packages
bcvk is available in Fedora 42+ and EPEL 9/10:
sudo dnf install bcvk
Prerequisites
Required:
- Rust
- Git
- QEMU/KVM
- virtiofsd
- Podman
Optional:
- libvirt (for persistent VM features)
sudo systemctl enable --now libvirtd sudo usermod -a -G libvirt $USER
Development Binaries
Pre-built binaries from main are available as OCI artifacts:
# Requires ORAS (https://oras.land/)
# Note: This command pulls the x86_64 architecture binary
oras pull ghcr.io/bootc-dev/bcvk-binary:x86_64-latest
tar -xzf bcvk-x86_64-unknown-linux-gnu.tar.gz
sudo install -m 755 bcvk-x86_64-unknown-linux-gnu /usr/local/bin/bcvk
Building from Source
Without cloning the repo:
cargo install --locked --git https://github.com/bootc-dev/bcvk bcvk
Inside a clone of the repo:
cargo install --locked --path crates/kit
Platform Support
- Linux: Supported
- macOS: Not supported, use podman-bootc
- Windows: Not supported
See the Quick Start Guide to begin using bcvk.
Quick Start
Prerequisites
- bcvk installed (see Installation Guide)
- podman
- QEMU/KVM
- A bootc container image
Your First VM
bcvk ephemeral run-ssh quay.io/fedora/fedora-bootc:42
This starts a VM and automatically SSHs into it. The VM terminates when you exit the SSH session.
Ephemeral VMs
# Start a background VM with auto-cleanup
bcvk ephemeral run -d --rm -K --name mytestvm quay.io/fedora/fedora-bootc:42
# SSH into it
bcvk ephemeral ssh mytestvm
Creating Disk Images
# Raw disk image
bcvk to-disk quay.io/centos-bootc/centos-bootc:stream10 /path/to/disk.img
# qcow2 format
bcvk to-disk --format qcow2 quay.io/fedora/fedora-bootc:42 /path/to/fedora.qcow2
# Custom size
bcvk to-disk --size 20G quay.io/fedora/fedora-bootc:42 /path/to/large-disk.img
Persistent VMs with libvirt
# Create and start
bcvk libvirt run --name my-server quay.io/fedora/fedora-bootc:42
# Manage lifecycle
bcvk libvirt ssh my-server
bcvk libvirt stop my-server
bcvk libvirt start my-server
bcvk libvirt list
bcvk libvirt rm my-server
Image Management
# List bootc images
bcvk images list
Resource Configuration
# Ephemeral VM
bcvk ephemeral run --memory 4096 --cpus 4 --name bigvm quay.io/fedora/fedora-bootc:42
# libvirt VM
bcvk libvirt run --name webserver --memory 8192 --cpus 8 --disk-size 50G quay.io/centos-bootc/centos-bootc:stream10
Workflow Comparison
The bootable container ecosystem includes several tools that serve different use cases. Understanding when to use each tool helps you choose the right approach.
Tool Overview
- bootc - Core tool for building and managing bootable container images
- bcvk - Virtualization toolkit for development and testing
- podman-bootc - Podman-integrated solution for cross-platform development
Quick Comparison
| Tool | Best For | Key Strength |
|---|---|---|
| bootc | Production deployment | Direct hardware installation |
| bcvk | Development/testing | Fast VM workflows |
| podman-bootc | Cross-platform dev | Consistent experience |
When to Use bcvk
- Development iteration: Quick testing of container changes
- Linux-focused workflows: Leveraging native virtualization
- Integration testing: Automated VM testing in CI/CD
- Performance testing: Native KVM performance
When to Use Alternatives
- podman-bootc: Cross-platform teams, Podman workflows
- bootc: Production deployment, bare metal installation
Most teams use multiple tools: bcvk for development, bootc for production.
Using bcvk via varlink
bcvk exposes a varlink interface for programmatic access. This is useful for building tooling on top of bcvk without parsing CLI output.
At the current time there are varlink APIs for:
bcvk images-- list bootc image namesbcvk ephemeral-- launch and query ephemeral VMs, get SSH connection infobcvk to-disk-- create bootable disk images
The API is intentionally minimal: it exposes only operations that require
bcvk-specific knowledge. For example, bcvk ephemeral rm-all is not exposed
via varlink because you can do that directly via podman APIs.
Via subprocess
bcvk serves varlink via socket activation. The idea is your higher level tool runs it as a subprocess, passing the socket FD to it.
An example of this with varlinkctl exec::
varlinkctl call exec:bcvk io.bootc.vk.images.List
Introspecting
The varlink API is defined in the source code; to see the version of
the API exposed by the tool, use varlinkctl introspect:
varlinkctl introspect exec:bcvk io.bootc.vk.images
varlinkctl introspect exec:bcvk io.bootc.vk.ephemeral
varlinkctl introspect exec:bcvk io.bootc.vk.todisk
SSH access to ephemeral VMs
After launching a VM with Run(ssh_keygen: true), use GetSshConnectionInfo
to get the connection details:
varlinkctl call exec:bcvk io.bootc.vk.ephemeral.GetSshConnectionInfo \
'{"container_id": "a1b2c3d4..."}'
This returns the container ID, key path, user, host, and port needed
to construct a podman exec ... ssh ... command:
podman exec <container_id> ssh -i <key_path> -p <port> \
-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
<user>@<host> [command...]
NAME
bcvk - A toolkit for bootable containers and (local) virtualization.
SYNOPSIS
bcvk [-h|--help] <subcommands>
DESCRIPTION
bcvk helps launch bootc containers using local virtualization for development and CI workflows. Build containers using your tool of choice (podman, docker, etc), then use bcvk to boot them as virtual machines.
Note: bcvk is designed for local development and CI environments, not for running production servers.
Quick Start
The fastest way to boot a bootc container image is with bcvk ephemeral run-ssh:
bcvk ephemeral run-ssh quay.io/fedora/fedora-bootc:42
This boots the container as a VM and drops you into an SSH session. When you exit the SSH session, the VM is automatically cleaned up.
Build and Test Workflow
A typical development workflow combines container builds with ephemeral VM testing:
# Build your bootc container
podman build -t localhost/myimage .
# Boot it as a VM and SSH in (auto-cleanup on exit)
bcvk ephemeral run-ssh localhost/myimage
# Or run in background for longer testing
bcvk ephemeral run -d --rm -K --name testvm localhost/myimage
bcvk ephemeral ssh testvm
# ... test, then stop the VM when done
podman stop testvm
Ephemeral vs Libvirt
bcvk provides two ways to run bootc containers as VMs:
bcvk ephemeral runs stateless VMs managed by podman. The VM boots directly from the container image's filesystem via virtiofs with no disk image creation, making startup very fast. Ideal for quick iteration and CI pipelines.
bcvk libvirt creates stateful VMs managed by libvirt with persistent disk images. These VMs survive reboots and support the full bootc upgrade workflow. Useful for longer-running local development or testing upgrade scenarios.
SUBCOMMANDS
bcvk-ephemeral(8)
: Manage stateless VMs via podman (fast startup, no disk images)
bcvk-images(8)
: Manage and inspect bootc container images
bcvk-to-disk(8)
: Install bootc images to persistent disk images
bcvk-libvirt(8)
: Manage stateful VMs via libvirt (persistent disk images)
EXAMPLES
Test a public bootc image interactively:
bcvk ephemeral run-ssh quay.io/centos-bootc/centos-bootc:stream10
Build and test a local image:
podman build -t localhost/mybootc .
bcvk ephemeral run-ssh localhost/mybootc
Run a background VM with SSH access:
bcvk ephemeral run -d --rm -K --name dev quay.io/fedora/fedora-bootc:42
bcvk ephemeral ssh dev
Create a libvirt VM with persistent disk:
bcvk libvirt run --name myvm quay.io/centos-bootc/centos-bootc:stream10
bcvk libvirt ssh myvm
SEE ALSO
bcvk-ephemeral(8), bcvk-ephemeral-run(8), bcvk-ephemeral-run-ssh(8), bcvk-libvirt(8), bcvk-to-disk(8), bootc(8)
VERSION
NAME
bcvk-ephemeral - Manage ephemeral VMs for bootc containers
SYNOPSIS
bcvk ephemeral <SUBCOMMAND>
DESCRIPTION
Manage stateless VMs for bootc container images.
Ephemeral VMs are managed by podman and boot directly from the container image's filesystem. Unlike libvirt VMs created with bcvk-libvirt-run(8), ephemeral VMs:
- Boot directly from the container image via virtiofs (no disk image creation)
- Start in seconds rather than minutes
- Are stateless by default - filesystem changes don't persist across restarts
- Are managed via podman - use familiar container tooling
This makes ephemeral VMs ideal for local development, CI pipelines, and any workflow where you want fast iteration without persistent state.
How It Works
Ephemeral VMs use a container-in-container architecture:
- A podman container is launched containing QEMU and virtiofsd
- The bootc container image's filesystem is shared into the VM via virtiofs
- The VM boots using the kernel and initramfs from the container image
- SSH access is provided via dynamically generated keys
The host needs /dev/kvm access and a virtualization stack (qemu, virtiofsd).
SUBCOMMANDS
bcvk-ephemeral-run(8)
: Run a bootc container as an ephemeral VM
bcvk-ephemeral-run-ssh(8)
: Run an ephemeral VM and immediately SSH into it (auto-cleanup on exit)
bcvk-ephemeral-ssh(8)
: SSH into a running ephemeral VM
bcvk-ephemeral-ps(8)
: List running ephemeral VMs
bcvk-ephemeral-rm-all(8)
: Remove all ephemeral VM containers
EXAMPLES
Quick Interactive Session
The simplest way to boot a bootc image is run-ssh, which starts the VM and drops you into an SSH session. When you exit, the VM is cleaned up:
bcvk ephemeral run-ssh quay.io/fedora/fedora-bootc:42
Build and Test Workflow
A typical development loop combines podman build with ephemeral testing:
# Edit your Containerfile
vim Containerfile
# Build the image
podman build -t localhost/mybootc .
# Test it immediately
bcvk ephemeral run-ssh localhost/mybootc
# Iterate: edit, build, test again
podman build -t localhost/mybootc . && bcvk ephemeral run-ssh localhost/mybootc
Background VM with SSH Access
For longer sessions or when you need to reconnect, run the VM in the background:
# Start VM in background with SSH keys and auto-cleanup
bcvk ephemeral run -d --rm -K --name testvm quay.io/fedora/fedora-bootc:42
# SSH into it (can reconnect multiple times)
bcvk ephemeral ssh testvm
# Run commands directly
bcvk ephemeral ssh testvm 'systemctl status'
# Stop when done (--rm ensures cleanup)
podman stop testvm
Development VM with Host Directory Access
Mount your source code into the VM for development:
bcvk ephemeral run -d --rm -K \
--bind /home/user/project:project \
--name devvm localhost/mybootc
bcvk ephemeral ssh devvm
# Inside VM: cd /run/virtiofs-mnt-project
Resource Customization
Allocate more resources for heavy workloads:
bcvk ephemeral run-ssh --memory 8G --vcpus 4 localhost/mybootc
Or use instance types:
bcvk ephemeral run-ssh --itype u1.medium localhost/mybootc
SEE ALSO
bcvk(8), bcvk-ephemeral-run(8), bcvk-ephemeral-run-ssh(8), bcvk-ephemeral-ssh(8), bcvk-libvirt(8)
VERSION
NAME
bcvk-ephemeral-run - Run bootc containers as stateless VMs
SYNOPSIS
bcvk ephemeral run [OPTIONS] IMAGE
DESCRIPTION
Run bootc containers as stateless VMs managed by podman. The VM boots directly from the container image's filesystem via virtiofs, with no disk image creation required. This makes startup fast and the VM stateless by default.
How It Works
This command creates an ephemeral virtual machine by launching a podman container that contains and runs QEMU. The process works as follows:
- Container Setup: A privileged podman container is launched with access to the host's virtualization infrastructure
- Host Virtualization Access: The container gains access to:
/dev/kvmfor hardware virtualization- Host's virtiofsd daemon for filesystem sharing
- QEMU binaries and virtualization stack
- VM Creation: Inside the container, QEMU is executed to create a virtual machine
- Root Filesystem: The bootc container image's root filesystem becomes the VM's root filesystem, mounted via virtiofs
- Kernel Boot: The VM boots using the kernel and initramfs from the bootc container image
This architecture provides several advantages:
- Isolation: The VM runs in a contained environment separate from the host
- Fast I/O: virtiofs provides efficient filesystem access between container and VM
- Resource Efficiency: Leverages existing container infrastructure while providing full VM capabilities
Container-VM Relationship
The relationship between the podman container and the VM inside it:
- Podman Container: Acts as the virtualization environment, providing QEMU and system services
- QEMU Process: Runs inside the podman container, creating the actual virtual machine
- VM Guest: The bootc container image runs as a complete operating system inside the VM
- Filesystem Sharing: The container's root filesystem is shared with the VM via virtiofs at runtime
This design allows bcvk to provide VM-like isolation and boot behavior while leveraging container tooling.
OPTIONS
IMAGE
Container image to run as ephemeral VM
This argument is required.
--itype=ITYPE
Instance type (e.g., u1.nano, u1.small, u1.medium). Overrides vcpus/memory if specified.
--memory=MEMORY
Memory size (e.g. 4G, 2048M, or plain number for MB)
Default: 4G
--vcpus=VCPUS
Number of vCPUs (overridden by --itype if specified)
--console
Connect the QEMU console to the container's stdio (visible via podman logs/attach)
--debug
Enable debug mode (drop to shell instead of running QEMU)
--virtio-serial-out=NAME:FILE
Add virtio-serial device with output to file (format: name:/path/to/file)
--execute=EXECUTE
Execute command inside VM via systemd and capture output
-K, --ssh-keygen
Generate SSH keypair and inject via systemd credentials
-t, --tty
Allocate a pseudo-TTY for container
-i, --interactive
Keep STDIN open for container
-d, --detach
Run container in background
--rm
Automatically remove container when it exits
--name=NAME
Assign a name to the container
--network=NETWORK
Configure the network for the container
--label=LABEL
Add metadata to the container in key=value form
-e, --env=ENV
Set environment variables in the container (key=value)
--debug-entrypoint=DEBUG_ENTRYPOINT
Do not run the default entrypoint directly, but instead invoke the provided command (e.g. `bash`)
--bind=HOST_PATH[:NAME]
Bind mount host directory (RW) at /run/virtiofs-mnt-<name>
--ro-bind=HOST_PATH[:NAME]
Bind mount host directory (RO) at /run/virtiofs-mnt-<name>
--systemd-units=SYSTEMD_UNITS_DIR
Directory with systemd units to inject (expects system/ subdirectory)
--bind-storage-ro
Mount host container storage (RO) at /run/virtiofs-mnt-hoststorage
--add-swap=ADD_SWAP
Allocate a swap device of the provided size
--mount-disk-file=FILE[:NAME]
Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>
--karg=KERNEL_ARGS
Additional kernel command line arguments
EXAMPLES
Build and Test Workflow
The most common use case is testing container images you're building:
# Build your bootc container image
podman build -t localhost/mybootc .
# Run it as an ephemeral VM (background, auto-cleanup, SSH keys)
bcvk ephemeral run -d --rm -K --name test localhost/mybootc
# SSH in to verify it works
bcvk ephemeral ssh test
# Stop when done (container auto-removed due to --rm)
podman stop test
For a faster iteration loop, use bcvk-ephemeral-run-ssh(8) which combines run and SSH into one command with automatic cleanup.
Common Flag Combinations
Testing a public image:
bcvk ephemeral run -d --rm -K --name testvm quay.io/fedora/fedora-bootc:42
bcvk ephemeral ssh testvm
Development with mounted source code:
bcvk ephemeral run -d --rm -K \
--bind /home/user/project:src \
--name devvm localhost/mybootc
bcvk ephemeral ssh devvm
# Files available at /run/virtiofs-mnt-src inside VM
Resource-intensive workloads:
bcvk ephemeral run -d --rm -K \
--memory 8G --vcpus 4 \
--name bigvm localhost/mybootc
Debugging boot issues:
bcvk ephemeral run --console --name debugvm localhost/mybootc
Understanding the Flags
-d, --detach: Run in background. Without this, the container runs in foreground and you see QEMU output directly.
--rm: Auto-remove the container when it stops. Highly recommended for ephemeral testing to avoid accumulating stopped containers.
-K, --ssh-keygen: Generate SSH keypair and inject into the VM via systemd credentials. Required for bcvk ephemeral ssh to work.
--name: Assign a name for easy reference with other commands like bcvk ephemeral ssh.
Bind Mounts
Share host directories with the VM using --bind or --ro-bind:
# Read-write mount
bcvk ephemeral run -d --rm -K --bind /host/path:name --name vm image
# Inside VM, access at:
/run/virtiofs-mnt-name
# Read-only mount (safer for sensitive data)
bcvk ephemeral run -d --rm -K --ro-bind /etc/myconfig:config --name vm image
Disk File Mounts
Mount raw disk images as block devices:
# Create a test disk
truncate -s 10G /tmp/testdisk.raw
# Mount into VM
bcvk ephemeral run -d --rm -K \
--mount-disk-file /tmp/testdisk.raw:testdisk \
--name vm localhost/mybootc
# Inside VM: /dev/disk/by-id/virtio-testdisk
Port Forwarding
For SSH port forwarding (recommended), use bcvk ephemeral ssh with -L or -R:
# Forward VM port 80 to localhost:8080
bcvk ephemeral ssh myvm -L 8080:localhost:80
For network-level port forwarding via podman, configure slirp4netns:
bcvk ephemeral run -d --rm -K \
--network slirp4netns:port_handler=slirp4netns,allow_host_loopback=true \
--name webvm localhost/mybootc
Instance Types
Use predefined instance types for consistent resource allocation:
bcvk ephemeral run -d --rm -K --itype u1.small --name vm localhost/mybootc
bcvk ephemeral run -d --rm -K --itype u1.medium --name vm localhost/mybootc
bcvk ephemeral run -d --rm -K --itype u1.large --name vm localhost/mybootc
DEBUGGING
When troubleshooting ephemeral VM issues, bcvk provides several debugging logs that can be accessed from within the container.
Guest Journal Log
The systemd journal from the guest VM is automatically streamed to /run/journal.log inside the container. This log captures all boot messages, service startup events, and system errors from the VM's perspective.
To view the journal log:
# For a running detached VM
podman exec <container-id> tail -f /run/journal.log
# View specific systemd service messages
podman exec <container-id> grep "dbus-broker" /run/journal.log
# Save journal for offline analysis
podman exec <container-id> cat /run/journal.log > guest-journal.log
The journal log is particularly useful for:
- Diagnosing boot failures and systemd service issues
- Investigating permission denied errors
- Understanding VM initialization problems
- Debugging network and device configuration
Virtiofsd Logs
The virtiofsd daemon logs are written to /run/virtiofsd.log and /run/virtiofsd-<mount-name>.log for each filesystem mount. These logs show filesystem sharing operations between the container and VM.
To view virtiofsd logs:
# Main virtiofsd log
podman exec <container-id> cat /run/virtiofsd.log
# Logs for additional bind mounts
podman exec <container-id> cat /run/virtiofsd-workspace.log
Virtiofsd logs are helpful for:
- Debugging filesystem access issues
- Understanding file handle support warnings
- Investigating mount-related errors
SEE ALSO
bcvk(8)
VERSION
NAME
bcvk-ephemeral-ssh - Connect to running VMs via SSH
SYNOPSIS
bcvk ephemeral ssh CONTAINER_NAME [SSH_ARGS]
DESCRIPTION
Connect to a running ephemeral VM via SSH. This command locates the VM's SSH port and connects using the SSH key that was injected when the VM was started with -K or --ssh-keygen.
Prerequisites
The target VM must have been started with SSH key injection:
bcvk ephemeral run -d --rm -K --name myvm image
Without -K, the VM will not have SSH keys configured and this command will fail to authenticate.
How It Works
- Queries the podman container to find the VM's SSH port
- Retrieves the SSH private key from the container
- Connects using the dynamically assigned port and key
- Passes any additional arguments to the ssh client
VM Lifecycle
SSH connections do not affect the VM lifecycle for background VMs:
- Background VMs (started with -d): Continue running after SSH disconnect. You can reconnect as many times as needed.
- Auto-cleanup VMs (started with --rm): Container is removed when the VM stops, but SSH disconnect alone does not stop the VM.
To stop a background VM, use podman stop.
For automatic cleanup on SSH exit, use bcvk-ephemeral-run-ssh(8) instead.
OPTIONS
CONTAINER_NAME
Name or ID of the container running the target VM
This argument is required.
ARGS
SSH arguments like -v, -L, -o
EXAMPLES
Basic Connection
Connect to a running VM:
bcvk ephemeral ssh myvm
Running Remote Commands
Execute a command directly:
bcvk ephemeral ssh myvm 'systemctl status'
Check disk usage:
bcvk ephemeral ssh myvm 'df -h'
View journal logs:
bcvk ephemeral ssh myvm 'journalctl -f'
SSH Options
Enable verbose output for debugging connection issues:
bcvk ephemeral ssh myvm -v
Forward a local port to the VM:
bcvk ephemeral ssh myvm -L 8080:localhost:80
# Access VM's port 80 at localhost:8080
Reverse port forwarding (expose host port to VM):
bcvk ephemeral ssh myvm -R 3000:localhost:3000
Typical Workflow
# Start a VM in the background
bcvk ephemeral run -d --rm -K --name testvm quay.io/fedora/fedora-bootc:42
# Connect and do some work
bcvk ephemeral ssh testvm
# ... interactive session ...
# exit
# Reconnect later
bcvk ephemeral ssh testvm
# Run a quick command without interactive session
bcvk ephemeral ssh testvm 'cat /etc/os-release'
# Stop the VM when done
podman stop testvm
File Transfer
Use scp-style operations by getting the SSH details:
# For now, use podman exec for file transfer
podman cp localfile testvm:/path/in/container
# Or mount a shared directory when starting the VM
bcvk ephemeral run -d --rm -K --bind /host/path:shared --name vm image
TROUBLESHOOTING
Connection refused: The VM may still be booting. Wait a few seconds and retry.
Permission denied: Ensure the VM was started with -K for SSH key injection.
Host key verification failed: Each VM gets a unique host key. Use -o StrictHostKeyChecking=no if needed.
SEE ALSO
bcvk(8), bcvk-ephemeral(8), bcvk-ephemeral-run(8), bcvk-ephemeral-run-ssh(8), ssh(1)
VERSION
NAME
bcvk-ephemeral-run-ssh - Run ephemeral VM and SSH into it
SYNOPSIS
bcvk ephemeral run-ssh [OPTIONS] IMAGE [SSH_ARGS]
DESCRIPTION
Run a bootc container as an ephemeral VM and immediately connect via SSH. When the SSH session ends, the VM is automatically stopped and cleaned up.
This is the recommended command for quick testing and iteration. It combines bcvk ephemeral run and bcvk ephemeral ssh into a single command with automatic lifecycle management.
Lifecycle Behavior
Unlike bcvk ephemeral run -d which starts a background VM that persists until explicitly stopped, run-ssh ties the VM lifecycle to the SSH session:
- VM boots and waits for SSH to become available
- SSH session is established
- When you exit the SSH session (or the connection drops), the VM is stopped
- The container is automatically removed
This makes run-ssh ideal for:
- Quick one-off testing of container images
- Rapid build-test iteration cycles
- Running a single command in a VM environment
- Demos and exploration
For longer-running VMs where you need to reconnect multiple times, use bcvk ephemeral run -d --rm -K instead.
OPTIONS
IMAGE
Container image to run as ephemeral VM
This argument is required.
SSH_ARGS
SSH command to execute (optional, defaults to interactive shell)
--itype=ITYPE
Instance type (e.g., u1.nano, u1.small, u1.medium). Overrides vcpus/memory if specified.
--memory=MEMORY
Memory size (e.g. 4G, 2048M, or plain number for MB)
Default: 4G
--vcpus=VCPUS
Number of vCPUs (overridden by --itype if specified)
--console
Connect the QEMU console to the container's stdio (visible via podman logs/attach)
--debug
Enable debug mode (drop to shell instead of running QEMU)
--virtio-serial-out=NAME:FILE
Add virtio-serial device with output to file (format: name:/path/to/file)
--execute=EXECUTE
Execute command inside VM via systemd and capture output
-K, --ssh-keygen
Generate SSH keypair and inject via systemd credentials
-t, --tty
Allocate a pseudo-TTY for container
-i, --interactive
Keep STDIN open for container
-d, --detach
Run container in background
--rm
Automatically remove container when it exits
--name=NAME
Assign a name to the container
--network=NETWORK
Configure the network for the container
--label=LABEL
Add metadata to the container in key=value form
-e, --env=ENV
Set environment variables in the container (key=value)
--debug-entrypoint=DEBUG_ENTRYPOINT
Do not run the default entrypoint directly, but instead invoke the provided command (e.g. `bash`)
--bind=HOST_PATH[:NAME]
Bind mount host directory (RW) at /run/virtiofs-mnt-<name>
--ro-bind=HOST_PATH[:NAME]
Bind mount host directory (RO) at /run/virtiofs-mnt-<name>
--systemd-units=SYSTEMD_UNITS_DIR
Directory with systemd units to inject (expects system/ subdirectory)
--bind-storage-ro
Mount host container storage (RO) at /run/virtiofs-mnt-hoststorage
--add-swap=ADD_SWAP
Allocate a swap device of the provided size
--mount-disk-file=FILE[:NAME]
Mount disk file as virtio-blk device at /dev/disk/by-id/virtio-<name>
--karg=KERNEL_ARGS
Additional kernel command line arguments
EXAMPLES
Basic Usage
Test a public bootc image:
bcvk ephemeral run-ssh quay.io/fedora/fedora-bootc:42
Test a CentOS bootc image:
bcvk ephemeral run-ssh quay.io/centos-bootc/centos-bootc:stream10
Build and Test Workflow
The most common development pattern is building and immediately testing:
# Build your container
podman build -t localhost/mybootc .
# Boot it and SSH in (auto-cleanup on exit)
bcvk ephemeral run-ssh localhost/mybootc
For rapid iteration, combine in one command:
podman build -t localhost/mybootc . && bcvk ephemeral run-ssh localhost/mybootc
Running Commands
Execute a specific command and exit:
bcvk ephemeral run-ssh localhost/mybootc 'systemctl status'
Check what services are running:
bcvk ephemeral run-ssh localhost/mybootc 'systemctl list-units --type=service --state=running'
Verify your custom configuration:
bcvk ephemeral run-ssh localhost/mybootc 'cat /etc/myapp/config.yaml'
Resource Allocation
For memory-intensive testing:
bcvk ephemeral run-ssh --memory 8G --vcpus 4 localhost/mybootc
Using instance types:
bcvk ephemeral run-ssh --itype u1.medium localhost/mybootc
With Bind Mounts
Mount source code for testing:
bcvk ephemeral run-ssh --bind /home/user/project:src localhost/mybootc
# Inside VM: ls /run/virtiofs-mnt-src
Debugging
Enable console output to see boot messages:
bcvk ephemeral run-ssh --console localhost/mybootc
TIPS
-
Fast iteration: Keep your container builds small and layered for faster rebuilds. The VM boots in seconds, so the container build is usually the bottleneck.
-
SSH arguments: Any arguments after the image name are passed to SSH. Use this for commands, port forwarding, or SSH options.
-
Exit cleanly: Use
exitor Ctrl+D to cleanly end the SSH session and trigger VM cleanup. Ctrl+C may not clean up properly.
SEE ALSO
bcvk(8), bcvk-ephemeral(8), bcvk-ephemeral-run(8), bcvk-ephemeral-ssh(8)
VERSION
NAME
bcvk-to-disk - Install bootc images to persistent disk images
SYNOPSIS
bcvk to-disk [-h|--help] [OPTIONS] IMAGE
DESCRIPTION
Performs automated installation of bootc containers to disk images using ephemeral VMs as the installation environment. Supports multiple filesystems, custom sizing, and creates bootable disk images ready for production deployment.
The installation process:
- Creates a new disk image with the specified filesystem layout
- Boots an ephemeral VM with the target container image
- Runs `bootc install to-disk` within the VM to install to the disk
- Produces a bootable disk image that can be deployed anywhere
OPTIONS
SOURCE_IMAGE
Container image to install
This argument is required.
TARGET_DISK
Target disk/device path
This argument is required.
--filesystem=FILESYSTEM
Root filesystem type (e.g. ext4, xfs, btrfs)
--root-size=ROOT_SIZE
Root filesystem size (e.g., '10G', '5120M')
--storage-path=STORAGE_PATH
Path to host container storage (auto-detected if not specified)
--target-transport=TARGET_TRANSPORT
The transport; e.g. oci, oci-archive, containers-storage. Defaults to `registry`
--karg=KARG
Set a kernel argument
--composefs-backend
Default to composefs-native storage
--bootloader=BOOTLOADER
Which bootloader to use for composefs-native backend
--allow-missing-fsverity
Allow installation without fs-verity support for composefs-native backend
--disk-size=DISK_SIZE
Disk size to create (e.g. 10G, 5120M, or plain number for bytes)
--format=FORMAT
Output disk image format
Possible values:
- raw
- qcow2
Default: raw
--itype=ITYPE
Instance type (e.g., u1.nano, u1.small, u1.medium). Overrides vcpus/memory if specified.
--memory=MEMORY
Memory size (e.g. 4G, 2048M, or plain number for MB)
Default: 4G
--vcpus=VCPUS
Number of vCPUs (overridden by --itype if specified)
--console
Connect the QEMU console to the container's stdio (visible via podman logs/attach)
--debug
Enable debug mode (drop to shell instead of running QEMU)
--virtio-serial-out=NAME:FILE
Add virtio-serial device with output to file (format: name:/path/to/file)
--execute=EXECUTE
Execute command inside VM via systemd and capture output
-K, --ssh-keygen
Generate SSH keypair and inject via systemd credentials
--install-log=INSTALL_LOG
Configure logging for `bootc install` by setting the `RUST_LOG` environment variable
--label=LABEL
Add metadata to the container in key=value form
--dry-run
Check if the disk would be regenerated without actually creating it
ARGUMENTS
IMAGE
: Container image reference to install (e.g., `registry.example.com/my-bootc:latest`)
EXAMPLES
Create a raw disk image:
bcvk to-disk quay.io/centos-bootc/centos-bootc:stream10 /path/to/disk.img
Create a qcow2 disk image (more compact):
bcvk to-disk --format qcow2 quay.io/fedora/fedora-bootc:42 /path/to/fedora.qcow2
Create with specific disk size:
bcvk to-disk --disk-size 20G quay.io/fedora/fedora-bootc:42 /path/to/large-disk.img
Create with custom filesystem and root size:
bcvk to-disk --filesystem btrfs --root-size 15G quay.io/fedora/fedora-bootc:42 /path/to/btrfs-disk.img
Development workflow - test then create deployment image:
# Test the container as a VM first
bcvk ephemeral run-ssh my-app
# If good, create the deployment image
bcvk to-disk my-app /tmp/my-app.img
VERSION
v0.1.0
NAME
bcvk-images - Manage and inspect bootc container images
SYNOPSIS
bcvk images [OPTIONS]
DESCRIPTION
Manage and inspect bootc container images
SUBCOMMANDS
bcvk-images-list(8)
: List available bootc images
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
v0.1.0
NAME
bcvk-images-list - List all available bootc container images on the system
SYNOPSIS
bcvk images list [OPTIONS]
DESCRIPTION
List all available bootc container images on the system
OPTIONS
--json
Output as structured JSON instead of table format
EXAMPLES
List all bootc images (those with containers.bootc=1 label):
bcvk images list
Get structured JSON output for scripting:
bcvk images list --json
Find available bootc containers on your system:
# This helps you find available bootc containers before running VMs
bcvk images list
SEE ALSO
bcvk(8)
VERSION
v0.1.0
NAME
bcvk-libvirt - Manage libvirt integration for bootc containers
SYNOPSIS
bcvk libvirt [-h|--help] <subcommands>
DESCRIPTION
Comprehensive libvirt integration with subcommands for uploading disk images, creating domains, and managing bootc containers as libvirt VMs.
This command provides seamless integration between bcvk disk images and libvirt virtualization infrastructure, enabling:
- Upload of disk images to libvirt storage pools
- Creation of libvirt domains with appropriate bootc annotations
- Management of VM lifecycle through libvirt
- Integration with existing libvirt-based infrastructure
OPTIONS
-c, --connect=CONNECT
Hypervisor connection URI (e.g., qemu:///system, qemu+ssh://host/system)
SUBCOMMANDS
bcvk-libvirt-upload(8)
: Upload bootc disk images to libvirt storage pools
bcvk-libvirt-create(8)
: Create libvirt domains from bootc disk images
bcvk-libvirt-list(8)
: List bootc-related libvirt domains and storage
bcvk-libvirt-help(8)
: Print this message or the help of the given subcommand(s)
VERSION
v0.1.0
NAME
bcvk-libvirt-run - Run a bootable container as a persistent VM
SYNOPSIS
bcvk libvirt run [OPTIONS]
DESCRIPTION
Run a bootable container as a persistent VM
OPTIONS
IMAGE
Container image to run as a bootable VM
This argument is required.
--name=NAME
Name for the VM (auto-generated if not specified)
-R, --replace
Replace existing VM with same name (stop and remove if exists)
--itype=ITYPE
Instance type (e.g., u1.nano, u1.small, u1.medium). Overrides cpus/memory if specified.
--memory=MEMORY
Memory size (e.g. 4G, 2048M, or plain number for MB)
Default: 4G
--cpus=CPUS
Number of virtual CPUs for the VM (overridden by --itype if specified)
Default: 2
--disk-size=DISK_SIZE
Disk size for the VM (e.g. 20G, 10240M, or plain number for bytes)
Default: 20G
--filesystem=FILESYSTEM
Root filesystem type (e.g. ext4, xfs, btrfs)
--root-size=ROOT_SIZE
Root filesystem size (e.g., '10G', '5120M')
--storage-path=STORAGE_PATH
Path to host container storage (auto-detected if not specified)
--target-transport=TARGET_TRANSPORT
The transport; e.g. oci, oci-archive, containers-storage. Defaults to `registry`
--karg=KARG
Set a kernel argument
--composefs-backend
Default to composefs-native storage
--bootloader=BOOTLOADER
Which bootloader to use for composefs-native backend
--allow-missing-fsverity
Allow installation without fs-verity support for composefs-native backend
-p, --port=PORT_MAPPINGS
Port mapping from host to VM (format: host_port:guest_port, e.g., 8080:80)
-v, --volume=RAW_VOLUMES
Volume mount from host to VM (raw virtiofs tag, for manual mounting)
--bind=BIND_MOUNTS
Bind mount from host to VM (format: host_path:guest_path)
--bind-ro=BIND_MOUNTS_RO
Bind mount from host to VM as read-only (format: host_path:guest_path)
--network=NETWORK
Network mode for the VM
Default: user
--detach
Keep the VM running in background after creation
--ssh
Automatically SSH into the VM after creation
--ssh-wait
Wait for SSH to become available and verify connectivity (for testing)
--bind-storage-ro
Mount host container storage (RO) at /run/host-container-storage
--update-from-host
Implies --bind-storage-ro, but also configure to update from the host container storage by default
--firmware=FIRMWARE
Firmware type for the VM (defaults to uefi-secure)
Possible values:
- uefi-secure
- uefi-insecure
- bios
Default: uefi-secure
--disable-tpm
Disable TPM 2.0 support (enabled by default)
--secure-boot-keys=SECURE_BOOT_KEYS
Directory containing secure boot keys (required for uefi-secure)
--label=LABEL
User-defined labels for organizing VMs (comma not allowed in labels)
--transient
Create a transient VM that disappears on shutdown/reboot
EXAMPLES
Create and start a persistent VM:
bcvk libvirt run --name my-server quay.io/fedora/fedora-bootc:42
Create a VM with custom resources:
bcvk libvirt run --name webserver --memory 8192 --cpus 8 --disk-size 50G quay.io/centos-bootc/centos-bootc:stream10
Create a VM with port forwarding:
bcvk libvirt run --name webserver --port 8080:80 quay.io/centos-bootc/centos-bootc:stream10
Create a VM with volume mount:
bcvk libvirt run --name devvm --volume /home/user/code:/workspace quay.io/fedora/fedora-bootc:42
Create a VM and automatically SSH into it:
bcvk libvirt run --name testvm --ssh quay.io/fedora/fedora-bootc:42
Create a VM with access to host container storage for bootc upgrade:
bcvk libvirt run --name upgrade-test --bind-storage-ro quay.io/fedora/fedora-bootc:42
Server management workflow:
# Create a persistent server VM
bcvk libvirt run --name production-server --memory 8192 --cpus 4 --disk-size 100G my-server-image
# Check status
bcvk libvirt list
# Access for maintenance
bcvk libvirt ssh production-server
SEE ALSO
bcvk(8)
VERSION
v0.1.0
NAME
bcvk-libvirt-list - List available bootc volumes with metadata
SYNOPSIS
bcvk libvirt list [DOMAIN_NAME] [OPTIONS]
DESCRIPTION
List available bootc domains with metadata. When a domain name is provided, returns information about that specific domain only.
When using --format=json with a specific domain name, the output is a single JSON object (not an array), making it easy to extract SSH credentials and connection information using tools like jq.
OPTIONS
DOMAIN_NAME
Optional domain name to query. When specified, returns information about only this domain.
OPTIONS
DOMAIN_NAME
Domain name to query (returns only this domain)
--format=FORMAT
Output format
Possible values:
- table
- json
- yaml
- xml
Default: table
-a, --all
Show all domains including stopped ones
--label=LABEL
Filter domains by label
EXAMPLES
List all running bootc VMs:
bcvk libvirt list
List all bootc VMs including stopped ones:
bcvk libvirt list --all
Show VM status in your workflow:
# Check what VMs are running
bcvk libvirt list
# Start a specific VM if needed
bcvk libvirt start my-server
Query a specific domain:
bcvk libvirt list my-domain
Working with SSH credentials via JSON output
Connect via SSH using extracted credentials:
# Query once, save to file, then extract credentials
DOMAIN_NAME="mydomain"
# Query domain info once and save to file
bcvk libvirt list $DOMAIN_NAME --format=json > /tmp/domain-info.json
# Extract SSH private key
jq -r '.ssh_private_key' /tmp/domain-info.json > /tmp/key.pem
chmod 600 /tmp/key.pem
# Extract SSH port
SSH_PORT=$(jq -r '.ssh_port' /tmp/domain-info.json)
# Connect via SSH
ssh -o IdentitiesOnly=yes -i /tmp/key.pem -p $SSH_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@127.0.0.1
# Cleanup
rm /tmp/domain-info.json /tmp/key.pem
This is useful for automation scripts or when you need direct SSH access without using bcvk libvirt ssh.
SEE ALSO
bcvk(8)
VERSION
v0.1.0
NAME
bcvk-libvirt-ssh - SSH to libvirt domain with embedded SSH key
SYNOPSIS
bcvk libvirt ssh [OPTIONS]
DESCRIPTION
SSH to libvirt domain with embedded SSH key
OPTIONS
DOMAIN_NAME
Name of the libvirt domain to connect to
This argument is required.
COMMAND
Command to execute on remote host
--user=USER
SSH username to use for connection (defaults to 'root')
Default: root
--strict-host-keys
Use strict host key checking
--timeout=TIMEOUT
SSH connection timeout in seconds
Default: 5
--log-level=LOG_LEVEL
SSH log level
Default: ERROR
--extra-options=EXTRA_OPTIONS
Extra SSH options in key=value format
EXAMPLES
SSH into a running libvirt VM:
bcvk libvirt ssh my-server
Execute a command on the VM:
bcvk libvirt ssh my-server 'systemctl status'
SSH with a specific user:
bcvk libvirt ssh --user admin my-server
Connect to a VM with extended timeout:
bcvk libvirt ssh --timeout 60 my-server
SEE ALSO
bcvk(8)
VERSION
v0.1.0
NAME
bcvk-libvirt-stop - Stop a running libvirt domain
SYNOPSIS
bcvk libvirt stop [OPTIONS]
DESCRIPTION
Stop a running libvirt domain
OPTIONS
NAME
Name of the domain to stop
This argument is required.
-f, --force
Force stop the domain
--timeout=TIMEOUT
Timeout in seconds for graceful shutdown
Default: 60
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
NAME
bcvk-libvirt-start - Start a stopped libvirt domain
SYNOPSIS
bcvk libvirt start [OPTIONS]
DESCRIPTION
Start a stopped libvirt domain
OPTIONS
NAME
Name of the domain to start
This argument is required.
--ssh
Automatically SSH into the domain after starting
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
NAME
bcvk-libvirt-inspect - Show detailed information about a libvirt domain
SYNOPSIS
bcvk libvirt inspect [OPTIONS]
DESCRIPTION
Show detailed information about a libvirt domain
OPTIONS
NAME
Name of the domain to inspect
This argument is required.
--format=FORMAT
Output format
Possible values:
- table
- json
- yaml
- xml
Default: yaml
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
NAME
bcvk-libvirt-rm - Remove a libvirt domain and its resources
SYNOPSIS
bcvk libvirt rm [OPTIONS]
DESCRIPTION
Remove a libvirt domain and its resources
OPTIONS
NAME
Name of the domain to remove
This argument is required.
-f, --force
Force removal without confirmation (also stops running VMs)
--stop
Stop domain if it's running (implied by --force)
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
NAME
bcvk-libvirt-upload - Upload bootc disk images to libvirt with metadata annotations
SYNOPSIS
bcvk libvirt upload [OPTIONS]
DESCRIPTION
Upload bootc disk images to libvirt with metadata annotations
OPTIONS
SOURCE_IMAGE
Container image to install and upload
This argument is required.
--volume-name=VOLUME_NAME
Name for the libvirt volume (defaults to sanitized image name)
--pool=POOL
Libvirt storage pool name
Default: default
--disk-size=DISK_SIZE
Size of the disk image (e.g., '20G', '10240M'). If not specified, uses the actual size of the created disk
--filesystem=FILESYSTEM
Root filesystem type (e.g. ext4, xfs, btrfs)
--root-size=ROOT_SIZE
Root filesystem size (e.g., '10G', '5120M')
--storage-path=STORAGE_PATH
Path to host container storage (auto-detected if not specified)
--target-transport=TARGET_TRANSPORT
The transport; e.g. oci, oci-archive, containers-storage. Defaults to `registry`
--karg=KARG
Set a kernel argument
--composefs-backend
Default to composefs-native storage
--bootloader=BOOTLOADER
Which bootloader to use for composefs-native backend
--allow-missing-fsverity
Allow installation without fs-verity support for composefs-native backend
--memory=MEMORY
Memory size (e.g. 4G, 2048M, or plain number for MB)
Default: 4G
--vcpus=VCPUS
Number of vCPUs for installation VM
EXAMPLES
TODO: Add practical examples showing how to use this command.
SEE ALSO
bcvk(8)
VERSION
v0.1.0
libvirt create
HACKING
See ../HACKING.md for development instructions.