From: Cedric Hombourger <cedric_hombourger@mentor.com>
To: Helmut Grohne <helmut@subdivi.de>, Jan Kiszka <jan.kiszka@siemens.com>
Cc: isar-users <isar-users@googlegroups.com>,
Baurzhan Ismagulov <ibr@ilbers.de>,
"MacDonald, Joe" <Joe_MacDonald@mentor.com>
Subject: Re: [RFC] using lightweight containers instead of chroot
Date: Fri, 9 Jul 2021 17:46:48 +0200 [thread overview]
Message-ID: <f08277ba-7517-38c7-ac88-42553152bda7@mentor.com> (raw)
In-Reply-To: <YOcDDwNG/7o3PhwJ@alf.mars>
On 7/8/2021 3:52 PM, Helmut Grohne wrote:
> On Thu, Jul 08, 2021 at 01:38:01PM +0200, Jan Kiszka wrote:
>> On 08.07.21 11:07, Cedric Hombourger wrote:
>> ...
>> Longterm, there is also the desire to include support for DPKG_ROOT as
>> chroot-less way of building packages, faster when doing it cross and
>> also without special permissions (e.g. for qemu-user). But that requires
>> per-package support from Debian upstream. Discussions only started, in
>> particular with Helmuth (added to CC).
> You appear to be confusing some aspects here. DPKG_ROOT is not relevant
> to building packages. It is only relevant to installing them (which may
> be relevant here for creating filesystem images).
>
> Building packages without chroot in a reproducible way seems next to
> impossible to me. Even when you use user namespaces, chroot does not go
> away. It merely becomes unprivileged. Is that what you mean here?
>
>>> Proposal
>>>
>>> We may want to use unshare(1) to create a mount namespace where we
>>> will create our bind mounts,
>>> chroot into the buildchroot and run the specified command/script
> Are you aware that sbuild directly supports this use case? It has a
> --mode argument and one of its values is "unshare". In that case, you
> supply a tarball containing the chroot and it'll perform an unprivileged
> build inside an unshared chroot.
I was not and that's very promising. I am now modifying the PoC code to
use it.
Did I read correctly that we can tell sbuild to use an existing
directory for its chroot when using the "unshare" mode? I am asking
because that's failing for me (my host is on Debian/testing). Here's the
error
copy() failed: Is a directory
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors
and here's the full command I ran (with the key args being -c
<existing-chroot-dir> --chroot-mode=unshare):
+ sbuild -c
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/
--chroot-mode=unshare -d industrial-os --no-apt-update -v
--pre-build-commands= mkdir -p
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/base-apt
; mount --bind
/home/chombourger/unshare_sbuild/experimental/mel-apt
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/base-apt
; mount --bind
'/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/deploy/isar-apt/industrial-os-amd64/apt/industrial-os'
'/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/isar-apt'
; mount --bind
'/home/chombourger/unshare_sbuild/experimental/build-ipc/downloads'
'/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/downloads'
; mount -t proc none
'/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/proc'
; mount --rbind /sys
'/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/sys'
; mount -t tmpfs -o rw,nosuid,nodev,seclabel none
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/dev/shm
; mount -o bind /dev/pts
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/dev/pts
; mkdir -p
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs//home/builder/base-files
; mount --bind
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs//home/builder/base-files
--build-path=/home/builder/base-files/base-files-10.3+deb10u10 -D
and it produced the following output:
dh clean
dh: warning: Compatibility levels before 10 are deprecated (level 9
in use)
dh_clean
dh_clean: warning: Compatibility levels before 10 are deprecated
(level 9 in use)
dpkg-source: info: using source format '3.0 (native)'
dpkg-source: info: building base-files in base-files_2.4+ind3.tar.xz
dpkg-source: info: building base-files in base-files_2.4+ind3.dsc
Selected distribution industrial-os
Selected chroot
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/
D: Setting Config=Sbuild::ConfBase=HASH(0x55a7fa84d508)
D: Setting ABORT=undef
D: Setting
Job=/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Setting Build Dir=
D: Setting Max Lock Trys=120
D: Setting Lock Interval=5
D: Setting Pkg Status=pending
D: Setting Pkg Status Trigger=undef
D: Setting Pkg Start Time=0
D: Setting Pkg End Time=0
D: Setting Pkg Fail Stage=init
D: Setting Build Start Time=0
D: Setting Build End Time=0
D: Setting Install Start Time=0
D: Setting Install End Time=0
D: Setting This Time=0
D: Setting This Space=0
D: Setting Sub Task=initialisation
D: Setting Config=Sbuild::ConfBase=HASH(0x55a7fa84d508)
D: Setting Session ID=
D: Setting Chroot ID=/
D: Setting Defaults=HASH(0x55a7fc2a7e48)
D: Setting Split=1
D: Setting Split=0
D: Setting Host=Sbuild::ChrootRoot=HASH(0x55a7fc2a8010)
D: Setting Priority=0
D: Setting Location=/
D: Setting Session Purged=0
D: Setting Session=undef
D: Setting Dependency Resolver=undef
D: Setting Log File=undef
D: Setting Log Stream=undef
D: Setting Summary Stats=HASH(0x55a7fc283c70)
D: Setting dpkg-buildpackage pid=undef
D: Setting Dpkg Version=undef
D: Setting DSC:
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Setting
DSC=/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Setting Source
Dir=/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0
D: Setting DSC Base=base-files_2.4+ind3.dsc
D: DSC =
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Source Dir =
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0
D: DSC Base = base-files_2.4+ind3.dsc
D: Setting package version:
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Parsing
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3.dsc
D: Setting Package=base-files
D: Setting Version=1:2.4+ind3
D: Setting Package_Version=base-files_1:2.4+ind3
D: Setting Package_OVersion=base-files_1:2.4+ind3
D: Setting Package_OSVersion=base-files_2.4+ind3
D: Setting Package_SVersion=base-files_2.4+ind3
D: Setting OVersion=1:2.4+ind3
D: Setting OSVersion=2.4+ind3
D: Setting SVersion=2.4+ind3
D: Setting VersionEpoch=1
D: Setting VersionUpstream=2.4+ind3
D: Setting VersionDebian=
D: Setting DSC File=base-files_2.4+ind3.dsc
D: Setting DSC Dir=base-files-2.4+ind3
D: Package = base-files
D: Version = 1:2.4+ind3
D: Package_Version = base-files_1:2.4+ind3
D: Package_OVersion = base-files_1:2.4+ind3
D: Package_OSVersion = base-files_2.4+ind3
D: Package_SVersion = base-files_2.4+ind3
D: OVersion = 1:2.4+ind3
D: OSVersion = 2.4+ind3
D: SVersion = 2.4+ind3
D: VersionEpoch = 1
D: VersionUpstream = 2.4+ind3
D: VersionDebian =
D: DSC File = base-files_2.4+ind3.dsc
D: DSC Dir = base-files-2.4+ind3
D: Setting Pkg Status Trigger=CODE(0x55a7fc2300c8)
D: Setting Pkg Status=building
D: Setting Pkg Start Time=1625844658
D: Setting Pkg End Time=1625844658
D: Setting Host Arch=amd64
D: Setting Build Arch=amd64
D: Setting Build Profiles=
D: Setting Build Type=binary
D: Setting FILTER_PREFIX=__SBUILD_FILTER_1412690:
D: Setting COLOUR_PREFIX=__SBUILD_COLOUR_1412690:
D: Setting Log
File=/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/2.4+ind3-r0/base-files_2.4+ind3_amd64-2021-07-09T15:30:58Z.build
D: Setting Log Stream=GLOB(0x55a7fc28c788)
sbuild (Debian sbuild) 0.81.2 (31 January 2021) on build.local
+==============================================================================+
| base-files 1:2.4+ind3 (amd64) Fri, 09 Jul 2021
15:30:58 +0000 |
+==============================================================================+
Package: base-files
Version: 1:2.4+ind3
Source Version: 1:2.4+ind3
Distribution: industrial-os
Machine Architecture: amd64
Host Architecture: amd64
Build Architecture: amd64
Build Type: binary
D: Setting Config=Sbuild::ConfBase=HASH(0x55a7fa84d508)
D: Setting Chroots=HASH(0x55a7fc28ff88)
I: No tarballs found in /home/builder/.cache/sbuild
D: Setting Chroots=HASH(0x55a7fc298bd0)
D: Setting Config=Sbuild::ConfBase=HASH(0x55a7fa84d508)
D: Setting Session ID=
D: Setting Chroot
ID=/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/
D: Setting Defaults=HASH(0x55a7fc362e08)
D: Setting Chroots=Sbuild::ChrootInfoUnshare=HASH(0x55a7fc2880a0)
D: Setting Uid Gid Map=ARRAY(0x55a7fbdf7608)
running perl -e require 'syscall.ph';pipe my $rfh, my $wfh;my $ppid
= $$;my $cpid = fork() // die "fork() failed: $!";if ($cpid == 0)
{close $wfh;0 == sysread $rfh, my $c, 1 or die "read() did not
receive EOF";0 == system "newuidmap $ppid 0 1000 1 1 100000 1" or
die "newuidmap failed: $!";0 == system "newgidmap $ppid 0 1000 1 1
100000 1" or die "newgidmap failed: $!";exit 0;}0 == syscall
&SYS_unshare, 268435456 or die "unshare() failed: $!";close
$wfh;$cpid == waitpid $cpid, 0 or die "waitpid() failed: $!";if ($?
!= 0) {die "child had a non-zero exit status: $?";}0 == syscall
&SYS_setgid, 0 or die "setgid failed: $!";0 == syscall &SYS_setuid,
0 or die "setuid failed: $!";0 == syscall &SYS_setgroups, 0, 0 or
die "setgroups failed: $!";exec { $ARGV[0] } @ARGV or die "exec()
failed: $!"; chown 1:1 /tmp/tmp.sbuild.l7HJK58Vy2
Unpacking
/home/chombourger/unshare_sbuild/experimental/build-ipc/tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs
to /tmp/tmp.sbuild.l7HJK58Vy2...
running perl -e require 'syscall.ph';pipe my $rfh, my $wfh;my $ppid
= $$;my $cpid = fork() // die "fork() failed: $!";if ($cpid == 0)
{close $wfh;0 == sysread $rfh, my $c, 1 or die "read() did not
receive EOF";0 == system "newuidmap $ppid 0 100000 65536" or die
"newuidmap failed: $!";0 == system "newgidmap $ppid 0 100000 65536"
or die "newgidmap failed: $!";exit 0;}0 == syscall &SYS_unshare,
268435456 or die "unshare() failed: $!";close $wfh;$cpid == waitpid
$cpid, 0 or die "waitpid() failed: $!";if ($? != 0) {die "child had
a non-zero exit status: $?";}0 == syscall &SYS_setgid, 0 or die
"setgid failed: $!";0 == syscall &SYS_setuid, 0 or die "setuid
failed: $!";0 == syscall &SYS_setgroups, 0, 0 or die "setgroups
failed: $!";exec { $ARGV[0] } @ARGV or die "exec() failed: $!"; tar
--exclude=./dev/urandom --exclude=./dev/random --exclude=./dev/full
--exclude=./dev/null --exclude=./dev/console --exclude=./dev/zero
--exclude=./dev/tty --exclude=./dev/ptmx --directory
/tmp/tmp.sbuild.l7HJK58Vy2 --extract
copy() failed: Is a directory
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors
D: Error run_chroot_session(): Error creating chroot session:
skipping base-filesD: Setting Session=undef
D: Error run_chroot(): Error creating chroot session: skipping
base-filesE: Error creating chroot session: skipping base-files
D: Setting Pkg Status=failed
D: Setting Pkg Fail Stage=create-session
The extra bind-mounts would be needed for the following apt source to be
work:
$ cat
tmp/work/industrial-os-amd64/base-files/buildchroot/rootfs/etc/apt/sources.list.d/isar-apt.list
deb [trusted=yes] file:///isar-apt mel main
>
>>> The immediate benefit of this approach is that all mounts
>>> automatically disappear as the supplied
>>> command exits (whether it aborts prematurely because of an error or
>>> normally on completion).
>>>
>>> Another nice benefit is that bind mounts we created within this
>>> namespace are not (directly) visible
>>> from the parent namespace
>>>
>>> However, we found that running scripts within an unshare environment
>>> may not be as easy as
>>> chroot. We would welcome feedback on the code snippets provided
>>> below if you happen to have
>>> some better ideas.
> All of this applies to sbuild --mode=unshare as well except that it
> makes running scripts from hooks simple.
it certainly would!
>
>> I suspect Helmuth can tell us if that would take us on a fragile path
>> from Debian perspective. Isar-internal implementation details we could
>> likely sort out, but if that approach has architectural limits /wrt what
>> Debian packages expect/require, it might be the wrong direction.
> Reimplementing this functionality seems like a waste of time to me. If
> we ignore that for a moment, we notice that there are already ~10
> implementations and updating them all is painful. Therefore, we can
> conclude that changes to the build environment are rare and your
> reimplementation likely is maintainable with limited effort.
>
>>> def isar_user_spec():
>>> import os
>>> return '%d:%d' % (os.getuid(), os.getgid())
>>>
>>> ISAR_USER_SPEC = "${@ isar_user_spec() }"
>>> ISAR_UNSHARE_CMD = "sudo unshare --pid --fork --ipc --mount sh -ex"
>>> ISAR_CHROOT_SHELL = "sh -ex"
>>> ISAR_CHROOT_ROOT = "chroot ${BUILDCHROOT_DIR} ${ISAR_CHROOT_SHELL}"
>>> ISAR_CHROOT_USER = "chroot --userspec='${ISAR_USER_SPEC}'
>>> ${BUILDCHROOT_DIR} ${ISAR_CHROOT_SHELL}"
>>>
>>> # Would be similar to buildchroot_do_mounts but will happen in a
>>> separate mount namespace
>>> BUILDCHROOT_DO_MOUNTS =
>>> " \
>>> mount --bind '${REPO_ISAR_DIR}/${DISTRO}'
>>> '${BUILDCHROOT_DIR}/isar-apt' ; \
>>> mount --bind '${DL_DIR}'
>>> '${BUILDCHROOT_DIR}/downloads' ; \
>>> mount -t proc none
>>> '${BUILDCHROOT_DIR}/proc' ; \
>>> mount --rbind /sys
>>> '${BUILDCHROOT_DIR}/sys' ; \
>>> mount -t tmpfs -o rw,nosuid,nodev,seclabel none
>>> ${BUILDCHROOT_DIR}/dev/shm ; \
>>> mount -o bind /dev/pts
>>> ${BUILDCHROOT_DIR}/dev/pts \
>>> "
>>>
>>> # Would be similar to dpkg_do_mounts but will happen in a separate
>>> mount namespace
>>> DPKG_DO_MOUNTS = " \
>>> ${BUILDCHROOT_DO_MOUNTS} ; \
>>> mkdir -p ${BUILDROOT} ; \
>>> mount --bind ${WORKDIR} ${BUILDROOT} \
>>> "
>>>
>>> # Build package from sources using build script
>>> _runbuild() {
>>> export arch=${1}
>>>
>>> E="${@ isar_export_proxies(d)}"
>>> ( cat <<" UNSHARE"
>>> ${DPKG_DO_MOUNTS}
>>> ( cat <<" SCRIPT"
>>> export DEB_BUILD_OPTIONS="${DEB_BUILD_OPTIONS}"
>>> export DEB_BUILD_PROFILES="${DEB_BUILD_PROFILES}"
>>> export PARALLEL_MAKE="${PARALLEL_MAKE}"
>>> /isar/build.sh ${PP}/${PPS} ${arch}
>>> SCRIPT
>>> ) | ${ISAR_CHROOT_USER}
>>> UNSHARE
>>> ) | envsubst '$arch' | ${ISAR_UNSHARE_CMD}
>>> }
>>>
>>> dpkg_runbuild() {
>>> ( _runbuild ${PACKAGE_ARCH} )
>>> }
>>>
>>> PS: I am not very happy with the need to feed the script to execute
>>> under unshare
>>> via stdin, if there are better ways, we would be happy to
>>> consider them!
> When I started talking to Jan, I proposed adding an abstraction layer
> for package building. Work on that layer has now progressed under the
> name "mdbp" and source is available at
> https://git.subdivi.de/?p=~helmut/mdbp.git. I'm also working with
> Raphael Hertzog on unifying the API with debusine. Let us for a moment
> consider the implications of using mdbp here.
Thanks for the pointer. Yet another thing I probably want to look at
>
> * Much of the complexity would go away. What you are left with is
> writing a json file describing how you want your package built. What
> gets a little more difficult is getting the isar-apt repository past
> mdbp. Likely that would require a temporary http server.
> * mdbp is not another builder, but an adapter to existing ones. It can
> perform your builds using an existing sbuild or pbuilder
> installation. If you want more isolation, maybe using debspawn
> (backed by systemd-nspawn) is for you?
> * mdbp also provides a stateless backend that uses mmdebstrap. This
> backend performs the build in a user namespace.
> * If you decide that you prefer building in docker, we can add a
> backend for e.g. debocker or something else.
>
> I'm not sure what you'd be missing by using mdbp here, but one thing
> you'd certainly miss is quite a bit of complex code.
>
> If you want to consider this route, read the schema first:
> https://git.subdivi.de/?p=~helmut/mdbp.git;a=blob;f=mdbp/build_schema.json
>
> Helmut
>
next prev parent reply other threads:[~2021-07-09 15:47 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-08 9:07 Cedric Hombourger
2021-07-08 11:38 ` Jan Kiszka
2021-07-08 13:52 ` Helmut Grohne
2021-07-08 17:16 ` Jan Kiszka
2021-07-08 19:34 ` Helmut Grohne
2021-07-12 8:25 ` Jan Kiszka
2021-07-12 10:54 ` Helmut Grohne
2021-07-12 11:47 ` Jan Kiszka
2021-07-12 12:29 ` Cedric Hombourger
2021-07-12 14:35 ` Jan Kiszka
2021-07-09 15:46 ` Cedric Hombourger [this message]
2021-07-09 16:12 ` Cedric Hombourger
2021-07-26 13:55 ` Anton Mikanovich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f08277ba-7517-38c7-ac88-42553152bda7@mentor.com \
--to=cedric_hombourger@mentor.com \
--cc=Joe_MacDonald@mentor.com \
--cc=helmut@subdivi.de \
--cc=ibr@ilbers.de \
--cc=isar-users@googlegroups.com \
--cc=jan.kiszka@siemens.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox