diff --git a/Makefile b/Makefile index 58598cf6e2..aa515dee17 100644 --- a/Makefile +++ b/Makefile @@ -9,15 +9,17 @@ ROOTFS_BUILDER := $(MK_DIR)/rootfs-builder/rootfs.sh INITRD_BUILDER := $(MK_DIR)/initrd-builder/initrd_builder.sh IMAGE_BUILDER := $(MK_DIR)/image-builder/image_builder.sh +DISTRO := centos +BUILD_METHOD := distro +BUILD_METHOD_LIST := distro dracut AGENT_INIT ?= no -DISTRO ?= centos -ROOTFS_BUILD_DEST := $(PWD) -IMAGES_BUILD_DEST := $(PWD) -DISTRO_ROOTFS := $(ROOTFS_BUILD_DEST)/$(DISTRO)_rootfs +ROOTFS_BUILD_DEST := $(shell pwd) +IMAGES_BUILD_DEST := $(shell pwd) ROOTFS_MARKER_SUFFIX := _rootfs.done -DISTRO_ROOTFS_MARKER := $(ROOTFS_BUILD_DEST)/.$(DISTRO)$(ROOTFS_MARKER_SUFFIX) -DISTRO_IMAGE := $(IMAGES_BUILD_DEST)/kata-containers.img -DISTRO_INITRD := $(IMAGES_BUILD_DEST)/kata-containers-initrd.img +TARGET_ROOTFS := $(ROOTFS_BUILD_DEST)/$(DISTRO)_rootfs +TARGET_ROOTFS_MARKER := $(ROOTFS_BUILD_DEST)/.$(DISTRO)$(ROOTFS_MARKER_SUFFIX) +TARGET_IMAGE := $(IMAGES_BUILD_DEST)/kata-containers.img +TARGET_INITRD := $(IMAGES_BUILD_DEST)/kata-containers-initrd.img VERSION_FILE := ./VERSION VERSION := $(shell grep -v ^\# $(VERSION_FILE)) @@ -25,6 +27,34 @@ COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true) COMMIT := $(if $(shell git status --porcelain --untracked-files=no),${COMMIT_NO}-dirty,${COMMIT_NO}) VERSION_COMMIT := $(if $(COMMIT),$(VERSION)-$(COMMIT),$(VERSION)) +ifeq ($(filter $(BUILD_METHOD),$(BUILD_METHOD_LIST)),) + $(error Invalid BUILD_METHOD value '$(BUILD_METHOD)'. Supported values: $(BUILD_METHOD_LIST)) +endif + +ifeq (dracut,$(BUILD_METHOD)) + DISTRO := + TARGET_ROOTFS := dracut_rootfs + TARGET_ROOTFS_MARKER := $(ROOTFS_BUILD_DEST)/.dracut$(ROOTFS_MARKER_SUFFIX) + # dracut specific variables + DRACUT_KVERSION := + DRACUT_OVERLAY_DIR := $(MK_DIR)/dracut_overlay + DRACUT_DIR := $(MK_DIR)/dracut + DRACUT_CONF_DIR := $(DRACUT_DIR)/dracut.conf.d + DRACUT_OPTIONS := --no-compress --conf /dev/null --confdir $(DRACUT_CONF_DIR) + + ifneq (,$(DRACUT_KVERSION)) + # If a kernel version is not specified, do not make systemd load modules + # at startup + DRACUT_KMODULES := $(shell grep "^drivers=" $(DRACUT_CONF_DIR)/10-drivers.conf | sed -E "s,^drivers=\"(.*)\"$$,\1,") + else + DRACUT_OPTIONS += --no-kernel + endif + + ifeq (,$(DRACUT_OVERLAY_DIR)) + $(error DRACUT_OVERLAY_DIR cannot be empty) + endif +endif + # Set the variable to silent logs using chronic OSBUILDER_USE_CHRONIC := @@ -53,7 +83,17 @@ rootfs-%: $(ROOTFS_BUILD_DEST)/.%$(ROOTFS_MARKER_SUFFIX) .PRECIOUS: $(ROOTFS_BUILD_DEST)/.%$(ROOTFS_MARKER_SUFFIX) $(ROOTFS_BUILD_DEST)/.%$(ROOTFS_MARKER_SUFFIX):: rootfs-builder/% $(call silent_run,Creating rootfs for "$*",$(ROOTFS_BUILDER) -o $(VERSION_COMMIT) -r $(ROOTFS_BUILD_DEST)/$*_rootfs $*) - touch $@ + @touch $@ + +# To generate a dracut rootfs, we first generate a dracut initrd and then +# extract it in a local folder. +# Notes: +# - assuming a not compressed initrd. +.PRECIOUS: $(ROOTFS_BUILD_DEST)/.dracut$(ROOTFS_MARKER_SUFFIX) +$(ROOTFS_BUILD_DEST)/.dracut$(ROOTFS_MARKER_SUFFIX): $(TARGET_INITRD) + mkdir -p $(TARGET_ROOTFS) + cat $< | cpio --extract --preserve-modification-time --make-directories --directory=$(TARGET_ROOTFS) + @touch $@ image-%: $(IMAGES_BUILD_DEST)/kata-containers-image-%.img @ # DONT remove. This is not cancellation rule. @@ -73,19 +113,37 @@ $(IMAGES_BUILD_DEST)/kata-containers-initrd-%.img: rootfs-% all: image initrd .PHONY: rootfs -rootfs: $(DISTRO_ROOTFS_MARKER) +rootfs: $(TARGET_ROOTFS_MARKER) .PHONY: image -image: $(DISTRO_IMAGE) +image: $(TARGET_IMAGE) + +$(TARGET_IMAGE): $(TARGET_ROOTFS_MARKER) + $(call silent_run,Creating image based on "$(TARGET_ROOTFS)",$(IMAGE_BUILDER) -o $@ "$(TARGET_ROOTFS)") -$(DISTRO_IMAGE): $(DISTRO_ROOTFS_MARKER) - $(call silent_run,Creating image based on "$(DISTRO_ROOTFS)",$(IMAGE_BUILDER) "$(DISTRO_ROOTFS)") .PHONY: initrd -initrd: $(DISTRO_INITRD) +initrd: $(TARGET_INITRD) -$(DISTRO_INITRD): $(DISTRO_ROOTFS_MARKER) - $(call silent_run,Creating initrd image based on "$(DISTRO_ROOTFS)",$(INITRD_BUILDER) "$(DISTRO_ROOTFS)") +ifeq (distro,$(BUILD_METHOD)) +$(TARGET_INITRD): $(TARGET_ROOTFS_MARKER) + $(call silent_run,Creating initrd image based on "$(TARGET_ROOTFS)",$(INITRD_BUILDER) "$(TARGET_ROOTFS)") +else +$(TARGET_INITRD): $(DRACUT_OVERLAY_DIR) + @echo Creating initrd image based on the host OS using dracut + dracut $(DRACUT_OPTIONS) --include $< / $@ $(DRACUT_KVERSION) +endif + +# Notes on overlay dir: +# - If user specified any kernel module in the dracut conf file, +# we need to make sure these are pre-loaded at startup using +# systemd modules-load.d +$(DRACUT_OVERLAY_DIR): + mkdir -p $@ + # Modules preload + $(ROOTFS_BUILDER) -o $(VERSION_COMMIT) -r $@ + mkdir -p $@/etc/modules-load.d + echo $(DRACUT_KMODULES) | tr " " "\n" > $@/etc/modules-load.d/kata-modules.conf .PHONY: test test: @@ -140,7 +198,7 @@ install-scripts: .PHONY: clean clean: - rm -rf $(DISTRO_ROOTFS_MARKER) $(DISTRO_ROOTFS) $(DISTRO_IMAGE) $(DISTRO_INITRD) + rm -rf $(TARGET_ROOTFS_MARKER) $(TARGET_ROOTFS) $(TARGET_IMAGE) $(TARGET_INITRD) $(DRACUT_OVERLAY_DIR) # Prints the name of the variable passed as suffix to the print- target, # E.g., if Makefile contains: diff --git a/README.md b/README.md index 05911657a0..b39bfb4fae 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,25 @@ # osbuilder -* [Introduction](#introduction) -* [Terms](#terms) -* [Usage](#usage) - * [Rootfs creation](#rootfs-creation) +* [osbuilder](#osbuilder) + * [Introduction](#introduction) + * [Terms](#terms) + * [Building](#building) + * [Rootfs creation](#rootfs-creation) * [Rootfs with systemd as init](#rootfs-with-systemd-as-init) * [Rootfs with the agent as init](#rootfs-with-the-agent-as-init) - * [Image creation](#image-creation) + * [dracut based rootfs](#dracut-based-rootfs) + * [Image creation](#image-creation) * [Image with systemd as init](#image-with-systemd-as-init) * [Image with the agent as init](#image-with-the-agent-as-init) - * [Initrd creation](#initrd-creation) - * [Tests](#tests) -* [Platform-Distro Compatibility Matrix](#platform-distro-compatibility-matrix) + * [dracut based image](#dracut-based-image) + * [Initrd creation](#initrd-creation) + * [Rootfs based initrd](#rootfs-based-initrd) + * [dracut based initrd](#dracut-based-initrd) + * [dracut options](#dracut-options) + * [Add kernel modules](#add-kernel-modules) + * [Testing](#testing) + * [Platform-Distro Compatibility Matrix](#platform-distro-compatibility-matrix) ## Introduction @@ -53,16 +60,39 @@ This section describes the terms used for all documentation in this repository. A particular version of a Linux distribution used to create a rootfs from. -## Usage +- dracut + + A guest OS build method where the building host is used as the Base OS. + For more information refer to the [dracut homepage](https://dracut.wiki.kernel.org/index.php/Main_Page). + +## Building The top-level `Makefile` contains an example of how to use the available components. -By default, components will run on the host system. However, some components +Two build methods are available, `distro` and `dracut`. +By default, the `distro` build method is used, and this creates a rootfs using +distro specific commands (e.g.: `debootstrap` for Debian or `yum` for CentOS). +The `dracut` build method uses the distro-agnostic tool `dracut` to obtain the same goal. + +By default components are run on the host system. However, some components offer the ability to run from within Docker (for ease of setup) by setting the `USE_DOCKER=true` variable. For more detailed information, consult the documentation for a particular component. +When invoking the appropriate make target as showed below, a single command is used +to generate an initrd or an image. This is what happens in details: +1. A rootfs is generated based on the specified target distribution. +2. The rootfs is provisioned with Kata-specific components and configuration files. +3. The rootfs is used as a base to generate an initrd or an image. + +When using the dracut build method however, the build sequence is different: +1. An overlay directory is populated with Kata-specific components. +2. dracut is instructed to merge the overlay directory with the required host-side +filesystem components to generate an initrd. +3. When generating an image, the initrd is extracted to obtain the base rootfs for +the image. + ### Rootfs creation This section shows how to build a basic rootfs using the default distribution. @@ -81,6 +111,15 @@ $ sudo -E PATH=$PATH make USE_DOCKER=true rootfs $ sudo -E PATH=$PATH make USE_DOCKER=true AGENT_INIT=yes rootfs ``` +#### dracut based rootfs + +> **Note**: the dracut build method does not need a rootfs as a base for an image or initrd. +However, a rootfs can be generated by extracting the generated initrd. + +``` +$ sudo -E PATH=$PATH make BUILD_METHOD=dracut rootfs +``` + ### Image creation This section shows how to create an image from the already-created rootfs. For @@ -99,18 +138,55 @@ $ sudo -E PATH=$PATH make USE_DOCKER=true image $ sudo -E PATH=$PATH make USE_DOCKER=true AGENT_INIT=yes image ``` +#### dracut based image + +> Note: the dracut build method generates an image by first building an initrd, +and then using the rootfs extracted from it. + +``` +$ sudo -E PATH=$PATH make BUILD_METHOD=dracut image +``` + ### Initrd creation -To create an initrd from the already-created rootfs with the agent acting as the init daemon: +#### Rootfs based initrd + +Create an initrd from the already-created rootfs and with the agent acting as the init daemon +using: ``` $ sudo -E PATH=$PATH make AGENT_INIT=yes initrd ``` +#### dracut based initrd + +Create an initrd using the dracut build method with: + +``` +$ sudo -E PATH=$PATH make BUILD_METHOD=dracut AGENT_INIT=yes initrd +``` + For further details, see [the initrd builder documentation](initrd-builder/README.md). -### Tests +### dracut options + +#### Add kernel modules + +If the initrd or image needs to contain kernel modules, this can be done by: + +1. Specify the name of the modules (as reported by `modinfo MODULE-NAME`) in +`dracut/dracut.conf.d/10-drivers.conf`. For example this file can contain: +``` +drivers="9p 9pnet 9pnet_virtio" +``` +2. Set the `DRACUT_KVERSION` make variable to the release name of the kernel that +is paired with the built image or initrd, using the `uname -r` format. For example: +``` +$ make BUILD_METHOD=dracut DRACUT_KVERSION=5.2.1-23-kata AGENT_INIT=yes initrd +``` + +## Testing ``` $ make test @@ -120,6 +196,12 @@ For further details, see [the tests documentation](tests/README.md). ## Platform-Distro Compatibility Matrix +The following table illustrates what target architecture is supported for each +of the the osbuilder distributions. + +> Note: this table is not relevant for the dracut build method, since it supports +any Linux distribution and architecture where dracut is available. + | |Alpine |CentOS |Clear Linux |Debian/Ubuntu |EulerOS |Fedora |openSUSE | |-- |-- |-- |-- |-- |-- |-- |-- | |**ARM64** |:heavy_check_mark:|:heavy_check_mark:| | |:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:| diff --git a/dracut/dracut.conf.d/00-base.conf b/dracut/dracut.conf.d/00-base.conf new file mode 100644 index 0000000000..1dd41c4a11 --- /dev/null +++ b/dracut/dracut.conf.d/00-base.conf @@ -0,0 +1,17 @@ +# +# Copyright (c) 2019 SUSE LLC +# +# SPDX-License-Identifier: Apache-2.0 + +# Main dracut config for Kata Containers + +# do NOT combine early microcode with ramdisk +early_microcode="no" +# do NOT install only what's needed to boot the local host +hostonly="no" +# do NOT store the kernel command line arguments in the initramfs +hostonly_cmdline="no" +# create reproducible images +reproducible="yes" +# dracut modules to include (NOTE: these are NOT kernel modules) +dracutmodules="kernel-modules udev-rules syslog systemd" diff --git a/dracut/dracut.conf.d/10-drivers.conf b/dracut/dracut.conf.d/10-drivers.conf new file mode 100644 index 0000000000..121e858387 --- /dev/null +++ b/dracut/dracut.conf.d/10-drivers.conf @@ -0,0 +1,9 @@ +# +# Copyright (c) 2019 SUSE LLC +# +# SPDX-License-Identifier: Apache-2.0 + +# Specify a space-separated set of kernel modules to copy from the host to +# the initramfs image. For example: +# drivers="9p 9pnet 9pnet_virtio" +drivers="" diff --git a/rootfs-builder/README.md b/rootfs-builder/README.md index 1218db010f..9ceb1b7a24 100644 --- a/rootfs-builder/README.md +++ b/rootfs-builder/README.md @@ -11,7 +11,7 @@ * [Create template files](#create-template-files) * [Modify template files](#modify-template-files) * [Expected rootfs directory content](#expected-rootfs-directory-content) - * [Optional - Customise the rootfs](#optional---customise-the-rootfs) + * [Optional - Customize the rootfs](#optional---customize-the-rootfs) * [Adding extra packages](#adding-extra-packages) * [Arbitrary rootfs changes](#arbitrary-rootfs-changes) @@ -26,24 +26,24 @@ distribution. The script supports multiple distributions and can be extended to add further ones. ### Extra features + #### Supported distributions list -Supported distributions can be listed with: + +List the supported distributions by running the following: ``` $ ./rootfs.sh -l ``` #### Generate Kata specific files -`rootfs.sh` can be used to only populate a target directory with the set of Kata -specific files and components integrable into a generic Linux rootfs to generate -a Kata guest OS image. -This feature can be used when creating a rootfs with a distribution not officially -supported by osbuilder. -It is also used when building the rootfs using the 'dracut' build method. +The `rootfs.sh` script can be used to populate a directory with only Kata specific files and +components, without creating a full usable rootfs. +This feature is used to create a rootfs based on a distribution not officially +supported by osbuilder, and when building an image using the dracut build method. -To obtain this, simply invoke `rootfs.sh` without specifying a target rootfs, e.g.: +To achieve this, simply invoke `rootfs.sh` without specifying a target rootfs, e.g.: ``` -mkdir kata-overlay -./rootfs.sh -r `pwd`/kata-overlay +$ mkdir kata-overlay +$ ./rootfs.sh -r "$PWD/kata-overlay" ``` ## Rootfs requirements @@ -177,7 +177,7 @@ After the new directory structure is created: After the function `build_rootfs` is called, the script expects the rootfs directory to contain `/sbin/init` and `/sbin/kata-agent` binaries. -### Optional - Customise the rootfs +### Optional - Customize the rootfs For particular use cases developers might want to modify the guest OS. diff --git a/rootfs-builder/rootfs.sh b/rootfs-builder/rootfs.sh index 5f1aced6cf..cc410035ff 100755 --- a/rootfs-builder/rootfs.sh +++ b/rootfs-builder/rootfs.sh @@ -386,12 +386,15 @@ build_rootfs_distro() # This is used when a distro is not specified. prepare_overlay() { - pushd "${ROOTFS_DIR}" >> /dev/null + pushd "${ROOTFS_DIR}" > /dev/null mkdir -p ./etc ./lib/systemd ./sbin ./var ln -sf ./usr/lib/systemd/systemd ./init ln -sf ../../init ./lib/systemd/systemd ln -sf ../init ./sbin/init - popd >> /dev/null + # Kata sytemd unit file + mkdir -p ./etc/systemd/system/basic.target.wants/ + ln -sf /usr/lib/systemd/system/kata-containers.target ./etc/systemd/system/basic.target.wants/kata-containers.target + popd > /dev/null } # Setup an existing rootfs directory, based on the OPTIONAL distro name @@ -405,14 +408,40 @@ setup_rootfs() if [ "$PWD" != "/" ] ; then rm -rf ./var/cache/ ./var/lib ./var/log ./var/tmp fi + ln -s ../tmp ./var/ # For some distros tmp.mount may not be installed by default in systemd paths if ! [ -f "./etc/systemd/system/tmp.mount" ] && \ ! [ -f "./usr/lib/systemd/system/tmp.mount" ] && [ "$AGENT_INIT" != "yes" ]; then + local unitFile="./etc/systemd/system/tmp.mount" info "Install tmp.mount in ./etc/systemd/system" - cp ./usr/share/systemd/tmp.mount ./etc/systemd/system/tmp.mount + mkdir -p `dirname "$unitFile"` + cp ./usr/share/systemd/tmp.mount "$unitFile" || cat > "$unitFile" << EOT +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Temporary Directory (/tmp) +Documentation=man:hier(7) +Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems +ConditionPathIsSymbolicLink=!/tmp +DefaultDependencies=no +Conflicts=umount.target +Before=local-fs.target umount.target +After=swap.target + +[Mount] +What=tmpfs +Where=/tmp +Type=tmpfs +Options=mode=1777,strictatime,nosuid,nodev +EOT fi popd >> /dev/null @@ -486,7 +515,7 @@ parse_arguments() l) get_distros | sort && exit 0;; o) OSBUILDER_VERSION="${OPTARG}" ;; r) ROOTFS_DIR="${OPTARG}" ;; - t) get_test_config "${OPTARG}" && exit -1;; + t) get_test_config "${OPTARG}" && exit 0;; *) die "Found an invalid option";; esac done