Skip to content

Stop using podman for qm - #993

Draft
alexlarsson wants to merge 10 commits into
mainfrom
qm-next
Draft

alexlarsson wants to merge 10 commits into
mainfrom
qm-next

Conversation

@alexlarsson

Copy link
Copy Markdown
Collaborator

This is a major change in how we start the qm container. Instead of using podman + quadlet, we're using a standard systemd qm.service file which starts "qmc launch". qmc is a small C program that generates the required OCI json file (similar to what podman would) in /run/qm/ and starts the container using crun. This lets qm start much faster, earlier and in ways more integrated with the system. The qmc app can be used in the installed image to e.g. run programs in the container (qmc exec bash) and inspect the current status (qmc inspect). This app replaces the old qmctl, even though its not an exact 1-to-1 replacement.

Interesting differences:

  • qm.service starts earlier (before basic.target)
  • qm.service starts before network-online.target, but still updates the resolv.conf in the qm container when it is later updated on the host side.
  • systemd in the qm container reports the sd_notify to the host qm.service when the qm systemd reached the default target (i.e. complete boot) which makes it possible on the host side to depend on a "fully started qm".
  • We run network setup (which is kinda slow) in parallel with the qm container start. Also, there is preparatory work that will allow the host network-online.target to signal the qm container and have its network-online.target follow that.
  • There is no dependency on netavark. Also, we're not using a bridge for the virtual network for the container, just a peer-to-peer veth.
  • The qmc config system support a very useful drop-in system that allows you to easily tweak the things we require in qm without having to change any file. These drop-ins are much more flexible that what we used to have, including things like optional device adding using globs or automatic use of seats. This allows the current oci hook + annotation hacks that we use for things like sound/video/tty to be replaced with simple qmc.conf.d drop ins. Also this should start much faster as we don't have to launch a bunch of processes in these hooks.
  • We now forward the host machine-id to the qm container, which is good now that we fixed the host machine-id to not be transient
  • qm systemd stdout output is visible as the host qm.service journal output, which makes things easier to debug

Note: while I tested and reviewed the main qmc work in another repo pretty carefully, the creation of this qm PR was mostly done by AI, so I marked this as draft, as I need to carefully review it. However, I want this in a PR early so people can look at it, and I can test out the CI changes.

Build the SELinux policy in an isolated build directory and install
the existing scripts, configuration, manuals and qmctl Python
module. Read the project version from VERSION while leaving the
existing Make build available for packaging migration.

Validated Make and Meson staged installs on CentOS Stream 10: existing
files match in content and permissions.

Assisted-by: AI
Use Meson for RPM builds and keep Make as a small developer
wrapper. Include tests in local source archives, align their filenames
with Source0, and build release archives without a Git checkout.

Remove EPEL 9 jobs and legacy policy/setup workarounds. Retain
existing Fedora coverage and subsystem Make entry points.

Validated a source-archive RPM build on CentOS Stream 10 and parsed
the updated Packit configuration.

Assisted-by: AI
Import launcher with layered configuration and OCI base data. Build
the main package for the host architecture with its C dependencies and
normal debuginfo; the existing runtime integration follows in separate
commits.

Assisted-by: AI
Register the existing unittest and C fixtures with Meson and RPM
checks, and build them in CentOS 10 CI. Keep privileged cases visible
as skips; no running QM instance is needed for this suite.

Assisted-by: AI
Install qm.service and matching DNS/hosts watchers in place of the
outer Quadlet. Keep the existing service resource defaults while
adding readiness, delegated payload cgroups and owned-resource
cleanup. Install the host forwarding sysctls with this runtime
conversion.

Assisted-by: AI
Persist custom rootfs and writable paths with matching mount
dependencies, inspect the configured paths for setup and removal, and
stop before removal on configuration errors. Replace Quadlet userns
settings with explicit required/off JSON and test the real script
functions, including repeat calls and error propagation.

Assisted-by: AI
Move KVM/tun, sound, camera and TTY selections to JSON vendor
configuration while keeping application Quadlets inside QM. Update
subsystem archives and RPM payloads, and document explicit
seat/input/render selection. Build all three affected RPMs and verify
their installed merged configuration.

Assisted-by: AI
Port outer QM access and configuration in the existing integration
helpers. Add bounded installed-service and isolated regression
checks. Fix enforcing-SELinux exec streams, scope sysusers to QM
accounts, and map persistent state and rootfs ownership for user
namespaces without changing on-disk IDs.

Assisted-by: AI
Replace the generated outer service directly, preserve activation
during upgrades, and reject leftover Quadlet configuration at startup
with migration instructions. Remove the host Podman requirement and
obsolete CLI packages, enable native QM during setup, and preserve
prepared filesystems on package removal.

Assisted-by: AI
Preserve README topics while updating service, capability and resource
examples. Add user-facing command, configuration and migration
references, build qmc(1) and qmc.conf(5) from the same MkDocs sources,
and port the existing usage, IPC, networking, subsystem and demo
instructions.

Assisted-by: AI
@dougsland

dougsland commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

The code looks good to me, even though this is a fairly large change. I couldn't find anything that caught my attention, particularly from a safety or potential side effects perspective.

We will need time to investigate why the CI/CD pipeline is failing and to perform additional testing locally. These would be good candidates for follow-up Jira tickets.

As a start, I would ask AI to fix the flake8 issues and shellcheck warnings here:
https://github.com/containers/qm/actions/runs/38773586065/job/116555407581?pr=993

Add your DCO too

@dougsland

dougsland commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

The bandit CI/CD failure seems false positive https://github.com/containers/qm/actions/runs/38773585735
One possible solution is ignore the tests dir as it's not a production code for check. Or go file by file and ignore it using # nosec B108 like.

 .github/workflows/bandit
exclude_dirs: ['oci-hooks/tests','tools/tests','tests/qmc']

From:
https://github.com/containers/qm/actions/runs/38773585735

@alexlarsson

Copy link
Copy Markdown
Collaborator Author

I'll have a look at the failures later this week. But, the missing DCO is intentional, as I want to review things more before I sign off.

@dougsland

dougsland commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

I believe worth speak with @pypingou regarding if we want to mimic qmctl commands into qmc as we had a RFE jira about it too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants