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

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

ToolBest ForKey Strength
bootcProduction deploymentDirect hardware installation
bcvkDevelopment/testingFast VM workflows
podman-bootcCross-platform devConsistent 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 names
  • bcvk ephemeral -- launch and query ephemeral VMs, get SSH connection info
  • bcvk 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:

  1. A podman container is launched containing QEMU and virtiofsd
  2. The bootc container image's filesystem is shared into the VM via virtiofs
  3. The VM boots using the kernel and initramfs from the container image
  4. 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:

  1. Container Setup: A privileged podman container is launched with access to the host's virtualization infrastructure
  2. Host Virtualization Access: The container gains access to:
    • /dev/kvm for hardware virtualization
    • Host's virtiofsd daemon for filesystem sharing
    • QEMU binaries and virtualization stack
  3. VM Creation: Inside the container, QEMU is executed to create a virtual machine
  4. Root Filesystem: The bootc container image's root filesystem becomes the VM's root filesystem, mounted via virtiofs
  5. 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

  1. Queries the podman container to find the VM's SSH port
  2. Retrieves the SSH private key from the container
  3. Connects using the dynamically assigned port and key
  4. 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:

  1. VM boots and waits for SSH to become available
  2. SSH session is established
  3. When you exit the SSH session (or the connection drops), the VM is stopped
  4. 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 exit or 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:

  1. Creates a new disk image with the specified filesystem layout
  2. Boots an ephemeral VM with the target container image
  3. Runs `bootc install to-disk` within the VM to install to the disk
  4. 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.