Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manual install without Fedora Kinoite #1

Closed
GrabbenD opened this issue Aug 28, 2023 · 61 comments
Closed

Manual install without Fedora Kinoite #1

GrabbenD opened this issue Aug 28, 2023 · 61 comments

Comments

@GrabbenD
Copy link

GrabbenD commented Aug 28, 2023

On a fresh archinstall system I cloned this repository and executed:

./update

Once podman run finishes in ./update it complains about:

Usage: ostree commit [OPTION…] [PATH]

(..) error: Command requires a --repo argument

Have I done something wrong?

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

oh yea you have to specify it if you're not running within the ostree system already: (man ostree)

       --repo
           For most commands, a repository is required. If unspecified, the current directory is used if it appears to be an OSTree
           repository. If it isn't, either the OSTREE_REPO environment variable is used, or the system repository located at
           /sysroot/ostree/repo.

So exporting OSTREE_REPO should work for you. You can create a create a (bootable) repo using ostree init --mode=bare. The repo option is global, so the same lookup logic applies.

@GrabbenD
Copy link
Author

GrabbenD commented Aug 28, 2023

You're sharp @M1cha, thanks a ton

Strangely this command made no difference:

$ export OSTREE_REPO=/ostree/repo

I did it this way instead:

$ mkdir -p /ostree/repo
$ ostree init --repo=/ostree/repo --mode=bare

# Then executed this after updating the last line to: ostree commit -v -b archlinux/latest --tree=dir="$rootfs" --repo=/ostree/repo
$ update 
OT: Preparing transaction in repository 0x56235963c080
OT: Pushing lock non-blocking with timeout 30
OT: Opening repo lock file
OT: Push lock: state=unlocked, depth=0
OT: Locking repo shared
OT: Using new tmpdir staging-48c0fb3b-8830-4a48-9557-4305e755d132-e1LPyT
OT: Committing transaction in repository 0x56235963c080
OT: txn commit staging-48c0fb3b-8830-4a48-9557-4305e755d132-e1LPyT
OT: Popping lock non-blocking with timeout 30
OT: Pop lock: state=shared, depth=1
OT: Unlocking repo

Something is still missing though:

$ ostree admin os-init archlinux
error: loading sysroot: fstatat(ostree/deploy): No such file or directory

$ ls /ostree
repo

$ ls /ostree/repo/
config  extensions  objects  refs  state  tmp

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

It looks like it's assuming the sysroot is in the current directory(ostree/deploy instead of /sysroot/ostree/deploy). I guess that's because you didn't boot via ostree. But that's fine because there's a --sysroot option. Check the bottom of man ostree-admin.

Also, I see that you created that in /ostree. That's fine and you will be able to boot into it using the root and ostree kernel cmdline options, but usually there's no normal OS on that partition.

@GrabbenD
Copy link
Author

GrabbenD commented Aug 28, 2023

I see that you created that in /ostree. That's fine and you will be able to boot into it using the root and ostree kernel cmdline options, but usually there's no normal OS on that partition.

Thanks for the insights!

If /ostree directory doesn't exists I get this error:

$ ostree init --repo=/ostree/repo --mode=bare
error: Creating repo: mkdirat: No such file or directory

Hence why I created it manually with mkdir (then the contents in /ostree/repo/* were created by ostree init)
Is there actually a better way of creating /ostree?

Edit: My bad, just realized that /sysroot/ostree is the right location. I though it was a placeholder!


It looks like it's assuming the sysroot is in the current directory(ostree/deploy instead of /sysroot/ostree/deploy). I guess that's because you didn't boot via ostree. But that's fine because there's a --sysroot option. Check the bottom of man ostree-admin.

Here's a new attempt with /sysroot/ostree instead of /ostree, this is strange though:

$ mkdir -p /sysroot/ostree
$ ostree init --repo=/sysroot/ostree/repo --mode=bare

$ ostree commit -v -b archlinux/latest --tree=dir=/root/archlinux-ostree/out/rootfs --repo=/sysroot/ostree/repo

$ mkdir /sysroot/ostree/deploy
$ ostree admin --sysroot=/sysroot/ostree/deploy os-init archlinux
error: loading sysroot: opendir(ostree/repo): No such file or directory

# Another attempt
$ export OSTREE_REPO=/sysroot/ostree/repo
$ ostree admin --sysroot=$OSTREE_REPO os-init archlinux
error: loading sysroot: opendir(ostree/repo): No such file or directory

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

ostree admin probably needs a --repo argument as well. Also (or alternatively), I'm not sure if the sysroot path is correct. I'd expect it to want /sysroot instead of /sysroot/ostree/repo.

@GrabbenD
Copy link
Author

Thanks a ton for the fast replies.
You're right, this worked!

$ ostree admin --sysroot=/sysroot os-init archlinux
ostree/deploy/archlinux initialized as OSTree root

$ ostree admin --sysroot=/sysroot deploy --os=archlinux --no-merge archlinux/latest
Relabeling /var (no stamp file 'var/.ostree-selabeled' found)
Bootloader updated; bootconfig swap: yes; bootversion: boot.1.1, deployment count change: 1

Although I've been stuck on bootloader for a while, I fail to understand the structure:
Fedora uses /boot/efi/EFI/fedora/grub.cfg, what's the equivalent for Arch Linux?

$ find /boot -iname grub.cfg
/boot/grub/grub.cfg

$ ls /boot
EFI  grub  initramfs-linux-fallback.img  initramfs-linux.img  vmlinuz-linux

$ ls /boot/EFI
BOOT

$ ls /boot/EFI/BOOT
BOOTX64.EFI

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

is /boot/grub/grub.cfg one that was generated by the deployment command? For me it is and it's the path that's usually used on arch as well. That file is missing some initialization though so you want to put a manually written config in a path that has higher loading priority(I assume there are multiple supported paths based on my observations).

In fedora they use /boot/efi/EFI/fedora/grub.cfg (next to grubx64.efi etc) and I modified it to look like this:

search --no-floppy --fs-uuid --set=dev 971087dd-5e14-4640-b11b-78aab4154b1a
set prefix=($dev)/grub2

search --no-floppy --fs-uuid --set=root 971087dd-5e14-4640-b11b-78aab4154b1a
search --no-floppy --fs-uuid --set=boot 48EE-9318

export $prefix
configfile $prefix/grub.cfg

keep in mind that if you have grub-mkconfig installed ostree simply triggers that instead of writing it's config. In that case you'll have to install their grub extensions: https://github.com/ostreedev/ostree/tree/v2023.6/src/boot/grub2

@GrabbenD
Copy link
Author

GrabbenD commented Aug 28, 2023

is /boot/grub/grub.cfg one that was generated by the deployment command?

I compared /boot/grub/grub.cfg before and after successfully installing OSTree but it's unchanged. It seems like Bootloader updated; bootconfig swap: yes; bootversion: boot.1.1, deployment count change: 1 only updated /sysroot/boot since there's a ostree folder there but not in /boot:

$ find /sysroot/boot
/sysroot/boot
/sysroot/boot/loader.1
/sysroot/boot/loader.1/entries
/sysroot/boot/loader.1/entries/ostree-1-archlinux.conf
/sysroot/boot/ostree
/sysroot/boot/ostree/archlinux-f7246e5ebdf5182e6157bacdbead3bf9eef5aa55517fa882fb05583b4e70ec25
/sysroot/boot/ostree/archlinux-f7246e5ebdf5182e6157bacdbead3bf9eef5aa55517fa882fb05583b4e70ec25/vmlinuz-6.4.12-zen1-1-zen
/sysroot/boot/ostree/archlinux-f7246e5ebdf5182e6157bacdbead3bf9eef5aa55517fa882fb05583b4e70ec25/initramfs-6.4.12-zen1-1-zen.img
/sysroot/boot/boot
/sysroot/boot/loader

$ find /boot ! -name "*.png" ! -name "*.pf2" ! -name "*.mo" ! -name "*.mod" ! -name "*.lst"
/boot
/boot/vmlinuz-linux
/boot/initramfs-linux.img
/boot/initramfs-linux-fallback.img
/boot/grub
/boot/grub/x86_64-efi
/boot/grub/x86_64-efi/modinfo.sh
/boot/grub/x86_64-efi/core.efi
/boot/grub/x86_64-efi/grub.efi
/boot/grub/locale
/boot/grub/themes
/boot/grub/themes/starfield
/boot/grub/themes/starfield/COPYING.CC-BY-SA-3.0
/boot/grub/themes/starfield/README
/boot/grub/themes/starfield/theme.txt
/boot/grub/fonts
/boot/grub/grubenv
/boot/grub/grub.cfg
/boot/EFI
/boot/EFI/BOOT
/boot/EFI/BOOT/BOOTX64.EFI

you want to put a manually written config in a path that has higher loading priority(I assume there are multiple supported paths based on my observations).

It sounds like /etc/grub.d/ should be the right place:
After the installation, the main configuration file /boot/grub/grub.cfg needs to be generated. The generation process can be influenced by a variety of options in /etc/default/grub and scripts in /etc/grub.d/

keep in mind that if you have grub-mkconfig installed ostree simply triggers that instead of writing it's config. In that case you'll have to install their grub extensions: https://github.com/ostreedev/ostree/tree/v2023.6/src/boot/grub2

That's the case!


I tried to put it together like this:

$ lsblk -o +UUID
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
                                       UUID
sda      8:0    0   127G  0 disk
├─sda1   8:1    0   512M  0 part /boot D668-25F1
└─sda2   8:2    0 126.5G  0 part /     6a36a809-abcd-40a5-b0c9-b9a53905e75e
# /etc/grub.d/00_boot.cfg
search --no-floppy --fs-uuid --set=dev 6a36a809-abcd-40a5-b0c9-b9a53905e75e
set prefix=($dev)/grub

search --no-floppy --fs-uuid --set=root 6a36a809-abcd-40a5-b0c9-b9a53905e75e
search --no-floppy --fs-uuid --set=boot D668-25F1

export $prefix
configfile $prefix/grub.cfg
# /etc/grub.d/10_ostree.cfg
# Contents of: https://github.com/ostreedev/ostree/blob/v2023.6/src/boot/grub2/grub2-15_ostree
$ grub-mkconfig -o /boot/grub/grub.cfg
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot:  initramfs-linux-fallback.img
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done

$ reboot
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-linux root=UUID=6a36a809-abcd-40a5-b0c9-b9a53905e75e rw rootfstype=xfs loglevel=3 quiet

I'm probably missing something since I can't grasp how grub is supposed to load contents from /sysroot and append ostree parameter to the cmdline

Sorry I'm really confused about the bootloader part

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

I'm probably missing something since I can't grasp how grub is supposed to load contents from /sysroot and append ostree parameter to the cmdline

Sorry I'm really confused about the bootloader part

ostree follows the GNU boot loader specification. The files in /boot/loader/entries/ define new menu entries - one per deployment. Since grub2 doesn't support that specification (yet), they wrote tools that convert them to grub.cfgs.

ostree-grub-generator is a tool that does this for installations without grub-mkconfig. If you have grub-mkconfig though, grub2-15_ostree ultimately calls ostree admin instutil grub2-generate which does something similar: https://github.com/ostreedev/ostree/blob/89e13a954cfbb0256bf8ebcd286f68f133b7ec9e/src/libostree/ostree-bootloader-grub2.c#L148

@GrabbenD
Copy link
Author

Thanks, that makes sense

I moved /etc/grub.d/10_ostree.cfg to /etc/grub.d/15_ostree and gave it the right permissions chmod +x /etc/grub.d/15_ostre. Now it appears in /boot/grub/grub.cfg but it's not adding a menuentry:

### BEGIN /etc/grub.d/15_ostree ###
### END /etc/grub.d/15_ostree ###

I think this condition is failing:

# https://github.com/ostreedev/ostree/blob/v2023.6/src/boot/grub2/grub2-15_ostree#L23C6-L23C26
test -d /ostree/repo

Not really sure where to go from here :/
Wish @cgwalters could have provided steps on how to bootstrap a system with ostree from scratch

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

I don't know if mkconfig has a verbose flag but if they keep stdout connected you could add set -x to that script to make sure. Also, why wouldn't /ostree/repo exist on your system?

What my scripts do is based on this: https://ostreedev.github.io/ostree/adapting-existing/
Unfortunately they skip on everything you're trying to do right now 🙈

@GrabbenD
Copy link
Author

GrabbenD commented Aug 28, 2023

What my scripts do is based on this: https://ostreedev.github.io/ostree/adapting-existing/
Unfortunately they skip on everything you're trying to do right now 🙈

Hehehe it's classic to have docs which only covers some parts of the implementation 💦

I don't know if mkconfig has a verbose flag but if they keep stdout connected you could add set -x to that script to make sure.

That's really clever considering grub-mkconfig doesn't have a parameter for debugging the generation:

# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot:  initramfs-linux-fallback.img
+ which ostree
+ test -d /ostree/repo
+ exit 0
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done

Yeah the issue seems to be that /ostree is missing in / ->

Also, why wouldn't /ostree/repo exist on your system?

Just to recap all the commands, I'm building /ostree in /sysroot

$ mkdir -p /sysroot/ostree
$ ostree init --repo=/sysroot/ostree/repo --mode=bare
$ ostree commit -v -b archlinux/latest --tree=dir=/root/archlinux-ostree/out/rootfs --repo=/sysroot/ostree/repo

$ mkdir /sysroot/ostree/deploy
$ ostree admin --sysroot=/sysroot os-init archlinux
$ ostree admin --sysroot=/sysroot deploy --os=archlinux --no-merge archlinux/latest

In this case, maybe it makes more sense to do it directly in /?

[root@arch ~]# mkdir /ostree
[root@arch ~]# ostree init --repo=/ostree/repo --mode=bare
[root@arch ~]# ostree commit -v -b archlinux/latest --tree=dir=/root/archlinux-ostree/out/rootfs --repo=/ostree/repo
OT: Preparing transaction in repository 0x55d991ddd080
OT: Pushing lock non-blocking with timeout 30
OT: Opening repo lock file
OT: Push lock: state=unlocked, depth=0
OT: Locking repo shared
OT: Using new tmpdir staging-a9b9c0dd-fc52-491a-aaea-346d924c7c53-cjqXhc
OT: Committing transaction in repository 0x55d991ddd080
OT: txn commit staging-a9b9c0dd-fc52-491a-aaea-346d924c7c53-cjqXhc
OT: Popping lock non-blocking with timeout 30
OT: Pop lock: state=shared, depth=1
OT: Unlocking repo
f3561001d80523d1d1162376ab54003f3827da2b55ca743a346350573293c656
[root@arch ~]# mkdir /ostree/deploy
[root@arch ~]# ostree admin --sysroot=/ os-init archlinux
ostree/deploy/archlinux initialized as OSTree root
[root@arch ~]# ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
Relabeling /var (no stamp file 'var/.ostree-selabeled' found)
error: Preparing final bootloader swap: symlinkat: Operation not permitted

Seems like it's not a good idea on a running system, instead with chroot:

$ mkdir -p /mnt/arch/
$ mount /dev/sda2 /mnt/arch/
$ mount /dev/sda1 /mnt/arch/boot
$ arch-chroot /mnt/arch

$ ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
error: opendir(var): No such file or directory

$ pwd
/

$ ls -d /var
/var

$ ls -d /ostree/deploy/archlinux/deploy/*/var
/ostree/deploy/archlinux/deploy/55f3f25edbe2ca0233c8b4bba6f61c110f21364c7bcbd6cfe1eac58c34331e5e.0/var

Oh man, feels like we're so close!

@M1cha
Copy link
Owner

M1cha commented Aug 28, 2023

On fedora, /ostree is a symlink. I never understood why it exists but I guess now we know 😋

# ls -lah /ostree
lrwxrwxrwx 3 root root 14 Jul 29 21:22 /ostree -> sysroot/ostree

@GrabbenD
Copy link
Author

Thanks!
Redid it with /sysroot/ostree and linked /ostree to that directory.
Now something more is happening but when I reboot there's no new boot entries, /boot/grub/grub.cfg didn't really change much either: https://www.diffchecker.com/2x5IKhKL/

$ ln -s /sysroot/ostree /ostree
$ grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot:  initramfs-linux-fallback.img
+ which ostree
+ test -d /ostree/repo
+ . /etc/default/grub
++ GRUB_DEFAULT=0
++ GRUB_TIMEOUT=5
++ GRUB_DISTRIBUTOR=Arch
++ GRUB_CMDLINE_LINUX_DEFAULT='loglevel=3 quiet'
++ GRUB_CMDLINE_LINUX=rootfstype=xfs
++ GRUB_PRELOAD_MODULES='part_gpt part_msdos'
++ GRUB_TIMEOUT_STYLE=menu
++ GRUB_TERMINAL_INPUT=console
++ GRUB_GFXMODE=auto
++ GRUB_GFXPAYLOAD_LINUX=keep
++ GRUB_DISABLE_RECOVERY=true
+ test -f /boot/grub2/.grub2-blscfg-supported
+ test -n /dev/sda2
+ set -e
+ . /usr/share/grub/grub-mkconfig_lib
++ prefix=/usr
++ exec_prefix=/usr
++ datarootdir=/usr/share
++ datadir=/usr/share
++ bindir=/usr/bin
++ sbindir=/usr/bin
++ '[' x/usr/share/grub = x ']'
++ test x = x
++ grub_probe=/usr/bin/grub-probe
++ test x = x
++ grub_file=/usr/bin/grub-file
++ test x = x
++ grub_mkrelpath=/usr/bin/grub-mkrelpath
++ command -v gettext
++ :
++ grub_tab='   '
+ DEVICE=/dev/sda1
++ grub_get_device_id /dev/sda1
++ old_ifs='
'
++ IFS='
'
++ device=/dev/sda1
++ '[' x '!=' xtrue ']'
+++ /usr/bin/grub-probe --device /dev/sda1 --target=fs_uuid
++ fs_uuid=D668-25F1
++ echo D668-25F1
++ IFS='
'
+ GRUB2_BOOT_DEVICE_ID=D668-25F1
+ export GRUB2_BOOT_DEVICE_ID
++ prepare_grub_to_access_device /dev/sda1
++ old_ifs='
'
++ IFS='
'
+++ /usr/bin/grub-probe --device /dev/sda1 --target=partmap
++ partmap=gpt
++ for module in ${partmap}
++ case "${module}" in
++ echo 'insmod part_gpt'
+++ /usr/bin/grub-probe --device /dev/sda1 --target=abstraction
++ abstraction=
+++ /usr/bin/grub-probe --device /dev/sda1 --target=fs
++ fs=fat
++ for module in ${fs}
++ echo 'insmod fat'
++ '[' x = xy ']'
+++ /usr/bin/grub-probe --device /dev/sda1 --target=compatibility_hint
++ fs_hint=hd0,gpt1
++ '[' xhd0,gpt1 '!=' x ']'
++ echo 'set root='\''hd0,gpt1'\'''
++ '[' x '!=' xtrue ']'
+++ /usr/bin/grub-probe --device /dev/sda1 --target=fs_uuid
++ fs_uuid=D668-25F1
+++ /usr/bin/grub-probe --device /dev/sda1 --target=hints_string
++ hints='--hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 '
++ '[' 'x--hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 ' '!=' x ']'
++ echo 'if [ x$feature_platform_search_hint = xy ]; then'
++ echo '  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1  D668-25F1'
++ echo else
++ echo '  search --no-floppy --fs-uuid --set=root D668-25F1'
++ echo fi
++ IFS='
'
+ GRUB2_PREPARE_ROOT_CACHE='insmod part_gpt
insmod fat
set root='\''hd0,gpt1'\''
if [ x$feature_platform_search_hint = xy ]; then
  search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1  D668-25F1
else
  search --no-floppy --fs-uuid --set=root D668-25F1
fi'
+ export GRUB2_PREPARE_ROOT_CACHE
+ exec ostree admin instutil grub2-generate
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done

Out of curiously I tried to run the command from /etc/grub.d/15_ostree manually:

$ ostree admin instutil grub2-generate
**
OSTree:ERROR:src/libostree/ostree-bootloader-grub2.c:164:_ostree_bootloader_grub2_generate_config: assertion failed: (grub2_boot_device_id != NULL)
Bail out! OSTree:ERROR:src/libostree/ostree-bootloader-grub2.c:164:_ostree_bootloader_grub2_generate_config: assertion failed: (grub2_boot_device_id != NULL)
Aborted (core dumped)

There's a piece missing in this lego set 👀

@M1cha
Copy link
Owner

M1cha commented Aug 29, 2023

ostree admin instutil grub2-generate has a --verbose flag. Adding that to the grub script might be useful.

@GrabbenD
Copy link
Author

Need more symlinks to somewhere, do you have these?

$ ostree admin instutil grub2-generate --verbose
OT: Didn't find $sysroot/boot/loader symlink; assuming bootversion 0
OT: Didn't find $sysroot/ostree/boot.0 symlink; assuming subbootversion 0
**
OSTree:ERROR:src/libostree/ostree-bootloader-grub2.c:164:_ostree_bootloader_grub2_generate_config: assertion failed: (grub2_boot_device_id != NULL)
Bail out! OSTree:ERROR:src/libostree/ostree-bootloader-grub2.c:164:_ostree_bootloader_grub2_generate_config: assertion failed: (grub2_boot_device_id != NULL)
Aborted (core dumped)

@M1cha
Copy link
Owner

M1cha commented Aug 29, 2023

I don't think running that outside of the grub script is the right way if you get errors when previously you didn't. My /sysroot/boot is empty

@GrabbenD
Copy link
Author

Hmm, took a few steps back found out that /sysroot/boot was created by the same command which said: Bootloader updated (meaning ostree admin --sysroot=/sysroot deploy --os=archlinux --no-merge archlinux/latest):

$ ls -lah /sysroot/boot
total 0
drwxr-xr-x 4 root root 62 Aug 29 09:12 .
drwxr-xr-x 4 root root 32 Aug 29 09:12 ..
lrwxrwxrwx 1 root root  1 Aug 29 09:12 boot -> .
lrwxrwxrwx 1 root root  8 Aug 29 09:12 loader -> loader.1
drwxr-xr-x 3 root root 21 Aug 29 09:12 loader.1
drwxr-xr-x 3 root root 88 Aug 29 09:12 ostree

$ ls -lah /sysroot/ostree/
total 0
drwxr-xr-x 5 root root  62 Aug 29 09:12 .
drwxr-xr-x 4 root root  32 Aug 29 09:12 ..
lrwxrwxrwx 1 root root   8 Aug 29 09:12 boot.1 -> boot.1.1
drwxr-xr-x 3 root root  23 Aug 29 09:12 boot.1.1
drwxr-xr-x 3 root root  23 Aug 29 09:12 deploy
drwxr-xr-x 7 root root 102 Aug 29 09:12 repo

I came across this also: https://wiki.gnome.org/Projects/OSTree/DeploymentModel2#Redeploying

Seems like files in /sysroot/boot are supposed to exist in /boot?

$ cp -rf /sysroot/boot/* /boot/
cp: cannot create symbolic link '/boot/boot': Operation not permitted
cp: cannot create symbolic link '/boot/loader': Operation not permitted

Well, that's not the right way of doing it 😂

@GrabbenD
Copy link
Author

Well, this explains why files are in the wrong location (/sysroot/boot and not /boot): ostreedev/ostree#2992

@M1cha
Copy link
Owner

M1cha commented Aug 29, 2023

oh yea that makes sense. Using / should work then 🤞

@M1cha M1cha changed the title OSTree error: Command requires a --repo argument Manual install without Fedora Kinoite Aug 29, 2023
@GrabbenD
Copy link
Author

GrabbenD commented Aug 29, 2023

I got way too happy when I saw that issue report and the resolution, I jinxed it:

[root@arch ~]# mkdir -p /sysroot/ostree
[root@arch ~]# ostree init --repo=/sysroot/ostree/repo --mode=bare
[root@arch ~]# ostree commit -v -b archlinux/latest --tree=dir=/root/archlinux-ostree/out/rootfs --repo=/sysroot/ostree/repo
OT: Preparing transaction in repository 0x56183e5cb070
OT: Pushing lock non-blocking with timeout 30
OT: Opening repo lock file
OT: Push lock: state=unlocked, depth=0
OT: Locking repo shared
OT: Using new tmpdir staging-aba45dca-9f39-4f3b-9154-9d877bdfff61-bmFwhf
OT: Committing transaction in repository 0x56183e5cb070
OT: txn commit staging-aba45dca-9f39-4f3b-9154-9d877bdfff61-bmFwhf
OT: Popping lock non-blocking with timeout 30
OT: Pop lock: state=shared, depth=1
OT: Unlocking repo
fa7daa856e1cff367d8a3a081bf3db981463c4eb552a71aa2f1c2f1f6b138865
[root@arch ~]# mkdir /sysroot/ostree/deploy
[root@arch ~]# ostree admin --sysroot=/ os-init archlinux
error: loading sysroot: opendir(ostree/repo): No such file or directory
[root@arch ~]# ostree admin --sysroot=/sysroot os-init archlinux
ostree/deploy/archlinux initialized as OSTree root
[root@arch ~]# ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
error: No such file or directory
[root@arch ~]# ostree admin deploy --os=archlinux --no-merge archlinux/latest
error: No such file or directory
[root@arch ~]# ostree admin deploy --verbose
error: No such file or directory

Also tried updating OSTree from 2023.5 -> 2023.6

@GrabbenD
Copy link
Author

GrabbenD commented Aug 29, 2023

Turns out /ostree symlinks needs to exist before using ostree admin

$ ln -s /sysroot/ostree /ostree
$ ostree admin --sysroot=/sysroot os-init archlinux
$ ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
Relabeling /var (no stamp file 'var/.ostree-selabeled' found)
error: Bootloader write config: No KERNEL argument found after LABEL

Now this is new.
Here's another attempt with / (this is the same issue I tried to workaround with chroot earlier):

[root@arch ~]# ln -s /sysroot/ostree /ostree
[root@arch ~]# mkdir /sysroot/ostree/deploy
[root@arch ~]# ostree admin --sysroot=/ os-init archlinux
ostree/deploy/archlinux initialized as OSTree stateroot
[root@arch ~]# ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
Relabeling /var (no stamp file 'var/.ostree-selabeled' found)
error: Preparing final bootloader swap: symlinkat: Operation not permitted

@GrabbenD
Copy link
Author

GrabbenD commented Aug 29, 2023

error: Preparing final bootloader swap: symlinkat: Operation not permitted

Sounds like this approach might need some adjustments to work with a (UEFI) FAT32 /boot partition since this filesystem doesn't support symbolic links 😞

ostreedev/ostree#2478
ostreedev/ostree#1967

@GrabbenD
Copy link
Author

Turns out you can use a separate (vfat) ESP partition which allows /boot to be any filesystem with a UEFI partition scheme (https://wiki.archlinux.org/title/EFI_system_partition)! I went with this approach:

  • /boot ext4 (this can be a separate partition but I'm sharing it with sdb3 (/) to be efficient with storage space)
  • /boot/efi fat32 (this ESP path allows for potentially EFISTUB support in the future)
$ lsblk -o +FSTYPE
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS FSTYPE

sdb      8:16   0   127G  0 disk
|-sdb1   8:17   0   512M  0 part /boot/efi vfat
|-sdb2   8:18   0    20G  0 part /home     ext4
`-sdb3   8:19   0 106.5G  0 part /         ext4
# /etc/fstab
# Generated with: $ genfstab -U /mnt/arch >> /mnt/arch/etc/fstab

# <file system> <dir> <type> <options> <dump> <pass>
# /dev/sdb3 LABEL=SYS_ROOT
UUID=661f46d0-e6de-4df5-8e0c-2b6f92016f32       /               ext4            rw,relatime     0 1

# /dev/sdb2 LABEL=SYS_HOME
UUID=c8f8e836-5b0c-4f52-a36c-9d04717243fc       /home           ext4            rw,relatime     0 2

# /dev/sdb1 LABEL=SYS_BOOT
UUID=B20C-7F9C          /boot/efi       vfat            rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro   0 2

There's a lot of ways to use a ESP partition (e.g. various paths, by adding efibootmgr, ..) but I found this minimal approach to be sufficient for now:

$ pacman -S grub
# --removable makes it detectable without having to use efibootmgr
$ grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable --boot-directory=/boot/efi/EFI --bootloader-id=archlinux
$ grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg

The current OSTree setup looks like this:

# OSTree DEPS
$ pacman -S ostree which wget

# OSTREE REPO INITALIZATION
$ mkdir -p /sysroot/ostree
$ ostree init --repo=/sysroot/ostree/repo --mode=bare
$ ostree commit -v -b archlinux/latest --tree=dir=/root/archlinux-ostree/out/rootfs --repo=/sysroot/ostree/repo
$ ln -s /sysroot/ostree /ostree

# OSTREE REPO ACTIVATION
$ mkdir /sysroot/ostree/deploy
$ ostree admin --sysroot=/ os-init archlinux
$ ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest

# OSTREE BOOTLOADER
$ wget https://raw.githubusercontent.com/ostreedev/ostree/v2023.6/src/boot/grub2/grub2-15_ostree -O /etc/grub.d/15_ostree
$ chmod +x /etc/grub.d/15_ostree
$ grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg

Touch down 😎

grub

This still needs a bit more work but it feels like it's getting close:

error: file `/ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b/vmlinuz-6.4.12-zen1-1-zen not found.
error: you need to load the kernel first.

@M1cha
Copy link
Owner

M1cha commented Aug 31, 2023

Sorry for the late answer.

Turns out you can use a separate (vfat) ESP partition which allows /boot to be any filesystem with a UEFI partition scheme (https://wiki.archlinux.org/title/EFI_system_partition)! I went with this approach:

That's similar to what fedora does:

Device           Start        End   Sectors   Size Type
/dev/nvme0n1p1    2048    1230847   1228800   600M EFI System
/dev/nvme0n1p2 1230848    3327999   2097152     1G Linux filesystem
/dev/nvme0n1p3 3328000 1000214527 996886528 475.4G Linux filesystem

error: file `/ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b/vmlinuz-6.4.12-zen1-1-zen not found.
error: you need to load the kernel first.

This sounds similar to what I had before I set root in my grub.cfg. I'd expect that to not be needed when using the grub extension though.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 1, 2023

In that case grub might need a few more tweaks!

But firstly, just realized something funny is going on. With a clean install (before adding any ostree related steps from above):

# ls /boot
efi  initramfs-linux.img  vmlinuz-linux

Then when following OSTree setup with commands from above (up to OSTREE REPO ACTIVATION), at this step bootloader gets duplicated:

$ ostree admin --sysroot=/ deploy --os=archlinux --no-merge archlinux/latest
Bootloader updated; bootconfig swap: yes; bootversion: boot.1.1, deployment count change: 1

# ls /boot
boot  efi  initramfs-linux.img  loader  loader.1  ostree  vmlinuz-linux
# ls /boot/boot
boot  efi  initramfs-linux.img  loader  loader.1  ostree  vmlinuz-linux
# ls /boot/boot/boot
boot  efi  initramfs-linux.img  loader  loader.1  ostree  vmlinuz-linux
# ls /boot/boot/boot/boot/boot/boot/boot/boot/boot/boot/boot/boot/boot/boot
boot  efi  initramfs-linux.img  loader  loader.1  ostree  vmlinuz-linux

Contents of /boot/boot are identical to /boot 🤯

@M1cha
Copy link
Owner

M1cha commented Sep 1, 2023

Contents of /boot/boot are identical to /boot 🤯

That's because it's a symbolic link. I recommend ls -la 😛 And it's totally normal because that's what allows ostree to perform atomic updates: https://ostreedev.github.io/ostree/atomic-upgrades/#the-bootversion

@GrabbenD
Copy link
Author

GrabbenD commented Sep 1, 2023

My bad, thanks for pointing it out!

This sounds similar to what I had before I set root in my grub.cfg. I'd expect that to not be needed when using the grub extension though.

If I inspect the ostree:0 grub entry which generates this error:

error: file `/ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b/vmlinuz-6.4.12-zen1-1-zen not found.

It looks like it's searching the right path:

grub-ostree-inspect

Since those exist here:

$ find /boot -iname *fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b*
/boot/ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b

$ ls /boot/ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b
initramfs-6.4.12-zen1-1-zen.img  vmlinuz-6.4.12-zen1-1-zen

$ find /sysroot -iname fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b
/sysroot/ostree/boot.1.1/archlinux/fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b

$ find /ostree -iname fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b

$ find /ostree/ -iname fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b
/ostree/boot.1.1/archlinux/fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b

$ ls -l /ostree/boot.1
lrwxrwxrwx 1 root root 8 Sep  1 10:49 /ostree/boot.1 -> boot.1.1

$ ls /ostree/boot.1/archlinux/fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b/0
bin  boot  dev  etc  home  lib  lib64  mnt  opt  ostree  proc  root  run  sbin  srv  sys  sysroot  tmp  usr  var

But I'm not sure if grub is able to see them or if something is wrong with the symlink (ln -s /sysroot/ostree /ostree):

$ ls -l /ostree
lrwxrwxrwx 1 root root 15 Sep  1 10:49 /ostree -> /sysroot/ostree

I'd expect that to not be needed when using the grub extension though.

Hmm, I gave it a shot anyway since I'm stuck:

$ lsblk -o +UUID
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS UUID
sdb      8:16   0   127G  0 disk
|-sdb1   8:17   0   512M  0 part /boot/efi B20C-7F9C
|-sdb2   8:18   0    20G  0 part /home     c8f8e836-5b0c-4f52-a36c-9d04717243fc
`-sdb3   8:19   0 106.5G  0 part /         661f46d0-e6de-4df5-8e0c-2b6f92016f32

$ ls /boot/efi/EFI/grub
fonts  grub.cfg  grub.cfg.old  grubenv  locale  themes  x86_64-efi

# nano /etc/grub.d/40_custom
search --no-floppy --fs-uuid --set=dev 661f46d0-e6de-4df5-8e0c-2b6f92016f32
set prefix=($dev)/boot/efi/EFI/grub

search --no-floppy --fs-uuid --set=root 661f46d0-e6de-4df5-8e0c-2b6f92016f32
search --no-floppy --fs-uuid --set=boot B20C-7F9C

export $prefix
configfile $prefix/grub.cfg

$ grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg

Leads to:

error: file `/boot/efi/EFI/grub/x86_64-efi/linux16.mod' not found.

The file is there though!

# ls -l /boot/efi/EFI/grub/x86_64-efi/linux16.mod
-rwxr-xr-x 1 root root 8480 Aug 31 10:48 /boot/efi/EFI/grub/x86_64-efi/linux16.mod

@M1cha
Copy link
Owner

M1cha commented Sep 1, 2023

grub has a shell as well (press escape). That might help exploring the issue.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 1, 2023

I'm not sure if I understand the issue with the generated code. The ls within grub probably didn't show any files because you forgot the trailing /.

Here's how it looks inside:

grub

Is there a reason for that? Might it be worth trying a similar setup?

Right now I have /boot as a regular directory on my main partition /dev/sdb3 (SYS_ROOT) to save storage space. However, OSTree is looking for a hardcoded(?) path /ostree/archlinux-fcad05e9f4bbe2a8e94763dda2542a4bf53ee9af812afb02de6d28f6051e9d1b/initramfs-6.4.12-zen1-1-zen.img in / (SYS_ROOT) while this file is actually located under /boot/ostree/archlinux-..

If I understand this correctly Fedora is able to find the right files with /ostree/.. path since /boot is a dedicated ext4 partition

I suppose I don't have a choice but to make /boot into its own partition unless there is a way to tweak this grub entry to use /boot/ostree instead of /ostree?

@GrabbenD
Copy link
Author

GrabbenD commented Sep 4, 2023

While researching some problems here I stumbled upon Gnome's QEMU VM setup which skips bootloader creation altogether and just copies the right files to /boot, figured I'd share it here since someone might find it useful:
https://gitlab.gnome.org/rmader/gnome-build-meta/-/blob/gnome-43/elements/vm/image.bst

They also have a working Raspberry Pi 4 setup with U-Boot here:
https://gitlab.gnome.org/rmader/gnome-build-meta/-/blob/gnome-43/elements/boards/raspberrypi-4/image.bst

I'm confused why OSTree think it's BIOS (GRUB2_SUFFIX) and not GRUB2_EFI_SUFFIX, is there actually some sort of OSTree config for this or are environment variables the only solution (_OSTREE_GRUB2_IS_EFI=true)?

Solved!
Compile OSTree with --with-builtin-grub2-mkconfig (check comment below for more details)
I've submitted a bug report here: https://bugs.archlinux.org/task/79560

I suppose I don't have a choice but to make /boot into its own partition unless there is a way to tweak this grub entry to use /boot/ostree instead of /ostree?

Solved!

$ ostree config --repo=/ostree/repo set sysroot.bootprefix 'true'

Timed out waiting for device /dev/gpt-auto-root

Solved!
Had to specify my root device (/dev/sdb3 which has a label SYS_ROOT) with: --karg="root=LABEL=SYS_ROOT"
I found that --karg-proc-cmdline works too since it imports root=UUID=661f46d0-e6de-4df5-8e0c-2b6f92016f32 as well as some other boot flags which I found undesirable

@GrabbenD
Copy link
Author

GrabbenD commented Sep 4, 2023

FINALLY IT WORKS !! 🎉 🎉 🎉

I decided to scratch /sysroot to have one less folder in / and as a added bonus ostree admin init-fs creates the right structure in /ostree without any extra commands

I also figured out how to add custom kernel boot flags, use e.g. --karg="mitigations=off" argument in ostree admin deploy

Here's the final setup in a CI/CD fashion:

# OSTREE: DEPS
$ pacman --noconfirm -S wget which

# OSTREE: DEPS (workaround missing --with-builtin-grub2-mkconfig)
$ pacman --noconfirm -S sudo git
$ git clone https://gitlab.archlinux.org/archlinux/packaging/packages/ostree.git /home/build/ostree
$ cd /home/build/ostree && chown -R nobody $(pwd)
$ source PKGBUILD && pacman -S --noconfirm --needed --asdeps base-devel "${makedepends[@]}" "${depends[@]}"
$ sed -i '/--with-builtin-grub2-mkconfig/a \ \ \ \ --with-modern-grub' PKGBUILD
$ sudo -u nobody makepkg -Cf --nocheck
$ pacman --noconfirm -U *.pkg.tar.zst

# OSTREE: REPO INITALIZATION
$ ostree admin init-fs --sysroot=/ --modern /
$ ostree init --repo=/ostree/repo --mode=bare
$ ostree config --repo=/ostree/repo set sysroot.bootprefix 'true'
$ ostree commit --repo=/ostree/repo --tree=dir=/root/archlinux-ostree/out/rootfs --branch=archlinux/latest -v

# OSTREE: REPO ACTIVATION
$ ostree admin os-init --sysroot=/ archlinux
$ ostree admin deploy --sysroot=/ --karg="root=LABEL=SYS_ROOT" --karg="rw" --os=archlinux --no-merge --retain archlinux/latest

# OSTREE: BOOTLOADER (GRUB2)
$ wget https://raw.githubusercontent.com/ostreedev/ostree/v2023.6/src/boot/grub2/grub2-15_ostree -O /etc/grub.d/15_ostree && chmod +x /etc/grub.d/15_ostree
$ grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg

# OSTREE: EXTRA
cp /etc/{fstab,crypttab,shadow} /ostree/deploy/archlinux/deploy/*/etc/

For reference:

$ lsblk -o +FSTYPE,LABEL
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS FSTYPE LABEL

sdb      8:16   0   127G  0 disk
|-sdb1   8:17   0   512M  0 part /boot/efi vfat   SYS_BOOT
|-sdb2   8:18   0    20G  0 part /home     ext4   SYS_HOME
`-sdb3   8:19   0 106.5G  0 part /         ext4   SYS_ROOT

All of this translates to:
grub_working

@M1cha
Copy link
Owner

M1cha commented Sep 5, 2023

that's awesome news, great work 🥳
And apparently the package already got updated so it works out of the box now, nice.

Also thanks for the hint about ostree admin init-fs, that's very useful.

At this point I'm wondering what we could do with all that information. Make an ostree installation guide in the arch wiki? Create a tool to automate all those steps? Also, would it be worth to create tools for generating the rootfs or did the overlap between my scripts and yours end up small anyway?

@GrabbenD
Copy link
Author

GrabbenD commented Sep 7, 2023

🚀 🚀 🚀

At this point I'm wondering what we could do with all that information. Make an ostree installation guide in the arch wiki?

Great idea!
That would definitely help a lot of people out as OSTree's documentation isn't that straightforward and the developers aren't keen on answering questions

Create a tool to automate all those steps?

Ideally I think it would be wiser to let the user assemble their OSTree installation from scratch rather than rely on scripts as it gives more flexibility especially once systemd-boot support rolls in

Also, would it be worth to create tools for generating the rootfs or did the overlap between my scripts and yours end up small anyway?

I'm still using your script to build a rootfs since I haven't come up with a easier approach yet

Have you looked into $ ostree container?
From my limited understanding it seems like OSTree is slowly moving towards upgrades through OCI images
I believe UBlue already uses this (although it seems like their project is limited to Fedora images)

Perhaps it be better to try to do something similar to UBlue/OSTree Container by making a Docker/Image which creates the correct filesystem layout (with RUN) which you'd be able to build locally or import (e.g. FROM archlinux-ostree:latest)? The user would just have to perform OSTree setup from above after importing the image and you'd be able to customize it with Dockerfile/Contailerfile (= multi-stage builds ❤️ )

For reference, Elemental-Toolkit (https://github.com/rancher/elemental-toolkit/blob/main/examples/tumbleweed/Dockerfile) and KairOS (https://github.com/kairos-io/kairos/tree/master/examples) are alternative projects to OSTree which already upgrades the base system through OCI images.

(For context, I'm not sure where $ ostree container command comes from, maybe it's a separate project)
https://coreos.github.io/rpm-ostree/container/#adapting-software

@M1cha
Copy link
Owner

M1cha commented Sep 7, 2023

Have you looked into $ ostree container?

That's actually how this whole project started out but I had so many issues that I gave that up. The tool that can do that is called bootc, and it uses functionality from ostree-rs-ext.

I didn't manage to find a way to build a container in a way or convert it in a way that ends up in a usable ostree image

Additionally the whole process was painfully slow. I probably could have improved this a lot by doing all the work in a single RUN step so it doesn't create a new cache a million times. But even then, that whole system exists so you can transport ostree images via existing infrastructure like the github container registry. For a single use image that works on exactly one machine and that you quickly want to update and deploy the process has too much overhead:

  • build a rootfs within a container (dockerfile)
  • let the container runtime copy the whole thing to the local registry and create an image from that
  • convert that image to an ostree image and thus copy it to the ostree repo

here is my old code for that: https://github.com/M1cha/bootc-archlinux

@GrabbenD
Copy link
Author

GrabbenD commented Sep 7, 2023

Thanks for sharing, your effort with BootC definitely saved me from pursuing another rabbit hole 🙂
The overhead which you mentioned is pretty much identical- and what drove me away from Elemental-Toolkit in the first place.

In this case, I think the only missing puzzle piece is a minimal set of commands for building a rootfs

@M1cha
Copy link
Owner

M1cha commented Sep 8, 2023

The updated ostree package broke my current setup 😅
It now installs the grub extension, is missing the fallback script and tries to use mkconfig even when it doesn't exist. The workaround is to install the script manually and set the environment variable OSTREE_GRUB2_EXEC to it's path.

I'll migrate to the mkconfig setup since it's better anyway but it's sad that something trivial like this is defined at compile time rather than detected at runtime within the ostree tool. 🤷

In this case, I think the only missing puzzle piece is a minimal set of commands for building a rootfs

I'll try to create a tool and/or a bash library to simplify the whole thing. For now this will be archlinux only since there isn't much code in this repo that would help other distros right now.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 8, 2023

I'll migrate to the mkconfig setup since it's better anyway but it's sad that something trivial like this is defined at compile time rather than detected at runtime within the ostree tool. 🤷

Even Gentoo's EBuild is hardcoded to use mkconfig, I don't know if doing it this way 4451680c is counterproductive or if it warrants a bug request. I suppose Arch Linux was never about freedom of choice but rather simplicity

I'll try to create a tool and/or a bash library to simplify the whole thing. For now this will be archlinux only since there isn't much code in this repo that would help other distros right now.

Awesome, thanks a ton 🙏🏼

@GrabbenD
Copy link
Author

GrabbenD commented Sep 14, 2023

Even Gentoo's EBuild is hardcoded to use mkconfig, I don't know if doing it this way 4451680c is counterproductive or if it warrants a bug request.

I've been playing around with building OSTree onto a empty partition (meaning rootfs only contains a bootloader and has no system outside of OSTree) to keep it super minimal, it almost works 🙂

$ find /mnt -maxdepth 2
/mnt
/mnt/ostree
/mnt/ostree/repo
/mnt/ostree/boot.1
/mnt/ostree/deploy
/mnt/ostree/boot.1.1
/mnt/boot
/mnt/boot/loader.1
/mnt/boot/efi
/mnt/boot/ostree
/mnt/boot/loader
/mnt/boot/boot

$ lsblk -o NAME,TYPE,MOUNTPOINTS
NAME   TYPE MOUNTPOINTS
sda    disk
├─sda1 part /boot
├─sda2 part /home
└─sda3 part /
sdb    disk
├─sdb1 part /mnt/boot/efi
├─sdb2 part
└─sdb3 part /mnt

Except for generation of boot entries.. Turns out grub-mkconfig has no built in way of changing the rootfs - it generates entries in /mnt/boot/efi/EFI/grub/grub.cfg for the current system in / and not the mountpoint which leads to:

  • Wrong partition UUID (it uses /dev/sda3 instead of /dev/sdb3)
  • Wrong insmod fat filesystem is used (if host doesn't use ESP partition scheme (/boot/efi with ext4))
  • OSTree first boot entry is never integrated since grub2-15_ostree script uses absolute path /ostree/repo

In other words: the idea is to build a OSTree system from a "rescue cd" onto a mountpoint, I'm trying to think of a clean way of doing this:

  • chroot into /mnt isn't possible (as far as I know) as there is no actual filesystem there
  • Perhaps building it inside Podmain container with multi-stage build (so just copy /ostree and /boot from first layer onto a empty scratch layer where target installation partitions are already mounted as volumes). I don't really like this approach as it adds overhead versus just running a script
  • OSBuild ?
  • ostree-grub-generator ?
  • GRUB_ENABLE_BLSCFG ?

I don't fully understand it but OSTree skips grub-mkconfig if GRUB_ENABLE_BLSCFG is used. Have you looked into BLS approach @M1cha? Maybe it could be a viable alternative to mkconfig?

@M1cha
Copy link
Owner

M1cha commented Sep 14, 2023

In other words: the idea is to build a OSTree system from a "rescue cd" onto a mountpoint, I'm trying to think of a clean way of doing this:

That'd be great. Having a guide that let's you quickly set up a new ostree system using the official live ISO would be ideal.

I think what you need is a chroot so you can enter a system that is similar enough to the ostree system that the bootloader setup works. Either you can just enter the rootfs directory you already have from the builder or you can use ostree checkout to create a new one. I think I'd prefer the first way since it requires no copy. Either way, you'll have to setup some additional mount points because the ostreeify step is quite destructive. If needed, we can reduce complexity using tools. If we created an arch package from this repo you could have tools for building and chrooting for example.

I don't fully understand it but OSTree skips grub-mkconfig if GRUB_ENABLE_BLSCFG is used. Have you looked into BLS approach @M1cha? Maybe it could be a viable alternative to mkconfig?

BLS is an unofficial patchset that allows grub to load loader entries directly. Fedora seems to be applying those patches to their grub package but it doesn't look like they're actually using it. While this might be the technical ideal it means that we would have to maintain a grub-bls package.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 14, 2023

That'd be great. Having a guide that let's you quickly set up a new ostree system using the official live ISO would be ideal.

Definitely! Leaving a summary here of the findings:

  • OSBuild is probably not suitable for this setup
  • ostree-grub-generator / --with-builtin-grub2-mkconfig uses hardcoded values instead of /etc/default/grub
  • GRUB_ENABLE_BLSCFG would require grub to be patched
  • Building /mnt with a Podman volumes is possible but introduces unnecessary overhead
  • Making a /mnt/boot/efi/EFI/grub/custom.cfg script iterate OSTree boot entries from /mnt/boot/loader/entries/*.cfg could perhaps be another alternative as it can be used alongside $ grub-mkconfig to generates /boot/efi/EFI/grub/grub.cfg which has user's configuration from /etc/default/grub (such as video settings, os-probe, ..). This would conflict with --with-grub2-mkconfig-path=/usr/bin/grub-mkconfig though
  • Chroot (see below)

I think what you need is a chroot so you can enter a system that is similar enough to the ostree system that the bootloader setup works.

Here's a working approach which uses the rootfs from the builder to keep the amount of steps to the minimum
Not sure if I like it though!

# Install OSTree boot entries
$ ostree admin deploy --sysroot=/mnt --karg="root=LABEL=SYS_ROOT" --karg="rw" --os=archlinux --no-merge --retain archlinux/latest

# Install ESP
$ grub-install --target=x86_64-efi --efi-directory=/mnt/boot/efi --removable --boot-directory=/mnt/boot/efi/EFI --bootloader-id=archlinuxezez /dev/sdb1

# Enable OSTree boot entries [workaround grub-mkconfig inability to change rootfs]
$ pacman --noconfirm -S arch-install-scripts
$ export OSTREE_SYS_PATH=$(ls -d /mnt/ostree/deploy/archlinux/deploy/*|head -n 1)
$ rm -rfv ${OSTREE_SYS_PATH}/boot/*
$ mount --mkdir --rbind /mnt/boot ${OSTREE_SYS_PATH}/boot
$ mount --mkdir --rbind /mnt/ostree ${OSTREE_SYS_PATH}/sysroot/ostree
$ arch-chroot ${OSTREE_SYS_PATH}
$ grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg
$ exit && cd && umount -R /mnt

The commands in the workaround section are entirely unnecessary if there is a way to do a pseudo chroot for $ grub-mkconfig to make it think that /mnt is rootfs. Like some sort of unshare but I've never seen anything like that before

Surely there must be a better way to do this which isn't as convoluted 🤔

@M1cha
Copy link
Owner

M1cha commented Sep 14, 2023

You should open a discussion with the grub maintainers. My fear is that it's not easy to fix on their side though because most things including the extension scripts will probably assume that the current system is the target system. The arch wiki even warns about running grub-mkconfig and even grub-install outside of the final rootfs. Options like boot-directory seem to be an afterthought.

Given all of that I'd actually say that the most compatible solution is a chroot into an ostree rootfs. I'm not sure if doing that on the deployment is safe in terms of unwanted modifications to it though. This solution would also work with other bootloaders. Keep in mind that ostree supports many.

The cleanest solution would probably be using a grub fork with bls support. The loader specification is supposed to be generic so any bootloader with support for it should be able to boot into ostree without generating any configs. Given all of the options I'd probably prefer this one even if it complicates the initial setup due to having to install an AUR helper first.

@M1cha
Copy link
Owner

M1cha commented Sep 14, 2023

Thinking more about my second suggestion: Technically you'd still want to do that from within the chroot:

  • after the initial setup you need the grub fork inside the ostree rootfs anyway so you can deploy updates
  • it's easier and more automated to install aur helpers and packages within the rootfs
  • you probably want to make sure that you're installing the bootloader version that the grub package that is installed in the ostree image would install too

Given that train of thought I think it would be clean, generic and useful to extend the ostree cli with a subcommand that takes an image name or hash and a path as arguments and then creates and chroots into a temporary deployment. Deployments are fast to create because they use hardlinks.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 16, 2023

Thanks for sharing your thoughts!

I think the first step could be to open a dialog with GRUB maintainers to see what they think, even if the final solution doesn't use grub-mkconfig, it'd be beneficial for users who'd like to generate a grub.cfg without chroot (since I encountered some users having this issue while doing ephemeral root)

Grub with BLS sounds like a great idea even if it requires AUR (since Arch Wiki often refers to AUR packages anyway) and I like the idea about integrating it with ostree cli! I have a hard time wrapping my head around BLS though, not sure I can be much of help in that regard.


I went ahead and summarized all the commands which I'm currently using to automatically build a OSTree system. Ended up making the code into a repository instead of a gist since this way it's easier to share/clone into a LiveCD with QEMU/VM. I might remove archive it later once there's a proper script to do this:
https://github.com/GrabbenD/ostree-demo

Not sure how the final tools/scripts/usage instructions will look like but hopefully this should make it easier to figure that out. I ended up building the entire OSTree in Podman with layer caching, only part which isn't cached is OSTree repo setup bits and partitioning.

Feel free to take a look

@M1cha
Copy link
Owner

M1cha commented Sep 29, 2023

Sorry for the very late answer.
I think disabling the layer cache is very smart but I don't like the idea of basing my OS on top of the archlinux docke image because they make some nasty changes their. For example, undoing their NoExtract patches only affects newly installed packages unless you reinstall everything explicitly.

@GrabbenD
Copy link
Author

GrabbenD commented Sep 29, 2023

Sorry for the very late answer.

No worries
2 weeks ago I reached out to GRUB's devel mail list (yes, it's ancient) and got no response, I doubt there ever will be one.

For example, undoing their NoExtract patches only affects newly installed packages unless you reinstall everything explicitly.

This definitely needs to be addressed for desktop usage

Someone recently added this wiki entry https://wiki.archlinux.org/title/Install_Arch_Linux_via_Docker
Pacstrap uses /etc/pacman.conf from the host which ends up including NoExtract into a newly built system 🙈

Nonetheless, I toyed around with various approaches. This is probably the worst as it can't use Pacman cache while creating rootfs (if there is one mounted) thus it's the slowest (unless you want to keep a local copy of archlinux-bootstrap-x86_64.tar.gz but I find that ugly):

# time podman build --file="Containerfile.bootstrap" --no-cache
FROM docker.io/library/archlinux AS rootfs

RUN curl https://mirror.bahnhof.net/pub/archlinux/iso/2023.09.01/archlinux-bootstrap-x86_64.tar.gz -o archlinux-bootstrap-x86_64.tar.gz && \
    tar -C /mnt -xzf archlinux-bootstrap-x86_64.tar.gz --numeric-owner && \
    curl -s -L "https://archlinux.org/mirrorlist/?country=SE&protocol=http&ip_version=4" | sed -e 's/^#Server/Server/' -e '/^#/d' > /mnt/root.x86_64/etc/pacman.d/mirrorlist

FROM scratch
COPY --from=rootfs /mnt/root.x86_64 /

RUN pacman-key --init && \
    pacman-key --populate && \
    pacman --noconfirm -Syu

real 0m40.570s
user 0m26.693s
sys 0m24.145s


Out of curiously I tried reinstalling every package (without a pkg cache) as unlike Debian's apt-get, Pacman seems to regenerate system files (like configs in /etc) when reinstalling packages. This ended up being twice as fast but I'm doubtful if it's a good approach:

FROM docker.io/library/archlinux AS rootfs

RUN sed -i -e "s|^NoExtract.*||g" /etc/pacman.conf && \
    pacman --noconfirm -Sy $(pacman -Qq)

real 0m19.159s
user 0m7.648s
sys 0m10.009s

This can be even faster if you use a package cache for consecutive builds (--volume="/var/cache/pacman:/var/cache/pacman"):

real 0m13.967s
user 0m7.199s
sys 0m9.183s


Here's the cleanest alternative code wise but it's just as slow as bootstrap:

# time podman build --file="Containerfile.pacstrap" --cap-add="SYS_ADMIN" --no-cache
FROM docker.io/library/archlinux AS rootfs

# pacstrap uses Pacman config from the host
RUN sed -i -e "s|^NoExtract.*||g" /etc/pacman.conf && \
    pacman --noconfirm -Sy arch-install-scripts && \
    pacstrap -K /mnt base

FROM scratch AS base
COPY --from=rootfs /mnt /

real 0m36.467s
user 0m22.195s
sys 0m21.537s

Using a package cache made no difference here
Most of the time is spent at COPY stage even with fast GEN4 NVME disk + XFS + Native OverlayFS

In summary:

  • The current approach which I'm using just builds off archlinux:base and ends up taking a total of 1m11s to create a minimal bootable OSTree commit (Containerfile.base.archlinux)
  • With Pacstrap approach (to avoid issues from NoExtract), compilation time increases to 1m56s to build a OSTree commit from scratch.

I guess the increase in built time with Pacstrap approach is neglectable once the result is cached on disk as a tagged- and reusable Podman (base) image.

Do you think there is any other way of going about this?

@M1cha
Copy link
Owner

M1cha commented Sep 29, 2023

Someone recently added this wiki entry https://wiki.archlinux.org/title/Install_Arch_Linux_via_Docker Pacstrap uses /etc/pacman.conf from the host which ends up including NoExtract into a newly built system 🙈

Yes, that's why I do this:

sed -e 's|^NoExtract.*||g' /etc/pacman.conf > /tmp/pacman.conf

Nonetheless, I toyed around with various approaches. This is probably the worst as it can't use Pacman cache while creating rootfs (if there is one mounted) thus it's the slowest (unless you want to keep a local copy of archlinux-bootstrap-x86_64.tar.gz but I find that ugly):

There is a latest symlink: https://mirror.bahnhof.net/pub/archlinux/iso/latest/archlinux-bootstrap-x86_64.tar.gz
You could probably do some curl CLI magic to only update it when the timestamp provides by the HTTP server is newer than one that was stored locally. I don't see an uglyness difference between the pacman cache and a bootstrap cache. It's just that we need more code if we want to cache stuff ourselves.

Out of curiously I tried reinstalling every package (without a pkg cache) as unlike Debian's apt-get, Pacman seems to regenerate system files (like configs in /etc) when reinstalling packages. This ended up being twice as fast but I'm doubtful if it's a good approach:

NoExtract is not the only change. Sure, we can try to revert all of their changes but we'd have to stay updated on their dockerfile changes so we can check if there's new stuff that we don't want. Personally, I find that risky and too much work.

Here's the cleanest alternative code wise but it's just as slow as bootstrap:

I agree as that's essentially exactly the same what my current bash scripts do, but utilizing podman containers instead of arch-chroot which is WAY cleaner. Good idea 👍

Using a package cache made no difference here Most of the time is spent at COPY stage even with fast GEN4 NVME disk + XFS + Native OverlayFS

For me it makes a huge difference because The package download takes like 1-2 minutes for me. Admittedly it could probably be optimized by selecting a better mirror but the more packages you install the more of a difference it makes. Also, if you update often(e.g. during phases of many security updates) then you save time since in most cases it's just gonna download like 1-5 packages.

We might actually be able to prevent the slow rootfs copy by using 2 dockerfiles instead of a single multi-stage dockerfile:

  • the first one pacstraps into a podman volume
  • the second one gets started using --rootfs instead of an image

@GrabbenD
Copy link
Author

Do you think there is any other way of going about this?

Just to expand on this, I ended up finding another method
I don't like it though as it's convoluted, just leaving it here as a reference

It's possible to use a script which fetches packages directly and unpacks them into a rootfs, this way you don't need to have Pacman or Pacstrap installed to build a new system.

Here's a up to date example from Artix's repo:
https://gitea.artixlinux.org/artix/artix-bootstrap/src/branch/master/artix-bootstrap.sh

For Arch Linux here's two examples:
https://github.com/tokland/arch-bootstrap/blob/master/arch-bootstrap.sh
https://github.com/BiteDasher/archbashstrap/blob/master/archbashstrap

I don't see an uglyness difference between the pacman cache and a bootstrap cache. It's just that we need more code if we want to cache stuff ourselves.

Sure, we can try to revert all of their changes but we'd have to stay updated on their dockerfile changes so we can check if there's new stuff that we don't want.

I agree as that's essentially exactly the same what my current bash scripts do, but utilizing podman containers instead of arch-chroot which is WAY cleaner. Good idea 👍

Good points, thanks for bringing them up!
You're right, Pacstrap is definitely the best bet.

Here's another reason for using Pacstrap. I'm working on a CachyOS image right now, first using Arch Linux bootstrap-x86_64.tar.gz and then having to overwrite packages with equivalents from CachyOS's repository ends up introducing unnecessary overhead which can be eliminated by using their repository from the beginning with Pacstrap

We might actually be able to prevent the slow rootfs copy by using 2 dockerfiles instead of a single multi-stage dockerfile:

  • the first one pacstraps into a podman volume
  • the second one gets started using --rootfs instead of an image

Yupp, that's exactly what I meant by re-usable base image 🙂
Wow thanks for digging up --rootfs, I tried using a volume for / earlier but I encountered some weird behavior and figured it wasn't a good practice. I'll give it another go!


On side note
Other than deleting and re-creating a OSTree repository, do you know if there is any way to reset the OSTree repository to have 0 commits (to clean boot entries in GRUB2 and save storage from having a large repository)?

@GrabbenD
Copy link
Author

GrabbenD commented Sep 29, 2023

the second one gets started using --rootfs instead of an image

Just a quick update:

  • Turns out --rootfs is only available in podman run
  • I came across --build-context which can pass values to FROM, RUN & COPY but unfortunately the directory path context could only be used in COPY instruction
  • Tried mounting a pacstrapped rootfs to / with $ podman build --file Containerfile.host --volume /tmp/rootfs:/ using:
    FROM scratch
    RUN ls -l
    But this hack wasn't successful: mount '/var/tmp/buildah3749765662/mnt/buildah-bind-target-0' to '': Invalid argument
  • Using --build-context to COPY files from /mnt/rootfs volume to / in a new image has identical performance as using COPY in a multi-stage build to copy data from stage 0 to stage 1 (meaning there's no performance uplift from a bind mount)
  • Out of curiosity I tried doing ADD /rootfs/* / but this is a lot slower and fails due to symlinks
  • It's possible to access files from pacstrapped rootfs directory instantly in a new image with:
     # --build-context="rootfs"="/tmp/rootfs"
     FROM archlinux
     RUN mount=type=bind,source=rootfs,destination=/mnt ls -l /mnt
    But I couldn't come up with any good way to use the files as replacing archlinux with scratch has no PATH (there's no commands to do anything with these files)

I failed to find anything else which could help us with getting rid of COPY after Pacstrap:

Well, the COPY instruction add +8.5s (on highend hardware). It's not that bad at the end of the day if there's no other alternative. After the base image has been built, the next image where customization takes place wont be slowed down by this unless the user chooses to rebuild the base.

@M1cha
Copy link
Owner

M1cha commented Sep 30, 2023

On side note
Other than deleting and re-creating a OSTree repository, do you know if there is any way to reset the OSTree repository to have 0 commits (to clean boot entries in GRUB2 and save storage from having a large repository)?

No, but I never have more than two grub entries though that might be an artifact of me not having migrated to the new grub setup yet. Fedora did have like 3 or 4 entries but that logic might have come from their rpm-ostree wrapper.

Another thing I kinda forgot about through all these discussions is that after you built the rootfs in a container you still need to do a commit. It looks like that's what you're doing here:
https://github.com/GrabbenD/ostree-utility/blob/87dc221bee85b6a662d2a0cd37826c9281d12efb/ostree.sh#L137

So you have to copy the base rootfs, then when building the final rootfs podman has to copy it to wherever they store images, then when you want to export it, podman has to tar it, you untar it and copy it to some disk location.

I don't think I like that process. I'd probably prefer a combination of both our approaches: keep using podman instead of arch-chroot, but without Containerfiles and using --rootfs and bash scripts instead. That way you can prevent both copies. And it looks like you repo now requires a bunch of bash scripts as well so it also became more than "lets build everything with a simple Containerfile".

@GrabbenD
Copy link
Author

Fedora did have like 3 or 4 entries but that logic might have come from their rpm-ostree wrapper.

Maybe this can be hidden with BLS?

podman has to tar it, you untar it and copy it to some disk location.

This indeed affects the performance, I did a experiment last week.
In practice I can't use tar with Containerfile until this is resolved containers/buildah#5093
However, I was still able to benchmark it
Here's the relevant results:

# [TAR] export rootfs
$ time sh -c "rm -rf ./rootfs.tar && podman build -f Containerfile -o dest=./rootfs.tar,type=tar"
real    0m4.892s
user    0m4.021s
sys     0m7.704s

# [TAR] commit to OSTree
$ time sh -c 'ostree commit --repo=/ostree/repo --tree=tar=rootfs.tar --tar-autocreate-parents --branch=archlinux/latest -v && ostree admin deploy --sysroot=/ --karg="root=LABEL=SYS_ROOT" --karg="rw" --os=archlinux --no-merge --retain archlinux/latest'
real    0m10.669s
user    0m5.120s
sys     0m4.598s

vs

# [DIR] export rootfs (this breaks file permissions) *invalid*
# $ time sh -c "rm -rf ./rootfs && podman build -f Containerfile -o dest=./rootfs,type=local"
# real    0m5.811s
# user    0m5.839s
# sys     0m10.875s

# [DIR] time sh -c 'rm -rf rootfs && podman export $(podman create rootfs bash) | tar -xC rootfs'
real    0m6.795s
user    0m2.011s
sys     0m9.950s

# [DIR] commit to OSTree
$ time sh -c 'ostree commit --repo=/ostree/repo --tree=dir=rootfs --branch=archlinux/latest -v && ostree admin deploy --sysroot=/ --karg="root=LABEL=SYS_ROOT" --karg="rw" --os=archlinux --no-merge --retain archlinux/latest'
real    0m10.185s
user    0m4.118s
sys     0m5.133s

In summary:

  • Exporting rootfs as tar from Podman was noticeably faster
  • Commit of a directory to OSTree was a few milliseconds faster than tar each time
  • Fun fact, removing old build (rm) speeds up the next command in each test

keep using podman instead of arch-chroot, but without Containerfiles and using --rootfs and bash scripts instead.

This would result in cleaner code for sure!
Only downside is losing out on build layer caching
I found this cache to be quite useful when trying new changes after system/base setup is done (e.g. quickly trying a new WM/DE or just adding a package like htop). This made it possible to continue from the last layer instead of from scratch which takes a total of 0m20s for a new deployment instead of 1m11s (in the version which uses NoExtract)

If we want to Pacstrap each new deployment in podman run without Containerfile, I did a rough estimate:

Podman Containerfile 1 (stage0) pacstrap = +28s
Podman Containerfile 1 (stage1) COPY = +8.5s <-- bottleneck
Podman Containerfile 2 (stage0) base setup + kernel + initramfs + bootloader + customization) = +62.5
Podman rootfs export = +6.8s <-- bottleneck
OSTree commit + deploy = +10.2s
Total = 1m56s (with Pacman cache)

Just removing the bottlenecks saves around 15.3s (but the real world number would be higher as creating cache for each RUN in Containerfile isn't instant plus the time it takes to COMMIT the final image).

Well from experience, layer caching is quite a big drain on storage space and you can't use it forever (usually after 1-2 weeks Arch's repository has a complete new set of packages which breaks new installs and this cache is useless if you want to update (without pacman -Syu))

Just food for thought ^

it looks like you repo now requires a bunch of bash scripts as well so it also became more than "lets build everything with a simple Containerfile".

Yepp, the script is designed to be used in a very specific way with a small room for customization
This wouldn't be suitable for Arch Linux wiki or as a AUR CLI helper
The final toolset would have to be more unopinionated/modular

@M1cha
Copy link
Owner

M1cha commented Sep 30, 2023

Personally, I always run a full pacstrap and never let pacman do an update because that removes the risk for leaving behind pacnew/pacdiff. For the number and kind of packages I have it rebuilds pretty fast when using a package cache. We seem to have different expectations for the speed though. For me 1 minute is a good time for building and committing from scratch. I also don't have a need for testing the resulting system in a container since my changes are minimal. I install packages, add config files and that's it.

That being said, it's fine if we have different ways to build a rootfs for different use cases. We'll just have to figure out which ways are the best fit for which use cases and then document them properly.

@M1cha
Copy link
Owner

M1cha commented Dec 22, 2023

@GrabbenD I know that you have continued to turn your demo into a generic tool, but I've done the same. I think I've come up with something that can fit both our usecases and even improves upon both of them. Here's a few key points that allowed for that:

  • I have given up on rootless building for now. It is possible but I don't see that many advantages given that the built image gains full root access as soon as you boot into the ostree anyway.
  • I'm now building a container that can be used for pacstrapping which is based on the official, latest bootstrap image. It's downloaded, verified and set up in the way described on the arch wiki. Note that this shall not be used as a base for your rootfs because it wasn't designed for that by the arch maintainers.
  • I'm now using podman instead of arch-chroot.
  • The changes, which are needed to make a rootfs bootable using ostree, are done in a non-persistent way. That removes one of the disadvantages of a directory over a Containerfile. This is done using a readonly overlayfs on top of the root directory.
  • We don't need to export a tarball because we can just mount another containers image at a directory of a new container.
  • With the previous two points, I'm now actually running ostree commit inside a container which has a readonly mount of the desired rootfs and a RW mount of the hosts ostree repo.
  • I've split things up into subcommands with small scopes to make this tool more flexible.

An issue I encountered:
overlayfs filesystems can't be stacked indefinitely, so for container-rootfs' I actually can't use a readonly overlayfs and I have to use rsync to make a copy instead. Performance-wise this should be similar to your export method though.

You can find a first version of this on the branch wip/generic of the repository (currently at a10cdbb). Please share your thoughts.

@M1cha
Copy link
Owner

M1cha commented Dec 22, 2023

Here's also some benchmarks with a fully populated pacman cache and while installing base amd-ucode intel-ucode linux-zen btrfs-progs:

# time ./run --pacman-cache cache build_rootfs_container
real    0m59.026s
user    0m30.336s
sys     0m36.108s

# time ./run --pacman-cache cache commit_rootfs_container -- -b test
real    0m17.179s
user    0m0.066s
sys     0m0.079s

# time ./run --pacman-cache cache pacstrap_rootfs_directory base amd-ucode intel-ucode linux-zen btrfs-progs
real    0m26.654s
user    0m0.087s
sys     0m0.101s

# time ./run --pacman-cache cache commit_rootfs_directory -- -b test
real    0m5.760s
user    0m0.059s
sys     0m0.079s

@GrabbenD
Copy link
Author

GrabbenD commented Dec 25, 2023

Great job!

I took a peak at your new branch and the design of your wrapper makes a lot of sense for AUR and Arch Linux Wiki! I think you should go ahead and submit it when you feel like you're happy with the codebase to get more users onboard the OSTree train :)

@M1cha
Copy link
Owner

M1cha commented Jan 24, 2024

I think this issue is very much solved now. The tool is now very generic and we have an (unofficial) guide on the arch wiki. @GrabbenD A few insights that you might be interested in:

  • ostree actually works with fully standard grub2 installations. All we needed to do was to create a grub.cfg symlink. It also works without UEFI now. The new codebase also has VM-based tests to verify a few common setups. (I still have to document how to run those tests).
  • Thanks to export BUILDAH_LAYERS=false even the Containerfile-approach is much faster now.

@M1cha M1cha closed this as completed Jan 24, 2024
@GrabbenD
Copy link
Author

Neat
Thanks for the update!

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

No branches or pull requests

2 participants