Image build time improvements (#10104)

* [build]: Patch debootstrap to not unmount the host's /proc filesystem

Currently, when the final image is being built (sonic-vs.img.gz,
sonic-broadcom.bin, or similar), each invocation of sudo in the
build_debian.sh script takes 0.8 seconds to run and execute the actual
command. This is because the /proc filesystem in the slave container has
been unmounted somehow. This is happening when debootstrap is running,
and it incorrectly unmounts the host's (in our case, the slave
container's) /proc filesystem because in the new image being built,
/proc is a symlink to the host's (the slave container's) /proc. Because
of that, /proc is gone, and each invocation of sudo adds 0.8 seconds
overhead. As a side effect, docker exec into the slave container during
this time will fail, because /proc/self/fd doesn't exist anymore, and
docker exec assumes that that exists.

Debootstrap has fixed this in 1.0.124 and newer, so backport the patch
that fixes this into the version that Bullseye has.

Signed-off-by: Saikrishna Arcot <sarcot@microsoft.com>

* [build_debian.sh]: Use eatmydata to speed up deb package installations

During package installations, dpkg calls fsync multiples times (for each
package) to ensure that tht efiles are written to disk, so that if
there's some system crash during package installation, then it is in at
least a somewhat recoverable state. For our use case though, we're
installing packages in a chroot in fsroot-* from a slave container and
then packaging it into an image. If there were a system crash (or even
if docker crashed), the fsroot-* directory would first be removed, and
the process would get restarted. This means that the fsync calls aren't
really needed for our use case.

The eatmydata package includes a library that will block/suppress the
use of fsync (and similar) system calls from applications and will
instead just return success, so that the application is not blocked on
disk writes, which can instead happen in the background instead as
necessary. If dpkg is run with this library, then the fsync calls that
it does will have no effect.

Therefore, install the eatmydata package at the beginning of
build_debian.sh and have dpkg be run under eatmydata for almost all
package installations/removals. At the end of the installation, remove
it, so that the final image uses dpkg as normal.

In my testing, this saves about 2-3 minutes from the image build time.

Signed-off-by: Saikrishna Arcot <sarcot@microsoft.com>

* Change ln syntax to use chroot

Signed-off-by: Saikrishna Arcot <sarcot@microsoft.com>
This commit is contained in:
Saikrishna Arcot 2022-04-19 12:22:16 -04:00 committed by GitHub
parent 598ab99469
commit 330777e795
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 0 deletions

View File

@ -113,6 +113,12 @@ sudo cp files/apt/apt.conf.d/{81norecommends,apt-{clean,gzip-indexes,no-language
## Note: set lang to prevent locale warnings in your chroot
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y update
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y upgrade
echo '[INFO] Install and setup eatmydata'
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y install eatmydata
sudo LANG=C chroot $FILESYSTEM_ROOT ln -s /usr/bin/eatmydata /usr/local/bin/dpkg
echo 'Dir::Bin::dpkg "/usr/local/bin/dpkg";' | sudo tee $FILESYSTEM_ROOT/etc/apt/apt.conf.d/00image-install-eatmydata > /dev/null
echo '[INFO] Install packages for building image'
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y install makedev psmisc
@ -586,6 +592,10 @@ scripts/collect_host_image_version_files.sh $TARGET_PATH $FILESYSTEM_ROOT
# Remove GCC
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y remove gcc
# Remove eatmydata
sudo rm $FILESYSTEM_ROOT/etc/apt/apt.conf.d/00image-install-eatmydata $FILESYSTEM_ROOT/usr/local/bin/dpkg
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y remove eatmydata
## Clean up apt
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get -y autoremove
sudo LANG=C chroot $FILESYSTEM_ROOT apt-get autoclean

10
rules/debootstrap.dep Normal file
View File

@ -0,0 +1,10 @@
SPATH := $($(DEBOOTSTRAP)_SRC_PATH)
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/debootstrap.mk rules/debootstrap.dep
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
DEP_FILES += $(shell git ls-files $(SPATH))
$(DEBOOTSTRAP)_CACHE_MODE := GIT_CONTENT_SHA
$(DEBOOTSTRAP)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
$(DEBOOTSTRAP)_DEP_FILES := $(DEP_FILES)

9
rules/debootstrap.mk Normal file
View File

@ -0,0 +1,9 @@
# debootstrap package
DEBOOTSTRAP_VERSION = 1.0.123
export DEBOOTSTRAP_VERSION
DEBOOTSTRAP = debootstrap_$(DEBOOTSTRAP_VERSION)_all.deb
$(DEBOOTSTRAP)_SRC_PATH = $(SRC_PATH)/debootstrap
SONIC_MAKE_DEBS += $(DEBOOTSTRAP)

View File

@ -992,6 +992,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
$$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \
$$(addprefix $(TARGET_PATH)/,$$(SONIC_PACKAGES_LOCAL)) \
$$(addprefix $(FILES_PATH)/,$$($$*_FILES)) \
$(addsuffix -install,$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(DEBOOTSTRAP))) \
$(if $(findstring y,$(ENABLE_ZTP)),$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(SONIC_ZTP))) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_UTILITIES_PY3)) \
$(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PY_COMMON_PY2)) \

3
src/debootstrap/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
debootstrap*.udeb
debootstrap*.dsc
debootstrap-*/

24
src/debootstrap/Makefile Normal file
View File

@ -0,0 +1,24 @@
.ONESHELL:
SHELL = /bin/bash
.SHELLFLAGS += -e
MAIN_TARGET = debootstrap_$(DEBOOTSTRAP_VERSION)_all.deb
$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
# Remove any stale files
rm -rf ./debootstrap-$(DEBOOTSTRAP_VERSION) ./debootstrap*.{deb,udeb,dsc}
# Get source package
dget https://deb.debian.org/debian/pool/main/d/debootstrap/debootstrap_$(DEBOOTSTRAP_VERSION).dsc
# Build source and Debian packages
pushd debootstrap-$(DEBOOTSTRAP_VERSION)
patch -p1 -i ../proc-mount.patch
dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR)
popd
# Move the newly-built .deb packages to the destination directory
mv $(DERIVED_TARGETS) $* $(DEST)/
$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET)

View File

@ -0,0 +1,34 @@
From 87cdebbcad6f4e16ba711227cbbbd70039f88752 Mon Sep 17 00:00:00 2001
From: YunQiang Su <syq@debian.org>
Date: Mon, 7 Sep 2020 09:29:37 +0800
Subject: [PATCH] stage1: re-mkdir /proc instead of umount if it is a symlink
In docker, the TARGET/proc will be a symlink to /proc.
And if the docker instance is called with --privileged, it will umount
the /proc of the whole instance in setup_proc.
---
debian/changelog | 3 +++
functions | 7 ++++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/functions b/functions
index 1ac63f7..065320d 100644
--- a/functions
+++ b/functions
@@ -1183,7 +1183,12 @@ setup_proc () {
umount_on_exit /dev/shm
umount_on_exit /proc
umount_on_exit /proc/bus/usb
- umount "$TARGET/proc" 2>/dev/null || true
+ if [ -L "$TARGET/proc" ];then
+ rm -f $TARGET/proc
+ mkdir $TARGET/proc
+ else
+ umount "$TARGET/proc" 2>/dev/null || true
+ fi
# some container environment are used at second-stage, it already treats /proc and so on
if [ -z "$(ls -A "$TARGET/proc")" ]; then
--
GitLab