From 3c0c85e2eedb7d5fa26afcf06b9e4f8f539879a0 Mon Sep 17 00:00:00 2001 From: Saikrishna Arcot Date: Sun, 20 Feb 2022 10:17:11 -0800 Subject: [PATCH 1/3] [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 --- rules/debootstrap.dep | 10 ++++++++++ rules/debootstrap.mk | 9 +++++++++ slave.mk | 1 + src/debootstrap/.gitignore | 3 +++ src/debootstrap/Makefile | 24 ++++++++++++++++++++++ src/debootstrap/proc-mount.patch | 34 ++++++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+) create mode 100644 rules/debootstrap.dep create mode 100644 rules/debootstrap.mk create mode 100644 src/debootstrap/.gitignore create mode 100644 src/debootstrap/Makefile create mode 100644 src/debootstrap/proc-mount.patch diff --git a/rules/debootstrap.dep b/rules/debootstrap.dep new file mode 100644 index 000000000000..82ca11d7e4df --- /dev/null +++ b/rules/debootstrap.dep @@ -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) + diff --git a/rules/debootstrap.mk b/rules/debootstrap.mk new file mode 100644 index 000000000000..dc60599d5f3f --- /dev/null +++ b/rules/debootstrap.mk @@ -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) diff --git a/slave.mk b/slave.mk index 04a2675f83af..714947936a94 100644 --- a/slave.mk +++ b/slave.mk @@ -984,6 +984,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)) \ diff --git a/src/debootstrap/.gitignore b/src/debootstrap/.gitignore new file mode 100644 index 000000000000..2aa8324ad667 --- /dev/null +++ b/src/debootstrap/.gitignore @@ -0,0 +1,3 @@ +debootstrap*.udeb +debootstrap*.dsc +debootstrap-*/ diff --git a/src/debootstrap/Makefile b/src/debootstrap/Makefile new file mode 100644 index 000000000000..04e8646a1b2e --- /dev/null +++ b/src/debootstrap/Makefile @@ -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) + diff --git a/src/debootstrap/proc-mount.patch b/src/debootstrap/proc-mount.patch new file mode 100644 index 000000000000..93084576490a --- /dev/null +++ b/src/debootstrap/proc-mount.patch @@ -0,0 +1,34 @@ +From 87cdebbcad6f4e16ba711227cbbbd70039f88752 Mon Sep 17 00:00:00 2001 +From: YunQiang Su +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 + From eb257c0b46cabb92761b9041a0b7196abd32a657 Mon Sep 17 00:00:00 2001 From: Saikrishna Arcot Date: Tue, 22 Feb 2022 11:35:15 -0800 Subject: [PATCH 2/3] [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 --- build_debian.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build_debian.sh b/build_debian.sh index 61f6912829e9..a699eff383da 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -110,6 +110,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 ln -s /usr/bin/eatmydata $FILESYSTEM_ROOT/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 @@ -557,6 +563,10 @@ fi # 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 From 3a273df86068b24c7572e8a8e4ee2925dc9afba4 Mon Sep 17 00:00:00 2001 From: Saikrishna Arcot Date: Fri, 18 Mar 2022 13:54:26 -0700 Subject: [PATCH 3/3] Change ln syntax to use chroot Signed-off-by: Saikrishna Arcot --- build_debian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_debian.sh b/build_debian.sh index 011553d77e9a..1e1311a55393 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -116,7 +116,7 @@ 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 ln -s /usr/bin/eatmydata $FILESYSTEM_ROOT/usr/local/bin/dpkg +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'