Closed pronvit closed 4 years ago
@pronvit
If you're interested, I can provide more details how to set it up
Please, by all means. This is something i've been meaning to do for a long time, however, without a nudge in the right direction and flooded with other tasks, not been able to start it.
creating images on real boards seems to be an overkill to me.
Yep, it is a nightmare, it would be much more beneficial if we could build/create the images via Qemu and chroot. Maybe its something we could all work on together? @MichaIng aswell?
Here you go http://github.com/pronvit/DietPi
Procedure
qemu-user-static
packagesudo su
- don't run chroot with sudo as otherwise it will get your user home folder path instead of /root../prep IMAGE_FN
/root/PREP_SYSTEM_FOR_DIETPI.sh
./post IMAGE_FN
, this will generate DietPi.img, if not, run ./cancel
to unmount stuff.Notes
Basically I just commented out stuff that doesn't work inside chroot:
dietpi-set_dphys-swapfile 0
fails because swapoff
fails, I don't think it's even needed in chroot.dietpi-set_cpu
fails because /sys isn't mounted so it can't determine supported governors. /sys from the host obviously can't be used, so I don't know.dietpi-ramdisk
directly because starting/stopping a service isn't possible.dietpi-drive_manager
invocation to generate fstab because in chroot nothing is mounted and instead the original fstab content needs to be preserved, so instead I APPEND to it.A big difference is that with chroot, any board-specific first boot procedures are not performed before running DietPi script. I only have a Tinker Board so could only test on it.
Its /etc/init.d/rockchip.sh
script definitely fails but what it does is related to GPU or to stuff that's replaced by DietPi scripts anyway. Need to check per-board if this causes any problems and if any additional packages need to be left for first boot scripts to run.
Unfortunately, even with the original DietPi image I'm having issues with WiFi - it's not getting IP address most of the time, so I didn't test much after the first boot.
Feel free to do whatever with the code as I guess my changes are not really suitable for a proper PR and merging.
@pronvit @Fourdee I played around with qemu and chroot for a short time with the aim to create RPi images and do dev/testing.
I used qemu as VM on Windows Host, but found it to be extremely slow and didn't work to boot a DietPi image, as some manual fstab/cmdline.txt adjustments are needed and DietPi overwrites/readjusts them on 1st boot.
I tried chroot then as well with a test system on USB stick, but for development the issue is, that you are not able to somehow "reboot" or re-initiate the system. For just running the preparation script it should work fine, indeed.
How does the combination of qemu and chroot work now? Is it started as real VM then, instead of a "dead" image, where you chroot inside? On the other hand, then /proc /sys /dev etc should be present.
Hardware info
Swapfile
fstab
After all, I guess it is still the safest way to create images directly on the machines. With some SD cards it is also not too much more effort. Flash/install pre-image and running preparation script must be done anyway once, or what do you mean by nightmare @Fourdee ? Performance on slow boards I can think of?
Why do you want to "reboot", "re-initiate" or somehow boot the system at all?
@pronvit
Why do you want to "reboot", "re-initiate" or somehow boot the system at all?
Not necessarily for image creation, just mentioned it as I was looking for some testing/development solutions as well, where e.g. some installation/configuration steps need system reboot or sometimes you want to test reboot behaviour especially. But this requires a VM at least. For this reason I am interested in what role qemu plays here.
For running commands inside chroot. Just look at my prep
script, the last line.
@pronvit
Many thanks for this 👍 I really appreciate it. I've got side-tracked with other tasks at the moment, however, once I can, i'll take an in-depth look into your commit and guide.
what do you mean by nightmare @Fourdee ? Performance on slow boards I can think of?
@MichaIng Yep, basically, and the time to read SD card to image, risk of SD card corruption during read, etc etc. Its just a lengthy process I feel with @pronvit's guide and commit, we may be able to achieve something more refined for image creation and updating them quicker.
Flagged for v6.9, so it doesn't get put to the bottom of pile.
I had another look into this. And indeed we might want to give it a try.
Just thought through a bid again. Understand chroot m qemu-arm-static /bin/bash
now: Instead of simply chroot
with the host system arch it emulates an ARM system inside the chroot, otherwise executing ARM binaries from e.g. x86 host of course fails. No sort of a mix of a simply chroot and a real VM, as far as I understood 😄.
Service starts (systemctl (re)start) can be easily replaced by executing the ExecStart directly, if required. fstab
pre-creation can be derived from the present fstab, however we should be careful there, of course using the whole method for each device individually first (and verify).
As well the possible existing swapfile location can be derived from fstab. But I doubt that any fresh images comes with an existing swap file anyway?
All other hardware related steps should be or are already done one first boot of destination system anyway.
Not sure if ARMv6/7/8 need different qemu binaries?
Just tested with a Raspbian Lite image on VM:
root@VM-Stretch:/mnt# chroot /mnt/rpi qemu-arm-static /bin/bash
root@VM-Stretch:/# hostname
bash: /bin/hostname: cannot execute binary file: Exec format error
root@VM-Stretch:/# nano
bash: /bin/nano: cannot execute binary file: Exec format error
Then I remembered that it should not work to emulate inside an emulation. So I tried on x86 notebook, but same.
cat /proc/cpuinfo
does not show vmx
or svm
flag, so it looks like my notebook as well does not support emulation 🤔?
Yeah its an old Acer emachines D725, so not unlikely.
Im running qemu emulation this way:
First I Mount the .img,
/etc/rc.local/
&& reboot
at the end of the row .Unmount the image and run QEMU with the noreboot flag.
I remount my .img, clean my /etc/rc.local
, Unount
Then Im ready for the next step.
--- Qemu is slow cuz it support only one core.
This is my QEMU cmds : For raspbian:
qemu-system-arm
-kernel ./qemu-rpi-kernel-master/kernel-qemu-4.14.79-stretch \
-cpu arm1176 \
-m 256 \
-M versatilepb \
-no-reboot \
-serial stdio \
-dtb ./qemu-rpi-kernel-master/versatile-pb.dtb \
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
-drive file=myimage.img,index=0,media=disk,format=raw \
-net user,hostfwd=tcp::9002-:22 \
-net nic
For debian X86_64:
qemu-system-x86_64
-m 256 \
-no-reboot \
-serial stdio \
-boot d \
-cdrom "myiso.iso" \
-drive file=mydrive.img,index=0,media=disk,format=raw \
-net user,hostfwd=tcp::9003-:22 \
-net nic
)
@FredericGuilbault Many thanks for sharing
So you run QEMU as VM.
Qemu is slow cuz it support only one core.
And no VT-x/AMD-V acceleration AFAIK.
The idea above is to run QEMU not as VM but only use it to execute ARM binaries: qemu-static
vs qemu-system
This reduces much overhead of course but reduces the chance to catch certain issues with the image (boot sequence). So your way to "boot" as VM via QEMU is somewhere in the middle between how we do not (boot on real machine) and the chroot method.
Actually the final image should be anyway ALWAYS tested one time (at least) on a real machine, verifying first run setup + boot sequence runs without issues, checking the boot/journalctl log for any anormalities. As long as we do not create our images from scratch there are simply too much possibilities of changes/conflicting bootloader/kernel configurations, first run scripts that come from the base-image and stuff.
Taken this, the fastest method would be indeed to use:
All these steps can be done within a single script. Then some can test the image on a real machine before it is released.
Work for me ™
thisSbc=RPi-ARMv6
IMAGE=./work/$thisSbc/raspbian.img
ROOTFS="$(pwd)/work/$thisSbc/rootfs"
BOOTFS="$(pwd)/work/$thisSbc/rootfs/boot"
#mount partitions
kpartx -sa $IMAGE
mount /dev/mapper/loop0p2 $ROOTFS
mount /dev/mapper/loop0p1 $BOOTFS
# mount binds
mount --bind /dev $ROOTFS/dev/
mount --bind /sys $ROOTFS/sys/
mount --bind /proc $ROOTFS/proc/
mount --bind /dev/pts $ROOTFS/dev/pts
# ld.so.preload fix
sed -i 's/^/#/g' $ROOTFS/etc/ld.so.preload
# copy qemu binary
cp /usr/bin/qemu-arm-static $ROOTFS/usr/bin/
# This is where the magic append
chroot $ROOTFS /bin/bash << EOF
ls /home/
apt-get install -y feh
EOF
# revert ld.so.preload fix
sed -i 's/^#//g' $ROOTFS/etc/ld.so.preload
# unmount
umount $ROOTFS/dev/
umount $ROOTFS/sys/
umount $ROOTFS/proc/
umount $ROOTFS/dev/pts
umount $BOOTFS
umount $ROOTFS
kpartx -d $imgFile
exit
It's obv broken if you try on DietPi due to the fact that the first run scripts haven't been run yet.
Emulation, chroot and automation will never replace real world testing and they come with their load of new issues and limitations. The point for me is productivity and reproducibility. It's often just a way to document the steps needed to have something done.
The point for me is productivity and reproducibility. It's often just a way to document the steps needed to have something done.
Jep that is indeed a large benefit! Having things documented and clear defined steps to reproduce.
Hi, im adding this article to the knowlege base.
It explain diff between qemu-armhf
and qemu-debootstrap
and mainly why qemu-debootstrap
is faster.
http://logan.tw/posts/2017/01/21/introduction-to-qemu-debootstrap/
*note that pi-gen is using qemu-debootstrap
,
The limitation is: The host operating system MUST be debian or a debian derivative.
@FredericGuilbault Many thanks for posting. Okay actually reading through it and checking the package docs, this should be indeed the preferred method to create DietPi images from scratch, as long as kernel+bootloader(+other required firmware) is handy to install, e.g. via 3rd party APT repo (archive.raspberrypi.org, apt.armbian.com, fuzon.co.uk/meveric/, ...).
schroot
seems to automate these bind mount/symlink creation required to access host hardware/devices from within the chroot. Very handy.I will play around with this soon, first to create an x86_64 image, so basically replacing Debian mini.iso installer with debootstrap + schroot, and see if DietPi-PREP can then run as before, in case after installing systemd to the target system.
When this went well, trying the same with qemu-debootstrap
.
cp -a
. Not 100% sure about the benefit of rsync here since cp -ax
has exactly the same result then rsync -aHAXx
on an empty target, but is an essential always present tool. However always creating a fresh img file should be also the method of DietPi-Imager by default.rsync is sometime/often faster then cp, that might justs be a performance concern.
I wonder if BTRFS also leave holes or it's just an ext4 problem? I remember messing with this when ext4 was new(long time ago enh) and copying to a new partition was the prefered method at the time.
We could then even create a FAT boot partition on all our images, so kernel/bootloader and dietpi.txt can always be modified from Windows system?
+1 I think it's not just about functionality but also performance and SDcard wear. ...And FOSS
@FredericGuilbault
rsync is sometime/often faster then cp, that might justs be a performance concern.
Possibly, could run some tests on next image creation. However for me at least it doesn't matter if it takes 1 or 1.5 minutes, I think it was even much faster since only ~650M data...
I wonder if BTRFS also leave holes or it's just an ext4 problem? I remember messing with this when ext4 was new(long time ago enh) and copying to a new partition was the prefered method at the time.
The file system type would be bad if it would not leave holes. I mean to reduce disk writes it totally makes sense to not move all data around all the time only to close holes. Usually you do not care where data is stored physically. Of course new data should usually be written into the holes first, but I think this is done on ext4 as well. The issue is that DietPi-PREP removes much more data than it adds, so holes are just expected. It would be just nice to have a tool that explicitly moves all data physically to the partition/disk start.
BTRFS is nothing that makes sense too soon, I think, there are simply too much boards with old kernel versions. E.g. I think swapfiles on BRTFS just became possible with kernel 4.18 or something.
+1 I think it's not just about functionality but also performance and SDcard wear. ...And FOSS
I just remember (will verify before attempting the first debootstrap RPi image) that RPi cannot boot from ext4 actually, so the FAT boot partition is required anyway 😅.
You mean performance and SDcard wear will benefit from a single ext4 partition? Only bootloader and kernel are there, read a single time on boot and never touched afterwards on usual operation. So I guess there is no measurable impact of having a separate /boot partition.
https://sourceforge.net/projects/ext2fsd/ no dev since 2 years, many open bug reports in relation with Windows 10. Seems to be still not safe to use for writing to an ext4 partition. I guess Windows Subsystem for Linux (WSL) is capable of doing this safely, but it is only available on Windows 10 Pro edition and upwards (AFAIK?). And of course it is quite an overhead of installing it just to edit a single text file...
You mean performance and SDcard wear will benefit from a single ext4 partition?
From what I have read on armbian forum BRTFS cause less internal less read and write then ext4 but I did not validate this info, take it as a rhumor.
I would vouch for having /boot partition in FAT32 for all SBC (even if it's not needed in some case like VirtualBox) it's a question of conviency and standardisation across OS and a tradition when it come about booting on SDcard/USB.
I also agree that 99% of W$ users won't install an outdated driver for editing a single file. This would be a suicide move in term of adoption of Dietpi.
Im working slowly on this but im working on a script to build lysmarine on top of dietpi. Wich is quite similar to building Dietpi in top other OS ( + lysmarine include compiling C++ projects and some nodejs library not available for armV6 )
IK it's not anyone priority ATM but I would totally agree Make it a common ground for both project. I kinda just need a repo to push to and some feedpack from DietPi people to make sure it stay in the common ground and you guys/girls will be happy to use it.
("A repo to push to" as I think the build tool should be seperated form the build content )
@FredericGuilbault
From what I have read on armbian forum BRTFS cause less internal less read and write then ext4
Perhaps we could create some testing images based on BTRFS for systems which offer a current enough kernel (with latest BTRFS support improvements, e.g. swap files). I have to check again the kernel changelogs where I found this. Basis is indeed a build script that creates images from source. Converting/migrating an existing image is not a nice solution IMO. Then we can get some feedback and can ask for some FS benchmarks across different devices to verify the change is worth it.
I would vouch for having /boot partition in FAT32 for all SBC
I was thinking the same. However this is sadly not possible that easy, as in many cases the kernel, bootloader and dtoverlay packages either rely on symlinks and/or POSIX permissions, which is both not supported on FAT. We would require custom packages and e.g. initramfs hooks to work around this, which is currently impossible due to lack of man power and experience. So this can only be implemented on a per-device basis, for those devices where the kernel/bootloader/initramfs/firmware packages/scripts can handle it.
Im working slowly on this but im working on a script to build lysmarine on top of dietpi.
I hope that I find time soon to start with some build from scratch attempts, based on debootstrap and (s)chroot. That would be a much more transparent and cleaner solution.
I have check about schroot and I Don't think it ca do well for distribution purpus as it rely on configuration files located in the /etc/ of the host system. And I found it intrusive. I ended up using proot.
@FredericGuilbault
Jep, testing will show if it is still easier than chroot
(or proot
, don't know that) and manually setup the chroot environment (/dev /proc /sys /run(?) mounts and some others possibly).
Tried to fiddle around with qemu system emulation to get the RPi image booting on my Windows machine. No success with "native" methods, so using the kernel and dtb files from the image and any combination of machine, CPU and image/drive invocation that is usually mentioned on online guides.
Interesting is that the "raspi2" machine is never mentioned, seems to not work at all, what is it for then? There is a "raspi3" machine available as well, but aarch64 only, so cannot boot Raspbian, and no network support.
It seems that booting any Raspbian requires a special kernel file, most likely a dtb file as well. Those I could find in various guides, are totally outdated, not matching the current Raspbian images.
I am a bid disappointed that, if there are already "raspi" machines available, that those are not able to boot an image right the same way an RPi would do, so using the contained bootloader to then load kernel, dtb files etc right from the image. But perhaps that is not even possible, not sure about the borders or qemu hardware emulation in general.
IMO there is not much point (for our image creation process) in using ARM emulation, if one needs to use an external custom kernel and dtb (and in some cases even initrd), that do not match the ones from the image you want to create, CPU that does not match the one form the actual SBC, RAM size as well (in case of versatilepb
) etc. And we would need to fiddle around for every single SBC again, to find a working machine/CPU/kernel/dtb/initrd combination.
So qemu-static
is what I will go for instead. DietPi-PREP requires some adjustment for this: https://github.com/MichaIng/DietPi/issues/1775#issuecomment-389432521
/
/boot
and /boot/efi
mounts and re-add afterwards, since it is created without any physical mounts from within chroot.Finally chroot
+ qemu-static
works very well inside a VM. I just forgot to install binfmt-support.
Currently running large APT updates, mounting and some other tasks inside an DietPi RPi image. Works very well, only minor adjustments need to be done, e.g. /etc/ld.so.preload
which loads the raspi-copies-and-fills
overrides of course fails on an VM, leading to an error prompt on every single command. However this can be backed up and restored on chroot exit.
Very nice for cross-compiling as well, which was the initial reason to go on with this topic.
Ah now I found https://wiki.debian.org/RaspberryPi/qemu-user-static which mentions the ld.so.preload issue as well 😄.
Since resolvconf
is not and cannot be started, a temporary DNS entry must be created:
mv /etc/resolv.conf /etc/resolv.conf_bak
echo 'nameserver 8.8.8.8' > /etc/resolv.conf # Google DNS should always work, but can of course be chosen different
...
# Do your stuff ...
...
mv /etc/resolv.conf_bak /etc/resolv.conf
Hi, I think i might have some time in the next 2 weeks to work on dietpi. The thing I would like to do is having a way to avoid using ramfs in qemu. This would allow me to use dietpi software and partition stretching tool in on my build script.
1) Would you accept such PR
2) what would be the best place to work on this (And discuss about it ) ? Fork, project, PR.... ???
--Fred
@FredericGuilbault Not sure what you mean by "avoid ramfs in qemu"? You mean skip DietPi-RAMdisk?
I just created the first RPi image on VirtualBox VM via systemd-nspawn
: https://dietpi.com/downloads/images/testing/DietPi_RPi-ARMv6-Buster.7z
This allows to kinda "boot" the image. It invokes qemu-static
automatically with the required architecture, using in combination with binfmt-support
, and runs /sbin/init
inside the container. /dev /sys /proc and such are mounted automatically correctly and systemctl works, knowing its inside a container.
There are some minor workarounds required, e.g. dhcpcd
will completely spam the syslog (systemd-journald) with hundreds of error messages every second. I needed a failed (corrupted) build first to recognise this, and was wondering why the container/VM had such a high CPU consumption, being very slow, all the time 😆. And when testing/doing this for more images, most likely other workarounds need to be added before chrooting.
Here the script I'm having so far:
#!/bin/bash
FP_IMG='DietPi_RPi-ARMv6-Buster.img'
FS_IMG='3' # GiB
[[ -f $FP_IMG ]] || exit 1
apt-install dosfstools systemd-container binfmt-support qemu-user-static
LOOP_DEV=$(losetup -f)
ROOT_DEV="${LOOP_DEV}p2"
BOOT_DEV="${LOOP_DEV}p1"
# Raise image+partition+fs size if required, always run fsck
if (( $(stat -c %s $FP_IMG) < $FS_IMG*1024*1024*1024 )); then
truncate -s $(($FS_IMG*1024*1024*1024)) $FP_IMG
losetup -f $FP_IMG
partx -u $LOOP_DEV
e2fsck -f $ROOT_DEV
dosfsck $BOOT_DEV
sfdisk $LOOP_DEV -fN 2 <<< ',+,,,'
partx -u $LOOP_DEV
resize2fs $ROOT_DEV
else
losetup -f $FP_IMG
partx -u $LOOP_DEV
e2fsck -f $ROOT_DEV
dosfsck $BOOT_DEV
fi
[[ -d 'm' ]] || mkdir m
mount $ROOT_DEV m
mount $BOOT_DEV m/boot
# Workarounds
# - RPi on non-RPi: Move raspi-copies-and-fills ARM-specific mem*-versions out of the way
[[ -f 'm/etc/ld.so.preload' ]] && mv m/etc/ld.so.preload m/etc/ld.so.preload_bak
# - Mask services which cannot succeed in container
ln -sf /dev/null m/etc/systemd/system/dropbear.service
ln -sf /dev/null m/etc/systemd/system/dhcpcd.service
# dbus and systemd-logind required for container spawn
systemctl unmask dbus.socket dbus systemd-logind
systemctl start dbus.socket dbus systemd-logind
systemd-nspawn -bD m
systemctl stop systemd-logind dbus dbus.socket
systemctl mask systemd-logind dbus dbus.socket
# Revert workarounds
[[ -f 'm/etc/ld.so.preload_bak' ]] && mv m/etc/ld.so.preload_bak m/etc/ld.so.preload
rm m/etc/systemd/system/{dropbear,dhcpcd}.service
umount $BOOT_DEV
umount $ROOT_DEV
losetup -d $LOOP_DEV
/etc/fstab
and /boot/cmdline.txt
need to be fixed. But I guess at least for fstab it is possible to configure systemd-nspawn to solve it.Will create some more images the next days, add env vars for DietPi-Imager to completely automate it, so that all steps from pre-image til archive upload are one automated script call with variables.
However back to your initial idea, if I understood it correctly:
DietPi-RAMdisk is what I meant. If the chroot env can handle the mounts and syncs. There is no much need for my feature in reality. I would push this on some wishlist far away
On lysmarine Im using : https://github.com/lysmarine/lysmarine_gen/blob/0.9.x/buildscript/rpi_build.sh With : https://github.com/lysmarine/lysmarine_gen/blob/0.9.x/buildscript/common.sh
caching at every step and reusing them is a huge time saver on repetitive compilation,
Have you been able to make nodejs work in the chroot env ?
@FredericGuilbault
If the chroot env can handle the mounts and syncs. There is no much need for my feature in reality.
Normal chroot needs much tinkering to allow mounts and even systemctl use, AFAIK, but systemd-nspawn
can handle all of this correctly, at least if it calls the target systems init to "boot" it. What I like about it is that you can validate correct systemd unit order and execution (besides some, like hardware-dependent services are expected to fail of course), something I was missing from ordinary chroot. Its does not save the need to a real machine test (bootloader/kernel/firmware test/config), but allows deeper checking/cleaning right during the build process.
caching at every step and reusing them is a huge time saver on repetitive compilation,
Makes sense, however for DietPi itself it is minimal, since it's 2.6M only. I wished GitHub would allow to download the archive as bz2 or even 7z/xz 🤔.
Have you been able to make nodejs work in the chroot env ?
I did not try Node.js, will keep it in mind for next session.
but systemd-nspawn can handle all of this correctly, at least if it calls the target systems init to "boot" it.
Oh I didin't know about systemd-nspawn. Seem like a nice tool.
This is just a feeling but as is not a real environement booting seem like a receipt for overheads problems for something that is mainly just file manipulation. in all case it worth exploring.
I will check if it's possible to make DietPi-RAMdisk mount in chroot.
@FredericGuilbault
This is just a feeling but as is not a real environement booting seem like a receipt for overheads problems for something that is mainly just file manipulation. in all case it worth exploring.
Yeah it depends on what you want to of course. In case of our image building, IMO it makes sense, since we want to have all installers and systemctl behave as it was a real system, as close as possible, to trigger possible issues in the first place before doing real machine tests. As well simple things like having APT installs enabling and starting services do not work in simple chroot, so the end result would be simply different. For our own services of course we could place the required symlinks and trigger the ExecStart commands manually, but APT AFAIK cannot do this, thus steps are missing or installs can even fail. Same for /dev /proc /sys access. which of course can be manually mounted into chroot, but systemd-nspawn automates this and handles/limits access reasonably. It is not yet everything perfect, e.g. I am still dealing with the issue that it can see its own loop mounts, but not their UUID or PARTUUID, which leads to missing /boot and / mounts in fstab after DietPi-PREP.
I made a quick test and DietPi-RAM disk mount in chroot.
Nearly all new images have been created via systemd-nspawn
, proving it a very well working method: #2979
And DietPi-RAMdisk
btw is about to be removed: https://github.com/MichaIng/DietPi/pull/3402
I mark this issue as closed. I'll create a wrapper build script which:
So this is then something that can be done on any systemd-capable OS, basically 🙂.
However this is something I gonna start with after v6.29 release.
I'm now using DietPi scripts for my needs (building a minimal image booting to miRack) and I'm doing it in chroot environment. Qemu (you mentioned you don't have experience with it) isn't an issue here as you specify it only once to chroot into a mounted original OS image and then you don't even notice it (apart from being a VM, qemu can just transparently run binaries for other platforms).
I think apart from removing stuff I don't need, the only major thing I had to fix is that since you can't start services in chroot environment, mounting tmpfs on /DietPi needs to be done differently (I don't need it so I just removed all that).
If you're interested, I can provide more details how to set it up - creating images on real boards seems to be an overkill to me.