Skip to content

RFC: Support building ELBE images without initvm#471

Open
koalo wants to merge 12 commits into
Linutronix:masterfrom
koalo:devel/koalo/container
Open

RFC: Support building ELBE images without initvm#471
koalo wants to merge 12 commits into
Linutronix:masterfrom
koalo:devel/koalo/container

Conversation

@koalo

@koalo koalo commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

This is the first attempt to enable building ELBE images without initvm, but instead rootless podman containers.

WARNING: This currently ONLY works for systems with solely ext* partitions (or systems that do not use Grub at all). It will break builds that rely on vfat (efi) partitions! More investigation is needed to find a clean way to avoid losetup for Grub.

koalo added 6 commits July 22, 2026 17:11
e2fsprogs comes with mkfs.ext4 that is needed to populate ext4
filesystems.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
binutils comes with strip that is required by dracut to strip
the initramfs, i.e. to avoid

INFO:soap:dracut[I]: Could not find 'strip'. Not stripping the initramfs.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
elbepack/initvm(action).py currently couples the SOAP submit/download
logic (used by elbe initvm submit) with parts only relevant for the
actual VM initialization. To enable a future command that does not
depend on a VM, extract the parts relevant for both commands into
separate files.

This commit only moves code around. No functional change.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Since the buildsubmitaction.py shall be used also without initvm, drop
all VM-specific wording from the messages.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Add a new top-level "elbe build" command as alternative
to "elbe initvm submit". It automatically starts an elbe daemon
running detached in the background, but not encapsulated into an
initvm. It is meant to be used inside a container that already
provides the required isolation.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
With the recent additions, it is no longer necessary to spawn an initvm
to build ELBE images. Therefore, provide a container that enables this
use case.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
@koalo
koalo force-pushed the devel/koalo/container branch from aa2de9e to b67a433 Compare July 23, 2026 09:38
Comment thread debian/control
android-sdk-libsparse-utils,
arch-test,
binfmt-support,
binutils,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already pulled in via devscripts/dpkg-dev as far as I can see.
Also dracut is not part of the initvm. When dracut is installed in the target, then I don't see why we need binutils in the build environment either.

koalo added 5 commits July 23, 2026 12:08
Adding initvm packages to the CDROMs is not reasonable when there is no
initvm. Therefore, exclude them. Also, provide this option as CLI
parameter (default off) for initvm builds for consistency.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Packages do not necessarily have the origin fully populated.
This is in particular the case when development versions of packages are
installed into a container
(e.g. via contrib/containerfile-vmless/Containerfile.local ).

Therefore, make these entries optional.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Currently, the dump solely considers /etc/apt/sources.list
However, this ignores further content in /etc/apt/sources.list.d/*
and in some systems /etc/apt/sources.list is completely replaced by
files in /etc/apt/sources.list.d/*

Therefore, merge all content of these files before further processing.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
Grub requires to actually access the final file systems to setup itself.
Since we want to avoid losetup as much as possible, use fuse2fs instead.

WARNING: This currently ONLY works for systems with solely ext*
partitions (or systems that do not use Grub at all). It will break
builds that rely on vfat efi partitions!
Provide a test that builds a two step ELBE build for trixie without
using an initvm.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>

from elbepack.tests.test_helpers import elbevalidate # noqa: F401

_WORKDIR_RETENTION = 3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pytest tmpfile fixture already does the same. Why do we need it here again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the pytest tmpfile fixture uses /tmp which is backed by RAM so it is not suitable for storing these huge build artifacts. One could change that via the pytest --basetemp=mydir parameter, but then everyone needs to add that manually when calling pytest or will run into RAM exhaustion. The best alternative would be a per-module rewrite of basetemp, but that does not seem to be possible (without ugly monkeypatching...).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also use it for the initvm created during testing, which is also big.

We can also provide a new fixture which uses TempPathFactory with a different base.

def build_image(self):
print(f'[CONTAINER] Building container image from {self.containerfile_dir}')

original_cwd = os.getcwd()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to change the cwd of the python process.
Use subprocess.run(cwd=).

raise
except Exception as e:
print(f'[CONTAINER] Unexpected error during build: {e}')
raise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the exception is reraised anyways, it's the caller responsibility to log it.

return pathlib.Path(tempfile.mkdtemp(prefix=f'{prefix}-{timestamp}-', dir=root))


class ElbePodmanContainer:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it need to be in conftest.py?
It is only used by a single test file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I would expect that it will be used by more tests in the future when we want to test things both with initvm and containers, but I guess I went a few steps to far with that thought for now. Will reintegrate into the test_build.py.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it would be a fixture in conftest.py but the logic lives somewhere else.

# ResourceWarning. Inhibit this warning: the daemon is meant to keep running
# detached from this process (e.g. to serve subsequent "elbe build"/
# "elbe control" calls in the same container), so it is never wait()ed for.
ps.returncode = 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this scheme of starting and leaving the daemon running in the background.
Instead start it on a random port and shut it down afterwards.

def _free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('127.0.0.1', 0))
return s.getsockname()[1]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ELBE daemon should be able to pick a random port on its own.



@pytest.mark.slow
def test_build_extended_image(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't duplicate the logic from test_xml.py. Instead the build type would be test parameter for the existing tests.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I explicitly wanted to test the base/extended XMLs. And that is also not parametrized in https://github.com/Linutronix/elbe/blob/master/elbepack/tests/test_xml.py#L163
The question remains why I haven't run the full test file set like https://github.com/Linutronix/elbe/blob/master/elbepack/tests/test_xml.py#L121 and the answer is that most still fail mainly due to this Grub Issue...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And that is also not parametrized

Not yet, as there was nothing to parameterize it with so far.

@@ -0,0 +1,59 @@
<!--

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need another test fixture? The existing ones should be good enough.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other ones are bookworm. And I explicitly wanted to test trixie because that is also the basis of the container in contrib/containerfile-vmless/ (and anyway the current stable). Maybe it would be anyway worth to bump all test XMLs to trixie?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be better.

-f Containerfile.local \
-t $(IMAGENAME) ../..

start:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned elsewhere, I want to get away from the whole persistent container idea.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would really love that!
And it is actually also what I am doing in my daily work even when using initvm. I just had doubts if there are use cases by others that rely on a persistent build environments? There are quite a few commands (e.g. the whole elbe control *) that people seem to have wanted to fiddle around after the build was finished.

ps = subprocess.Popen([
sys.executable, '-P', '-m', 'elbepack',
'daemon', '--host', host, '--port', str(port)
])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check if it is feasible to bypass the the whole SOAP thing?
Instead elbe build would directly use the projectmanager. Something like this was done in the past with raw elbe control build, but that needs a few other manual elbe control ... calls for the full cycle.

Document how to use elbe build in a rootless podman container.

Signed-off-by: Florian Kauer <florian.kauer@linutronix.de>
@koalo
koalo force-pushed the devel/koalo/container branch from b67a433 to 0377279 Compare July 23, 2026 10:12
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