[libcamera-ci,RFC,v1,3/5] Add job to build debian rootfs
diff mbox series

Message ID 20260119102039.3521673-4-barnabas.pocze@ideasonboard.com
State Superseded
Headers show
Series
  • on-device-testing proof of concept
Related show

Commit Message

Barnabás Pőcze Jan. 19, 2026, 10:20 a.m. UTC
Add a job that builds a debian rootfs and uploads it to the gitlab container
registry, with the dependencies needed by libcamera created in the
build-debian-cross job.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
---
 .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
 gitlab-ci.yml                     | 47 ++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100755 .gitlab-ci/build-debian-rootfs.sh

--
2.52.0

Comments

Laurent Pinchart Jan. 22, 2026, 2:22 a.m. UTC | #1
On Mon, Jan 19, 2026 at 11:20:37AM +0100, Barnabás Pőcze wrote:
> Add a job that builds a debian rootfs and uploads it to the gitlab container
> registry, with the dependencies needed by libcamera created in the
> build-debian-cross job.

I'm not sure this belongs to the FDO CI. Can't we build this container
locally instead, to avoid consuming CPU and network bandwidth from FDO ?
The Containerfile for this can be stored in a subdirectory of
containers/.

> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> ---
>  .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
>  gitlab-ci.yml                     | 47 ++++++++++++++++++
>  2 files changed, 126 insertions(+)
>  create mode 100755 .gitlab-ci/build-debian-rootfs.sh
> 
> diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
> new file mode 100755
> index 0000000..800ba5f
> --- /dev/null
> +++ b/.gitlab-ci/build-debian-rootfs.sh
> @@ -0,0 +1,79 @@
> +#!/bin/bash
> +# based on https://gitlab.freedesktop.org/freedesktop/ci-templates/-/blob/fb9d50ccb3cbbb4c6dc5f9ef53a0ad3cb0d8a177/bootstrap/cbuild
> +
> +set -ex
> +
> +packages=(
> +	# misc.
> +	ca-certificates
> +	coreutils
> +	chrony
> +	curl
> +	iproute2
> +	kmod
> +	moreutils
> +	openssh-server
> +	v4l-utils
> +	wget
> +
> +	# runtime dependencies
> +	libevent-2.1-7
> +	libevent-pthreads-2.1-7
> +	libpisp1
> +	libssl3t64
> +	libudev1
> +	libyaml-0-2
> +	udev
> +)
> +
> +podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
> +skopeo login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
> +
> +deb_distribution="$1"
> +deb_arch="$2"
> +container_image_path="$3"
> +container_image_tag="$4"
> +overlay_dir="$5"
> +
> +container_image_name="$CI_REGISTRY_IMAGE/$container_image_path:$container_image_tag"
> +
> +if skopeo inspect --no-tags --retry-times 3 "docker://$container_image_name"; then
> +	echo "container image exists"
> +	exit 0
> +fi
> +
> +# TODO: Check if image already exists in the registry of $FDO_UPSTREAM_REPO?
> +
> +newcontainer=$(buildah from scratch)
> +scratchmnt=$(buildah mount "$newcontainer")
> +
> +debootstrap --arch="$deb_arch" --variant=minbase "$deb_distribution" "$scratchmnt"
> +
> +buildah run --isolation=chroot "$newcontainer" apt update -y
> +buildah run --isolation=chroot "$newcontainer" apt install -y --no-install-recommends systemd systemd-sysv
> +buildah run --isolation=chroot "$newcontainer" apt install -y --no-install-recommends "${packages[@]}"
> +buildah run --isolation=chroot "$newcontainer" bash -c 'printf "root\nroot\n" | passwd root'
> +buildah run --isolation=chroot "$newcontainer" bash -c 'echo "PermitRootLogin yes" > /etc/ssh/sshd_config.d/10-allow-root-password.conf'
> +buildah run --isolation=chroot "$newcontainer" apt autoclean -y
> +buildah run --isolation=chroot "$newcontainer" apt autopurge -y
> +
> +buildah run --isolation=chroot "$newcontainer" rm -rf /var/cache/
> +buildah run --isolation=chroot "$newcontainer" rm -rf /var/lib/apt/
> +
> +if [[ -d "$overlay_dir" ]]; then
> +	rsync -av --chown=root:root "$overlay_dir/" "$scratchmnt/"
> +fi
> +
> +buildah unmount "$newcontainer"
> +
> +buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
> +buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
> +buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
> +buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
> +buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
> +
> +buildah commit --format=docker "$newcontainer" "$container_image_name"
> +
> +podman image inspect "$container_image_name"
> +
> +podman push --compression-format=gzip "$container_image_name"

If running on FDO, why do you reimplement all this instead of using the
CI templates ? And if not running on FDO, a Containerfile could be used.

> diff --git a/gitlab-ci.yml b/gitlab-ci.yml
> index b7362d7..36032e3 100644
> --- a/gitlab-ci.yml
> +++ b/gitlab-ci.yml
> @@ -144,6 +144,33 @@ container-build-debian-cross:
>        .gitlab-ci/setup-debian-cross-container.sh "$ARCH" ;
>        gem install fpm ;
> 
> +.container-build-debian-rootfs:
> +  variables:
> +    FDO_DISTRIBUTION_VERSION: 'trixie'
> +    FDO_DISTRIBUTION_TAG: 'build-debian-rootfs-2026-01-12.0'
> +
> +container-build-debian-rootfs:
> +  extends:
> +    - .fdo.container-build@debian
> +    - .container-build-debian-rootfs
> +  stage: container
> +  needs: []
> +  variables:
> +    GIT_STRATEGY: none
> +    FDO_DISTRIBUTION_PACKAGES: >-
> +      buildah
> +      ca-certificates
> +      debootstrap
> +      dpkg-dev
> +      findutils
> +      fuse-overlayfs
> +      git
> +      jq
> +      meson
> +      podman
> +      rsync
> +      skopeo
> +
>  # ------------------------------------------------------------------------------
>  # Build stage - Build libcamera for various platforms and configurations
>  # ------------------------------------------------------------------------------
> @@ -432,6 +459,26 @@ build-debian-cross:
>        - build/build.ninja
>        - "*.deb"
> 
> +build-debian-rootfs:
> +  extends:
> +    - .fdo.distribution-image@debian
> +    - .container-build-debian-rootfs
> +    - .debian-cross-build
> +    - .debian-cross-build-architectures
> +    - .libcamera-ci.scripts
> +  stage: build
> +  needs:
> +    - job: container-build-debian-rootfs
> +      artifacts: false
> +  variables:
> +    GIT_STRATEGY: none
> +  script:
> +    - $CI_PROJECT_DIR/.gitlab-ci/build-debian-rootfs.sh
> +        "$CROSS_BUILD_DISTRIBUTION_VERSION"
> +        "$ARCH"
> +        "$CROSS_BUILD_IMAGE"
> +        "$CROSS_BUILD_TAG-$ARCH"
> +
>  # ------------------------------------------------------------------------------
>  # Lint stage - Run checkstyle.py and check merge suitability
>  # ------------------------------------------------------------------------------
Barnabás Pőcze Jan. 22, 2026, 9:30 a.m. UTC | #2
2026. 01. 22. 3:22 keltezéssel, Laurent Pinchart írta:
> On Mon, Jan 19, 2026 at 11:20:37AM +0100, Barnabás Pőcze wrote:
>> Add a job that builds a debian rootfs and uploads it to the gitlab container
>> registry, with the dependencies needed by libcamera created in the
>> build-debian-cross job.
> 
> I'm not sure this belongs to the FDO CI. Can't we build this container
> locally instead, to avoid consuming CPU and network bandwidth from FDO ?
> The Containerfile for this can be stored in a subdirectory of
> containers/.

As mentioned in the cover letter, I think it would be nice to have the rootfs
in the ci pipeline. Normally this job, like the other `container-*` jobs, won't
do anything processing intensive, so my assumption was that it was fine.
(Especially if all this is guarded my a manual trigger / variable.)

Yes, this can be built locally, certainly. I think the main question is, do we
ever want to have the whole rootfs creation and deployment automated? If so, then
I believe it makes sense to keep it in a fdo ci "compatible" state. Since that
automation is still missing pieces on the hardware side, it might also make sense,
for the time being, to move these parts into a `containers/` with some documentation


> 
>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
>> ---
>>   .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
>>   gitlab-ci.yml                     | 47 ++++++++++++++++++
>>   2 files changed, 126 insertions(+)
>>   create mode 100755 .gitlab-ci/build-debian-rootfs.sh
>>
>> diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
>> new file mode 100755
>> index 0000000..800ba5f
>> --- /dev/null
>> +++ b/.gitlab-ci/build-debian-rootfs.sh
>> @@ -0,0 +1,79 @@
> [...]
>> +buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
>> +buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
>> +buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
>> +buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
>> +buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
>> +
>> +buildah commit --format=docker "$newcontainer" "$container_image_name"
>> +
>> +podman image inspect "$container_image_name"
>> +
>> +podman push --compression-format=gzip "$container_image_name"
> 
> If running on FDO, why do you reimplement all this instead of using the
> CI templates ? And if not running on FDO, a Containerfile could be used.

On a second look, it may be possible, although mapping between the docker
platform and debian architecture might be a bit inconvenient.


> [...]
Laurent Pinchart Jan. 22, 2026, 11:30 p.m. UTC | #3
On Thu, Jan 22, 2026 at 10:30:56AM +0100, Barnabás Pőcze wrote:
> 2026. 01. 22. 3:22 keltezéssel, Laurent Pinchart írta:
> > On Mon, Jan 19, 2026 at 11:20:37AM +0100, Barnabás Pőcze wrote:
> >> Add a job that builds a debian rootfs and uploads it to the gitlab container
> >> registry, with the dependencies needed by libcamera created in the
> >> build-debian-cross job.
> > 
> > I'm not sure this belongs to the FDO CI. Can't we build this container
> > locally instead, to avoid consuming CPU and network bandwidth from FDO ?
> > The Containerfile for this can be stored in a subdirectory of
> > containers/.
> 
> As mentioned in the cover letter, I think it would be nice to have the rootfs
> in the ci pipeline. Normally this job, like the other `container-*` jobs, won't
> do anything processing intensive, so my assumption was that it was fine.
> (Especially if all this is guarded my a manual trigger / variable.)
> 
> Yes, this can be built locally, certainly. I think the main question is, do we
> ever want to have the whole rootfs creation and deployment automated? If so, then
> I believe it makes sense to keep it in a fdo ci "compatible" state. Since that
> automation is still missing pieces on the hardware side, it might also make sense,
> for the time being, to move these parts into a `containers/` with some documentation

I'm in two minds about this. I see advantages in building the rootfs at
the same time as building libcamera, to ensure they're always in sync.
On the other hand, I don't expect frequent updates to the base Debian
version, and there are upsides of building the rootfs manually while we
experiment with all this. I'm slightly in favour of starting with a
Containerfile to decouple the rootfs from CI while we ramp up testing on
hardware, and then consider moving it to FDO. What do you think ?

> >> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> >> ---
> >>   .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
> >>   gitlab-ci.yml                     | 47 ++++++++++++++++++
> >>   2 files changed, 126 insertions(+)
> >>   create mode 100755 .gitlab-ci/build-debian-rootfs.sh
> >>
> >> diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
> >> new file mode 100755
> >> index 0000000..800ba5f
> >> --- /dev/null
> >> +++ b/.gitlab-ci/build-debian-rootfs.sh
> >> @@ -0,0 +1,79 @@
> >
> > [...]
> >
> >> +buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
> >> +buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
> >> +buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
> >> +buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
> >> +buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
> >> +
> >> +buildah commit --format=docker "$newcontainer" "$container_image_name"
> >> +
> >> +podman image inspect "$container_image_name"
> >> +
> >> +podman push --compression-format=gzip "$container_image_name"
> > 
> > If running on FDO, why do you reimplement all this instead of using the
> > CI templates ? And if not running on FDO, a Containerfile could be used.
> 
> On a second look, it may be possible, although mapping between the docker
> platform and debian architecture might be a bit inconvenient.
> 
> > [...]
Barnabás Pőcze Jan. 23, 2026, 10:59 a.m. UTC | #4
2026. 01. 23. 0:30 keltezéssel, Laurent Pinchart írta:
> On Thu, Jan 22, 2026 at 10:30:56AM +0100, Barnabás Pőcze wrote:
>> 2026. 01. 22. 3:22 keltezéssel, Laurent Pinchart írta:
>>> On Mon, Jan 19, 2026 at 11:20:37AM +0100, Barnabás Pőcze wrote:
>>>> Add a job that builds a debian rootfs and uploads it to the gitlab container
>>>> registry, with the dependencies needed by libcamera created in the
>>>> build-debian-cross job.
>>>
>>> I'm not sure this belongs to the FDO CI. Can't we build this container
>>> locally instead, to avoid consuming CPU and network bandwidth from FDO ?
>>> The Containerfile for this can be stored in a subdirectory of
>>> containers/.
>>
>> As mentioned in the cover letter, I think it would be nice to have the rootfs
>> in the ci pipeline. Normally this job, like the other `container-*` jobs, won't
>> do anything processing intensive, so my assumption was that it was fine.
>> (Especially if all this is guarded my a manual trigger / variable.)
>>
>> Yes, this can be built locally, certainly. I think the main question is, do we
>> ever want to have the whole rootfs creation and deployment automated? If so, then
>> I believe it makes sense to keep it in a fdo ci "compatible" state. Since that
>> automation is still missing pieces on the hardware side, it might also make sense,
>> for the time being, to move these parts into a `containers/` with some documentation
> 
> I'm in two minds about this. I see advantages in building the rootfs at
> the same time as building libcamera, to ensure they're always in sync.
> On the other hand, I don't expect frequent updates to the base Debian
> version, and there are upsides of building the rootfs manually while we
> experiment with all this. I'm slightly in favour of starting with a
> Containerfile to decouple the rootfs from CI while we ramp up testing on
> hardware, and then consider moving it to FDO. What do you think ?

Okay, I can move the scripts and overlay directory into `containers/`.
But would you prefer a `Containerfile` or is `buildah` fine? I imagine
`debootstrap` cannot really be used with a `Containerfile`, can it? So
you would use `debian:13-slim` or similar as base, I imagine? And skip
the manual `debootstrap` step?


> 
>>>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
>>>> ---
>>>>    .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
>>>>    gitlab-ci.yml                     | 47 ++++++++++++++++++
>>>>    2 files changed, 126 insertions(+)
>>>>    create mode 100755 .gitlab-ci/build-debian-rootfs.sh
>>>>
>>>> diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
>>>> new file mode 100755
>>>> index 0000000..800ba5f
>>>> --- /dev/null
>>>> +++ b/.gitlab-ci/build-debian-rootfs.sh
>>>> @@ -0,0 +1,79 @@
>>>
>>> [...]
>>>
>>>> +buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
>>>> +buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
>>>> +buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
>>>> +buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
>>>> +buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
>>>> +
>>>> +buildah commit --format=docker "$newcontainer" "$container_image_name"
>>>> +
>>>> +podman image inspect "$container_image_name"
>>>> +
>>>> +podman push --compression-format=gzip "$container_image_name"
>>>
>>> If running on FDO, why do you reimplement all this instead of using the
>>> CI templates ? And if not running on FDO, a Containerfile could be used.
>>
>> On a second look, it may be possible, although mapping between the docker
>> platform and debian architecture might be a bit inconvenient.
>>
>>> [...]
> 
> --
> Regards,
> 
> Laurent Pinchart
Laurent Pinchart Jan. 23, 2026, 2:45 p.m. UTC | #5
On Fri, Jan 23, 2026 at 11:59:37AM +0100, Barnabás Pőcze wrote:
> 2026. 01. 23. 0:30 keltezéssel, Laurent Pinchart írta:
> > On Thu, Jan 22, 2026 at 10:30:56AM +0100, Barnabás Pőcze wrote:
> >> 2026. 01. 22. 3:22 keltezéssel, Laurent Pinchart írta:
> >>> On Mon, Jan 19, 2026 at 11:20:37AM +0100, Barnabás Pőcze wrote:
> >>>> Add a job that builds a debian rootfs and uploads it to the gitlab container
> >>>> registry, with the dependencies needed by libcamera created in the
> >>>> build-debian-cross job.
> >>>
> >>> I'm not sure this belongs to the FDO CI. Can't we build this container
> >>> locally instead, to avoid consuming CPU and network bandwidth from FDO ?
> >>> The Containerfile for this can be stored in a subdirectory of
> >>> containers/.
> >>
> >> As mentioned in the cover letter, I think it would be nice to have the rootfs
> >> in the ci pipeline. Normally this job, like the other `container-*` jobs, won't
> >> do anything processing intensive, so my assumption was that it was fine.
> >> (Especially if all this is guarded my a manual trigger / variable.)
> >>
> >> Yes, this can be built locally, certainly. I think the main question is, do we
> >> ever want to have the whole rootfs creation and deployment automated? If so, then
> >> I believe it makes sense to keep it in a fdo ci "compatible" state. Since that
> >> automation is still missing pieces on the hardware side, it might also make sense,
> >> for the time being, to move these parts into a `containers/` with some documentation
> > 
> > I'm in two minds about this. I see advantages in building the rootfs at
> > the same time as building libcamera, to ensure they're always in sync.
> > On the other hand, I don't expect frequent updates to the base Debian
> > version, and there are upsides of building the rootfs manually while we
> > experiment with all this. I'm slightly in favour of starting with a
> > Containerfile to decouple the rootfs from CI while we ramp up testing on
> > hardware, and then consider moving it to FDO. What do you think ?
> 
> Okay, I can move the scripts and overlay directory into `containers/`.
> But would you prefer a `Containerfile` or is `buildah` fine? I imagine
> `debootstrap` cannot really be used with a `Containerfile`, can it? So
> you would use `debian:13-slim` or similar as base, I imagine? And skip
> the manual `debootstrap` step?

That's what I had in mind, but if buildah is a more modern and better
solution for the problem at hand, I'm OK with that too. We use
Containerfile for the CrOS container, it would be nice to standardize on
one technical solution if we can.

> >>>> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
> >>>> ---
> >>>>    .gitlab-ci/build-debian-rootfs.sh | 79 +++++++++++++++++++++++++++++++
> >>>>    gitlab-ci.yml                     | 47 ++++++++++++++++++
> >>>>    2 files changed, 126 insertions(+)
> >>>>    create mode 100755 .gitlab-ci/build-debian-rootfs.sh
> >>>>
> >>>> diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
> >>>> new file mode 100755
> >>>> index 0000000..800ba5f
> >>>> --- /dev/null
> >>>> +++ b/.gitlab-ci/build-debian-rootfs.sh
> >>>> @@ -0,0 +1,79 @@
> >>>
> >>> [...]
> >>>
> >>>> +buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
> >>>> +buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
> >>>> +buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
> >>>> +buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
> >>>> +buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
> >>>> +
> >>>> +buildah commit --format=docker "$newcontainer" "$container_image_name"
> >>>> +
> >>>> +podman image inspect "$container_image_name"
> >>>> +
> >>>> +podman push --compression-format=gzip "$container_image_name"
> >>>
> >>> If running on FDO, why do you reimplement all this instead of using the
> >>> CI templates ? And if not running on FDO, a Containerfile could be used.
> >>
> >> On a second look, it may be possible, although mapping between the docker
> >> platform and debian architecture might be a bit inconvenient.
> >>
> >>> [...]

Patch
diff mbox series

diff --git a/.gitlab-ci/build-debian-rootfs.sh b/.gitlab-ci/build-debian-rootfs.sh
new file mode 100755
index 0000000..800ba5f
--- /dev/null
+++ b/.gitlab-ci/build-debian-rootfs.sh
@@ -0,0 +1,79 @@ 
+#!/bin/bash
+# based on https://gitlab.freedesktop.org/freedesktop/ci-templates/-/blob/fb9d50ccb3cbbb4c6dc5f9ef53a0ad3cb0d8a177/bootstrap/cbuild
+
+set -ex
+
+packages=(
+	# misc.
+	ca-certificates
+	coreutils
+	chrony
+	curl
+	iproute2
+	kmod
+	moreutils
+	openssh-server
+	v4l-utils
+	wget
+
+	# runtime dependencies
+	libevent-2.1-7
+	libevent-pthreads-2.1-7
+	libpisp1
+	libssl3t64
+	libudev1
+	libyaml-0-2
+	udev
+)
+
+podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+skopeo login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+
+deb_distribution="$1"
+deb_arch="$2"
+container_image_path="$3"
+container_image_tag="$4"
+overlay_dir="$5"
+
+container_image_name="$CI_REGISTRY_IMAGE/$container_image_path:$container_image_tag"
+
+if skopeo inspect --no-tags --retry-times 3 "docker://$container_image_name"; then
+	echo "container image exists"
+	exit 0
+fi
+
+# TODO: Check if image already exists in the registry of $FDO_UPSTREAM_REPO?
+
+newcontainer=$(buildah from scratch)
+scratchmnt=$(buildah mount "$newcontainer")
+
+debootstrap --arch="$deb_arch" --variant=minbase "$deb_distribution" "$scratchmnt"
+
+buildah run --isolation=chroot "$newcontainer" apt update -y
+buildah run --isolation=chroot "$newcontainer" apt install -y --no-install-recommends systemd systemd-sysv
+buildah run --isolation=chroot "$newcontainer" apt install -y --no-install-recommends "${packages[@]}"
+buildah run --isolation=chroot "$newcontainer" bash -c 'printf "root\nroot\n" | passwd root'
+buildah run --isolation=chroot "$newcontainer" bash -c 'echo "PermitRootLogin yes" > /etc/ssh/sshd_config.d/10-allow-root-password.conf'
+buildah run --isolation=chroot "$newcontainer" apt autoclean -y
+buildah run --isolation=chroot "$newcontainer" apt autopurge -y
+
+buildah run --isolation=chroot "$newcontainer" rm -rf /var/cache/
+buildah run --isolation=chroot "$newcontainer" rm -rf /var/lib/apt/
+
+if [[ -d "$overlay_dir" ]]; then
+	rsync -av --chown=root:root "$overlay_dir/" "$scratchmnt/"
+fi
+
+buildah unmount "$newcontainer"
+
+buildah config -l fdo.pipeline_id="$CI_PIPELINE_ID" "$newcontainer"
+buildah config -l fdo.job_id="$CI_JOB_ID" "$newcontainer"
+buildah config -l fdo.project="$CI_PROJECT_PATH" "$newcontainer"
+buildah config -l fdo.commit="$CI_COMMIT_SHA" "$newcontainer"
+buildah config --entrypoint '["/sbin/init"]' "$newcontainer"
+
+buildah commit --format=docker "$newcontainer" "$container_image_name"
+
+podman image inspect "$container_image_name"
+
+podman push --compression-format=gzip "$container_image_name"
diff --git a/gitlab-ci.yml b/gitlab-ci.yml
index b7362d7..36032e3 100644
--- a/gitlab-ci.yml
+++ b/gitlab-ci.yml
@@ -144,6 +144,33 @@  container-build-debian-cross:
       .gitlab-ci/setup-debian-cross-container.sh "$ARCH" ;
       gem install fpm ;

+.container-build-debian-rootfs:
+  variables:
+    FDO_DISTRIBUTION_VERSION: 'trixie'
+    FDO_DISTRIBUTION_TAG: 'build-debian-rootfs-2026-01-12.0'
+
+container-build-debian-rootfs:
+  extends:
+    - .fdo.container-build@debian
+    - .container-build-debian-rootfs
+  stage: container
+  needs: []
+  variables:
+    GIT_STRATEGY: none
+    FDO_DISTRIBUTION_PACKAGES: >-
+      buildah
+      ca-certificates
+      debootstrap
+      dpkg-dev
+      findutils
+      fuse-overlayfs
+      git
+      jq
+      meson
+      podman
+      rsync
+      skopeo
+
 # ------------------------------------------------------------------------------
 # Build stage - Build libcamera for various platforms and configurations
 # ------------------------------------------------------------------------------
@@ -432,6 +459,26 @@  build-debian-cross:
       - build/build.ninja
       - "*.deb"

+build-debian-rootfs:
+  extends:
+    - .fdo.distribution-image@debian
+    - .container-build-debian-rootfs
+    - .debian-cross-build
+    - .debian-cross-build-architectures
+    - .libcamera-ci.scripts
+  stage: build
+  needs:
+    - job: container-build-debian-rootfs
+      artifacts: false
+  variables:
+    GIT_STRATEGY: none
+  script:
+    - $CI_PROJECT_DIR/.gitlab-ci/build-debian-rootfs.sh
+        "$CROSS_BUILD_DISTRIBUTION_VERSION"
+        "$ARCH"
+        "$CROSS_BUILD_IMAGE"
+        "$CROSS_BUILD_TAG-$ARCH"
+
 # ------------------------------------------------------------------------------
 # Lint stage - Run checkstyle.py and check merge suitability
 # ------------------------------------------------------------------------------