rootfs-builder: support provisioning existing rootfs

Add the use case of provisioning an existing rootfs directory with the
components / configurations needed to generate a Kata compatible images.
This supports use cases such as using a rootfs built outside of
osbuilder, and providing a overlay for dracut built initrds.

Signed-off-by: Marco Vedovati <mvedovati@suse.com>
This commit is contained in:
Marco Vedovati 2019-06-12 18:54:55 +02:00
parent 7d38b84203
commit 39370c2aea
2 changed files with 273 additions and 204 deletions

View File

@ -1,4 +1,8 @@
* [Building a Guest OS rootfs for Kata Containers](#building-a-guest-os-rootfs-for-kata-containers)
* [Supported base OSs](#supported-base-oss) * [Supported base OSs](#supported-base-oss)
* [Extra features](#extra-features)
* [Supported distributions list](#supported-distributions-list)
* [Generate Kata specific files](#generate-kata-specific-files)
* [Rootfs requirements](#rootfs-requirements) * [Rootfs requirements](#rootfs-requirements)
* [Creating a rootfs](#creating-a-rootfs) * [Creating a rootfs](#creating-a-rootfs)
* [Creating a rootfs with kernel modules](#creating-a-rootfs-with-kernel-modules) * [Creating a rootfs with kernel modules](#creating-a-rootfs-with-kernel-modules)
@ -21,10 +25,25 @@ The `rootfs.sh` script builds a rootfs based on a particular Linux\*
distribution. The script supports multiple distributions and can be extended distribution. The script supports multiple distributions and can be extended
to add further ones. to add further ones.
To list the supported distributions, run: ### Extra features
#### Supported distributions list
Supported distributions can be listed with:
``` ```
$ ./rootfs.sh -h $ ./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.
To obtain this, simply invoke `rootfs.sh` without specifying a target rootfs, e.g.:
```
mkdir kata-overlay
./rootfs.sh -r `pwd`/kata-overlay
``` ```
## Rootfs requirements ## Rootfs requirements

View File

@ -52,18 +52,31 @@ typeset -r CONFIG_ARCH_SH="config_${ARCH}.sh"
# build_rootfs() function. # build_rootfs() function.
typeset -r LIB_SH="rootfs_lib.sh" typeset -r LIB_SH="rootfs_lib.sh"
# rootfs distro name specified by the user
typeset distro=
# Absolute path to the rootfs root folder
typeset ROOTFS_DIR
# Absolute path in the rootfs to the "init" executable / symlink.
# Typically something like "${ROOTFS_DIR}/init
typeset init=
#$1: Error code if want to exit different to 0 #$1: Error code if want to exit different to 0
usage() usage()
{ {
error="${1:-0}" error="${1:-0}"
cat <<EOT cat <<EOT
Usage: ${script_name} [options] <distro> Usage: ${script_name} [options] [DISTRO]
Build a rootfs based on <distro> OS, to be included in a Kata Containers Build and setup a rootfs directory based on DISTRO OS, used to create
image. Kata Containers images or initramfs.
Supported <distro> values: When no DISTRO is provided, an existing base rootfs at ROOTFS_DIR is provisioned
with the Kata specific components and configuration.
Supported DISTRO values:
$(get_distros | tr "\n" " ") $(get_distros | tr "\n" " ")
Options: Options:
@ -75,7 +88,7 @@ Options:
yaml description. yaml description.
-r <directory> Specify the rootfs base directory. Overrides the ROOTFS_DIR -r <directory> Specify the rootfs base directory. Overrides the ROOTFS_DIR
environment variable. environment variable.
-t Print the test configuration for <distro> and exit -t DISTRO Print the test configuration for DISTRO and exit
immediately. immediately.
Environment Variables: Environment Variables:
@ -100,7 +113,7 @@ DISTRO_REPO Use host repositories to install guest packages.
GO_AGENT_PKG URL of the Git repository hosting the agent package. GO_AGENT_PKG URL of the Git repository hosting the agent package.
Default value: ${GO_AGENT_PKG} Default value: ${GO_AGENT_PKG}
GRACEFUL_EXIT If set, and if the <distro> configuration specifies a GRACEFUL_EXIT If set, and if the DISTRO configuration specifies a
non-empty BUILD_CAN_FAIL variable, do not return with an non-empty BUILD_CAN_FAIL variable, do not return with an
error code in case any of the build step fails. error code in case any of the build step fails.
This is used when running CI jobs, to tolerate failures for This is used when running CI jobs, to tolerate failures for
@ -112,7 +125,7 @@ KERNEL_MODULES_DIR Path to a directory containing kernel modules to include in
Default value: <empty> Default value: <empty>
ROOTFS_DIR Path to the directory that is populated with the rootfs. ROOTFS_DIR Path to the directory that is populated with the rootfs.
Default value: <${script_name} path>/rootfs-<distro-name> Default value: <${script_name} path>/rootfs-<DISTRO-name>
USE_DOCKER If set, build the rootfs inside a container (requires USE_DOCKER If set, build the rootfs inside a container (requires
Docker). Docker).
@ -137,7 +150,9 @@ get_distros() {
} }
get_test_config() { get_test_config() {
local distro="$1" local -r distro="$1"
[ -z "$distro" ] && die "No distro name specified"
local config="${script_dir}/${distro}/config.sh" local config="${script_dir}/${distro}/config.sh"
source ${config} source ${config}
@ -330,20 +345,8 @@ compare_versions()
true true
} }
while getopts a:hlo:r:t: opt check_env_variables()
do {
case $opt in
a) AGENT_VERSION="${OPTARG}" ;;
h) usage ;;
l) get_distros | sort && exit 0;;
o) OSBUILDER_VERSION="${OPTARG}" ;;
r) ROOTFS_DIR="${OPTARG}" ;;
t) get_test_config "${OPTARG}" && exit 0;;
esac
done
shift $(($OPTIND - 1))
# Fetch the first element from GOPATH as working directory # Fetch the first element from GOPATH as working directory
# as go get only works against the first item in the GOPATH # as go get only works against the first item in the GOPATH
[ -z "$GOPATH" ] && die "GOPATH not set" [ -z "$GOPATH" ] && die "GOPATH not set"
@ -353,10 +356,12 @@ GOPATH_LOCAL="${GOPATH%%:*}"
[ -n "${KERNEL_MODULES_DIR}" ] && [ ! -d "${KERNEL_MODULES_DIR}" ] && die "KERNEL_MODULES_DIR defined but is not an existing directory" [ -n "${KERNEL_MODULES_DIR}" ] && [ ! -d "${KERNEL_MODULES_DIR}" ] && die "KERNEL_MODULES_DIR defined but is not an existing directory"
[ -z "${OSBUILDER_VERSION}" ] && die "need osbuilder version" [ -n "${OSBUILDER_VERSION}" ] || die "need osbuilder version"
}
distro="$1"
# Builds a rootfs based on the distro name provided as argument
build_rootfs_distro()
{
[ -n "${distro}" ] || usage 1 [ -n "${distro}" ] || usage 1
distro_config_dir="${script_dir}/${distro}" distro_config_dir="${script_dir}/${distro}"
@ -376,8 +381,6 @@ if [ -z "$ROOTFS_DIR" ]; then
ROOTFS_DIR="${script_dir}/rootfs-${OS_NAME}" ROOTFS_DIR="${script_dir}/rootfs-${OS_NAME}"
fi fi
init="${ROOTFS_DIR}/sbin/init"
if [ -e "${distro_config_dir}/${LIB_SH}" ];then if [ -e "${distro_config_dir}/${LIB_SH}" ];then
rootfs_lib="${distro_config_dir}/${LIB_SH}" rootfs_lib="${distro_config_dir}/${LIB_SH}"
info "rootfs_lib.sh file found. Loading content" info "rootfs_lib.sh file found. Loading content"
@ -471,13 +474,31 @@ else
fi fi
build_rootfs ${ROOTFS_DIR} build_rootfs ${ROOTFS_DIR}
}
# Used to create a minimal directory tree where the agent can be instaleld.
# This is used when a distro is not specified.
prepare_overlay()
{
pushd "${ROOTFS_DIR}" >> /dev/null pushd "${ROOTFS_DIR}" >> /dev/null
if [ "$PWD" != "/" ] ; then mkdir -p ./etc ./lib/systemd ./sbin ./var
rm -rf ./var/cache/ ./var/lib ./var/log ln -sf ./usr/lib/systemd/systemd ./init
fi ln -sf ../../init ./lib/systemd/systemd
ln -sf ../init ./sbin/init
popd >> /dev/null
}
# Setup an existing rootfs directory, based on the OPTIONAL distro name
# provided as argument
setup_rootfs()
{
[ -z "$distro" ] && prepare_overlay
info "Create symlink to /tmp in /var to create private temporal directories with systemd" info "Create symlink to /tmp in /var to create private temporal directories with systemd"
rm -rf ./var/tmp pushd "${ROOTFS_DIR}" >> /dev/null
if [ "$PWD" != "/" ] ; then
rm -rf ./var/cache/ ./var/lib ./var/log ./var/tmp
fi
ln -s ../tmp ./var/ ln -s ../tmp ./var/
# For some distros tmp.mount may not be installed by default in systemd paths # For some distros tmp.mount may not be installed by default in systemd paths
@ -493,7 +514,7 @@ popd >> /dev/null
[ -n "${KERNEL_MODULES_DIR}" ] && copy_kernel_modules ${KERNEL_MODULES_DIR} ${ROOTFS_DIR} [ -n "${KERNEL_MODULES_DIR}" ] && copy_kernel_modules ${KERNEL_MODULES_DIR} ${ROOTFS_DIR}
chrony_conf_file="${ROOTFS_DIR}/etc/chrony.conf" chrony_conf_file="${ROOTFS_DIR}/etc/chrony.conf"
if [ ${distro} == ubuntu ] || [ ${distro} == debian ] ; then if [ "${distro}" == "ubuntu" ] || [ "${distro}" == "debian" ] ; then
chrony_conf_file="${ROOTFS_DIR}/etc/chrony/chrony.conf" chrony_conf_file="${ROOTFS_DIR}/etc/chrony/chrony.conf"
fi fi
@ -512,18 +533,9 @@ EOT
# Reference: https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html # Reference: https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html
sed -i 's/^\(server \|pool \|peer \)/# &/g' ${chrony_conf_file} sed -i 's/^\(server \|pool \|peer \)/# &/g' ${chrony_conf_file}
chrony_systemd_service="${ROOTFS_DIR}/usr/lib/systemd/system/chronyd.service"
if [ ${distro} == ubuntu ] || [ ${distro} == debian ] ; then
chrony_systemd_service="${ROOTFS_DIR}/lib/systemd/system/chrony.service"
fi
if [ -f "$chrony_systemd_service" ]; then
sed -i '/^\[Unit\]/a ConditionPathExists=\/dev\/ptp0' ${chrony_systemd_service}
fi
# The CC on s390x for fedora needs to be manually set to gcc when the golang is downloaded from the main page. # The CC on s390x for fedora needs to be manually set to gcc when the golang is downloaded from the main page.
# See issue: https://github.com/kata-containers/osbuilder/issues/217 # See issue: https://github.com/kata-containers/osbuilder/issues/217
[ "$distro" == fedora ] && [ "$ARCH" == "s390x" ] && export CC=gcc [ "$distro" == "fedora" ] && [ "$ARCH" == "s390x" ] && export CC=gcc
AGENT_DIR="${ROOTFS_DIR}/usr/bin" AGENT_DIR="${ROOTFS_DIR}/usr/bin"
AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}" AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}"
@ -556,3 +568,41 @@ OK "init is installed"
info "Creating summary file" info "Creating summary file"
create_summary_file "${ROOTFS_DIR}" create_summary_file "${ROOTFS_DIR}"
}
parse_arguments()
{
while getopts a:hlo:r:t: opt
do
case $opt in
a) AGENT_VERSION="${OPTARG}" ;;
h) usage ;;
l) get_distros | sort && exit 0;;
o) OSBUILDER_VERSION="${OPTARG}" ;;
r) ROOTFS_DIR="${OPTARG}" ;;
t) get_test_config "${OPTARG}" && exit -1;;
*) die "Found an invalid option";;
esac
done
shift $(($OPTIND - 1))
distro="$1"
}
main()
{
parse_arguments $*
check_env_variables
init="${ROOTFS_DIR}/sbin/init"
if [ -n "$distro" ]; then
build_rootfs_distro
else
#Make sure ROOTFS_DIR is set correctly
[ -d "${ROOTFS_DIR}" ] || die "Invalid rootfs directory: '$ROOTFS_DIR'"
fi
setup_rootfs
}
main $*