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)
* [Extra features](#extra-features)
* [Supported distributions list](#supported-distributions-list)
* [Generate Kata specific files](#generate-kata-specific-files)
* [Rootfs requirements](#rootfs-requirements)
* [Creating a rootfs](#creating-a-rootfs)
* [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
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

View File

@ -52,18 +52,31 @@ typeset -r CONFIG_ARCH_SH="config_${ARCH}.sh"
# build_rootfs() function.
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
usage()
{
error="${1:-0}"
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
image.
Build and setup a rootfs directory based on DISTRO OS, used to create
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" " ")
Options:
@ -75,7 +88,7 @@ Options:
yaml description.
-r <directory> Specify the rootfs base directory. Overrides the ROOTFS_DIR
environment variable.
-t Print the test configuration for <distro> and exit
-t DISTRO Print the test configuration for DISTRO and exit
immediately.
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.
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
error code in case any of the build step fails.
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>
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
Docker).
@ -137,7 +150,9 @@ get_distros() {
}
get_test_config() {
local distro="$1"
local -r distro="$1"
[ -z "$distro" ] && die "No distro name specified"
local config="${script_dir}/${distro}/config.sh"
source ${config}
@ -330,20 +345,8 @@ compare_versions()
true
}
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 0;;
esac
done
shift $(($OPTIND - 1))
check_env_variables()
{
# Fetch the first element from GOPATH as working directory
# as go get only works against the first item in the GOPATH
[ -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"
[ -z "${OSBUILDER_VERSION}" ] && die "need osbuilder version"
distro="$1"
[ -n "${OSBUILDER_VERSION}" ] || die "need osbuilder version"
}
# Builds a rootfs based on the distro name provided as argument
build_rootfs_distro()
{
[ -n "${distro}" ] || usage 1
distro_config_dir="${script_dir}/${distro}"
@ -376,8 +381,6 @@ if [ -z "$ROOTFS_DIR" ]; then
ROOTFS_DIR="${script_dir}/rootfs-${OS_NAME}"
fi
init="${ROOTFS_DIR}/sbin/init"
if [ -e "${distro_config_dir}/${LIB_SH}" ];then
rootfs_lib="${distro_config_dir}/${LIB_SH}"
info "rootfs_lib.sh file found. Loading content"
@ -471,13 +474,31 @@ else
fi
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
if [ "$PWD" != "/" ] ; then
rm -rf ./var/cache/ ./var/lib ./var/log
fi
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
}
# 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"
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/
# 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}
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"
fi
@ -512,18 +533,9 @@ EOT
# Reference: https://chrony.tuxfamily.org/doc/3.4/chrony.conf.html
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.
# 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_DEST="${AGENT_DIR}/${AGENT_BIN}"
@ -556,3 +568,41 @@ OK "init is installed"
info "Creating summary file"
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 $*