osbuilder: Multistrap Ubuntu

Use `multistrap` for building Ubuntu rootfs. Adds support for building
for foreign architectures using the `ARCH` environment variable
(including umoci).
In the process, the Ubuntu rootfs workflow is vastly simplified.

Signed-off-by: Jakob Naucke <jakob.naucke@ibm.com>
This commit is contained in:
Jakob Naucke 2022-03-21 20:20:24 +01:00
parent 578678e051
commit 8fbf6c4e14
No known key found for this signature in database
GPG Key ID: 45FA1C7D310C0EBE
5 changed files with 100 additions and 147 deletions

View File

@ -39,7 +39,11 @@ handle_error() {
trap 'handle_error $LINENO' ERR trap 'handle_error $LINENO' ERR
# Default architecture # Default architecture
ARCH=$(uname -m) export ARCH=${ARCH:-$(uname -m)}
if [ "$ARCH" == "ppc64le" ] || [ "$ARCH" == "s390x" ]; then
LIBC=gnu
echo "WARNING: Forcing LIBC=gnu because $ARCH has no musl Rust target"
fi
# distro-specific config file # distro-specific config file
typeset -r CONFIG_SH="config.sh" typeset -r CONFIG_SH="config.sh"
@ -103,6 +107,11 @@ AGENT_SOURCE_BIN Path to the directory of agent binary.
AGENT_VERSION Version of the agent to include in the rootfs. AGENT_VERSION Version of the agent to include in the rootfs.
Default value: ${AGENT_VERSION:-<not set>} Default value: ${AGENT_VERSION:-<not set>}
ARCH Target architecture (according to \`uname -m\`).
Foreign bootstraps are currently only supported for Ubuntu
and glibc agents.
Default value: $(uname -m)
DISTRO_REPO Use host repositories to install guest packages. DISTRO_REPO Use host repositories to install guest packages.
Default value: <not set> Default value: <not set>
@ -428,6 +437,7 @@ build_rootfs_distro()
--env ROOTFS_DIR="/rootfs" \ --env ROOTFS_DIR="/rootfs" \
--env AGENT_BIN="${AGENT_BIN}" \ --env AGENT_BIN="${AGENT_BIN}" \
--env AGENT_INIT="${AGENT_INIT}" \ --env AGENT_INIT="${AGENT_INIT}" \
--env ARCH="${ARCH}" \
--env CI="${CI}" \ --env CI="${CI}" \
--env KERNEL_MODULES_DIR="${KERNEL_MODULES_DIR}" \ --env KERNEL_MODULES_DIR="${KERNEL_MODULES_DIR}" \
--env LIBC="${LIBC}" \ --env LIBC="${LIBC}" \
@ -560,11 +570,6 @@ EOF
AGENT_DIR="${ROOTFS_DIR}/usr/bin" AGENT_DIR="${ROOTFS_DIR}/usr/bin"
AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}" AGENT_DEST="${AGENT_DIR}/${AGENT_BIN}"
if [ "$ARCH" == "ppc64le" ] || [ "$ARCH" == "s390x" ]; then
LIBC=gnu
warning "Forcing LIBC=gnu because $ARCH has no musl Rust target"
fi
if [ -z "${AGENT_SOURCE_BIN}" ] ; then if [ -z "${AGENT_SOURCE_BIN}" ] ; then
test -r "${HOME}/.cargo/env" && source "${HOME}/.cargo/env" test -r "${HOME}/.cargo/env" && source "${HOME}/.cargo/env"
# rust agent needs ${arch}-unknown-linux-${LIBC} # rust agent needs ${arch}-unknown-linux-${LIBC}
@ -583,7 +588,7 @@ EOF
info "Set up libseccomp" info "Set up libseccomp"
libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX) libseccomp_install_dir=$(mktemp -d -t libseccomp.XXXXXXXXXX)
gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX) gperf_install_dir=$(mktemp -d -t gperf.XXXXXXXXXX)
bash ${script_dir}/../../../ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}" ${script_dir}/../../../ci/install_libseccomp.sh "${libseccomp_install_dir}" "${gperf_install_dir}"
echo "Set environment variables for the libseccomp crate to link the libseccomp library statically" echo "Set environment variables for the libseccomp crate to link the libseccomp library statically"
export LIBSECCOMP_LINK_TYPE=static export LIBSECCOMP_LINK_TYPE=static
export LIBSECCOMP_LIB_PATH="${libseccomp_install_dir}/lib" export LIBSECCOMP_LIB_PATH="${libseccomp_install_dir}/lib"
@ -667,16 +672,28 @@ EOF
source "${HOME}/.cargo/env" source "${HOME}/.cargo/env"
target="${ARCH}-unknown-linux-${LIBC}" target="${ARCH}-unknown-linux-${LIBC}"
if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then
AA_RUSTFLAG="-C link-args=-Wl,-rpath,/usr/local/lib/rats-tls" RUSTFLAGS="-C link-args=-Wl,-rpath,/usr/local/lib/rats-tls"
# Currently eaa_kbc module only support this specific platform # Currently eaa_kbc module only support this specific platform
target="x86_64-unknown-linux-gnu" target="x86_64-unknown-linux-gnu"
fi fi
RUSTFLAGS=${AA_RUSTFLAG} cargo build --release --target "${target}" --no-default-features --features "${AA_KBC}" if [ "$(uname -m)" != "$ARCH" ]; then
install -o root -g root -m 0755 "target/${target}/release/attestation-agent" "${ROOTFS_DIR}/usr/local/bin/" RUSTFLAGS+=" -C linker=$CC"
fi
export RUSTFLAGS
# Foreign CC is incompatible with libgit2 -- CC is still handled by `-C linker=...` flag
CC= cargo build --release --target "${target}" --no-default-features --features "${AA_KBC}"
install -D -o root -g root -m 0755 "target/${target}/release/attestation-agent" -t "${ROOTFS_DIR}/usr/local/bin/"
popd popd
fi fi
if [ "${UMOCI}" = "yes" ]; then if [ "${UMOCI}" = "yes" ]; then
case "$ARCH" in
aarch64) GOARCH=arm64;;
x86_64) GOARCH=amd64;;
*) GOARCH="$ARCH"
esac
export GOARCH
umoci_url="$(get_package_version_from_kata_yaml externals.umoci.url)" umoci_url="$(get_package_version_from_kata_yaml externals.umoci.url)"
umoci_tag="$(get_package_version_from_kata_yaml externals.umoci.tag)" umoci_tag="$(get_package_version_from_kata_yaml externals.umoci.tag)"
info "Install umoci" info "Install umoci"

View File

@ -1,51 +1,36 @@
# # Copyright (c) 2018 Yash Jain, 2022 IBM Corp.
# Copyright (c) 2018 Yash Jain
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
ARG IMAGE_REGISTRY=docker.io ARG IMAGE_REGISTRY=docker.io
#ubuntu: docker image to be used to create a rootfs
#@OS_VERSION@: Docker image version to build this dockerfile
FROM ${IMAGE_REGISTRY}/ubuntu:@OS_VERSION@ FROM ${IMAGE_REGISTRY}/ubuntu:@OS_VERSION@
@SET_PROXY@
# This dockerfile needs to provide all the componets need to build a rootfs RUN apt-get update && \
# Install any package need to create a rootfs (package manager, extra tools) DEBIAN_FRONTEND=noninteractive \
apt-get --no-install-recommends -y install \
# RUN commands
RUN apt-get update && apt-get --no-install-recommends install -y \
apt-utils \
autoconf \
automake \
binutils \
build-essential \
ca-certificates \ ca-certificates \
chrony \
coreutils \
curl \ curl \
debianutils \
debootstrap \
g++ \ g++ \
gcc \ $(gcc_arch="@ARCH@" && [ "$(uname -m)" != "$gcc_arch" ] && ( \
libc_arch="$gcc_arch" && \
[ "$gcc_arch" = aarch64 ] && libc_arch=arm64; \
[ "$gcc_arch" = ppc64le ] && gcc_arch=powerpc64le && libc_arch=ppc64el; \
[ "$gcc_arch" = x86_64 ] && gcc_arch=x86-64 && libc_arch=amd64; \
echo "gcc-$gcc_arch-linux-gnu libc6-dev-$libc_arch-cross")) \
git \ git \
golang-go \ golang-go \
libdevmapper-dev \ libdevmapper-dev \
libc6-dev \
libgpgme-dev \ libgpgme-dev \
libssl-dev \ libssl-dev \
libstdc++-8-dev \
m4 \
make \ make \
multistrap \
musl-tools \ musl-tools \
pkg-config \ pkg-config \
protobuf-compiler \ protobuf-compiler
sed \
systemd \
tar \
vim \
wget
# aarch64 requires this name -- link for all # aarch64 requires this name -- link for all
RUN ln -s /usr/bin/musl-gcc "/usr/bin/$(uname -m)-linux-musl-gcc" RUN ln -s /usr/bin/musl-gcc "/usr/bin/$(uname -m)-linux-musl-gcc"
# This will install the proper packages to build Kata components
@INSTALL_RUST@ @INSTALL_RUST@
@INSTALL_AA_KBC@ @INSTALL_AA_KBC@

View File

@ -1,46 +1,39 @@
# This is a configuration file add extra variables to # Copyright (c) 2018 Yash Jain, 2022 IBM Corp.
#
# Copyright (c) 2018 Yash Jain
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# be used by build_rootfs() from rootfs_lib.sh the variables will be
# loaded just before call the function. For more information see the
# rootfs-builder/README.md file.
OS_VERSION=${OS_VERSION:-20.04} OS_NAME=ubuntu
# This should be Ubuntu's code name, e.g. "focal" (Focal Fossa) for 20.04 # This should be Ubuntu's code name, e.g. "focal" (Focal Fossa) for 20.04
OS_NAME=${OS_NAME:-"focal"} OS_VERSION=${OS_VERSION:-focal}
PACKAGES=chrony
[ "$AGENT_INIT" = no ] && PACKAGES+=" init"
[ "$SECCOMP" = yes ] && PACKAGES+=" libseccomp2"
[ "$SKOPEO" = yes ] && PACKAGES+=" libgpgme11"
REPO_URL=http://ports.ubuntu.com
# packages to be installed by default case "$ARCH" in
# Note: ca-certificates is required for confidential containers aarch64) DEB_ARCH=arm64;;
# to pull the container image on the guest ppc64le) DEB_ARCH=ppc64el;;
PACKAGES="systemd coreutils init kmod ca-certificates" s390x) DEB_ARCH="$ARCH";;
EXTRA_PKGS+=" chrony" x86_64) DEB_ARCH=amd64; REPO_URL=http://archive.ubuntu.com/ubuntu;;
*) die "$ARCH not supported"
DEBOOTSTRAP=${PACKAGE_MANAGER:-"debootstrap"}
case $(uname -m) in
x86_64) ARCHITECTURE="amd64";;
ppc64le) ARCHITECTURE="ppc64el";;
aarch64) ARCHITECTURE="arm64";;
s390x) ARCHITECTURE="s390x";;
(*) die "$(uname -m) not supported "
esac esac
# Init process must be one of {systemd,kata-agent}
INIT_PROCESS=systemd
# List of zero or more architectures to exclude from build,
# as reported by `uname -m`
ARCH_EXCLUDE_LIST=()
[ "$SECCOMP" = "yes" ] && PACKAGES+=" libseccomp2" || true
[ "$SKOPEO" = "yes" ] && PACKAGES+=" libgpgme11" || true
if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then
AA_KBC_EXTRAS=" PACKAGES+=" apt gnupg"
AA_KBC_EXTRAS="
RUN echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' \| tee /etc/apt/sources.list.d/inclavare-containers.list; \ RUN echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' \| tee /etc/apt/sources.list.d/inclavare-containers.list; \
wget -qO - http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key \| apt-key add -; \ curl -L http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key \| apt-key add -; \
apt-get update; \ apt-get update; \
apt-get install -y rats-tls apt-get install -y rats-tls
" "
fi fi
if [ "$(uname -m)" != "$ARCH" ]; then
case "$ARCH" in
ppc64le) cc_arch=powerpc64le;;
x86_64) cc_arch=x86-64;;
*) cc_arch="$ARCH"
esac
export CC="$cc_arch-linux-gnu-gcc"
fi

View File

@ -1,84 +1,41 @@
# - Arguments # Copyright (c) 2018 Yash Jain, 2022 IBM Corp.
#
# Copyright (c) 2018 Yash Jain
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
#
#
# rootfs_dir=$1
#
# - Optional environment variables
#
# EXTRA_PKGS: Variable to add extra PKGS provided by the user
#
# BIN_AGENT: Name of the Kata-Agent binary
#
# REPO_URL: URL to distribution repository ( should be configured in
# config.sh file)
#
# Any other configuration variable for a specific distro must be added
# and documented on its own config.sh
#
# - Expected result
#
# rootfs_dir populated with rootfs pkgs
# It must provide a binary in /sbin/init
#
build_rootfs() { build_rootfs() {
# Mandatory local rootfs_dir=$1
local ROOTFS_DIR=$1 local multistrap_conf=multistrap.conf
# Name of the Kata-Agent binary [ -z "$rootfs_dir" ] && die "need rootfs"
local BIN_AGENT=${BIN_AGENT} [ "$rootfs_dir" = "/" ] && die "rootfs cannot be slash"
# In case of support EXTRA packages, use it to allow # For simplicity's sake, use multistrap for foreign and native bootstraps.
# users to add more packages to the base rootfs cat > "$multistrap_conf" << EOF
local EXTRA_PKGS=${EXTRA_PKGS:-} [General]
cleanup=true
aptsources=Ubuntu
bootstrap=Ubuntu
# In case rootfs is created using repositories allow user to modify [Ubuntu]
# the default URL source=$REPO_URL
local REPO_URL=${REPO_URL:-YOUR_REPO} keyring=ubuntu-keyring
suite=focal
packages=$PACKAGES $EXTRA_PKGS
EOF
multistrap -a "$DEB_ARCH" -d "$rootfs_dir" -f "$multistrap_conf"
rm -rf "$rootfs_dir/var/run"
ln -s /run "$rootfs_dir/var/run"
for file in /etc/{resolv.conf,ssl/certs/ca-certificates.crt}; do
mkdir -p "$rootfs_dir$(dirname $file)"
cp --remove-destination "$file" "$rootfs_dir$file"
done
# PATH where files this script is placed # Reduce image size and memory footprint by removing unnecessary files and directories.
# Use it to refer to files in the same directory rm -rf $rootfs_dir/usr/share/{bash-completion,bug,doc,info,lintian,locale,man,menu,misc,pixmaps,terminfo,zsh}
# Example: ${CONFIG_DIR}/foo
local CONFIG_DIR=${CONFIG_DIR}
if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then
# Populate ROOTFS_DIR curl -L http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key | chroot "$rootfs_dir" apt-key add -
# Must provide /sbin/init and /bin/${BIN_AGENT} cat << EOF | chroot "$rootfs_dir"
DEBOOTSTRAP="debootstrap"
check_root
mkdir -p "${ROOTFS_DIR}"
if [ -n "${PKG_MANAGER}" ]; then
info "debootstrap path provided by user: ${PKG_MANAGER}"
elif check_program $DEBOOTSTRAP ; then
PKG_MANAGER=$DEBOOTSTRAP
else
die "$DEBOOTSTRAP is not installed"
fi
# trim whitespace
PACKAGES=$(echo $PACKAGES |xargs )
# add comma as debootstrap needs , separated package names.
# Don't change $PACKAGES in config.sh to include ','
# This is done to maintain consistency
PACKAGES=$(echo $PACKAGES | sed -e 's/ /,/g' )
${PKG_MANAGER} --variant=minbase \
--arch=${ARCHITECTURE}\
--include="$PACKAGES" \
${OS_NAME} \
${ROOTFS_DIR}
[ -n "${EXTRA_PKGS}" ] && chroot $ROOTFS_DIR apt-get install -y ${EXTRA_PKGS}
# Reduce image size and memory footprint
# removing not needed files and directories.
chroot $ROOTFS_DIR rm -rf /usr/share/{bash-completion,bug,doc,info,lintian,locale,man,menu,misc,pixmaps,terminfo,zoneinfo,zsh}
if [ "${AA_KBC}" == "eaa_kbc" ] && [ "${ARCH}" == "x86_64" ]; then
wget -qO - http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04/DEB-GPG-KEY.key | chroot $ROOTFS_DIR apt-key add -
cat << EOF | chroot $ROOTFS_DIR
echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' | tee /etc/apt/sources.list.d/inclavare-containers.list echo 'deb [arch=amd64] http://mirrors.openanolis.cn/inclavare-containers/ubuntu20.04 bionic main' | tee /etc/apt/sources.list.d/inclavare-containers.list
apt-get update apt-get update
apt-get install -y rats-tls apt-get install -y rats-tls

View File

@ -227,8 +227,8 @@ generate_dockerfile()
dir="$1" dir="$1"
[ -d "${dir}" ] || die "${dir}: not a directory" [ -d "${dir}" ] || die "${dir}: not a directory"
local rustarch=$(uname -m) local rustarch="$ARCH"
[ "$rustarch" = ppc64le ] && rustarch=powerpc64le [ "$ARCH" = ppc64le ] && rustarch=powerpc64le
[ -n "${http_proxy:-}" ] && readonly set_proxy="RUN sed -i '$ a proxy="${http_proxy:-}"' /etc/dnf/dnf.conf /etc/yum.conf; true" [ -n "${http_proxy:-}" ] && readonly set_proxy="RUN sed -i '$ a proxy="${http_proxy:-}"' /etc/dnf/dnf.conf /etc/yum.conf; true"
@ -244,6 +244,7 @@ RUN . /root/.cargo/env; cargo install cargo-when
sed \ sed \
-e "s#@OS_VERSION@#${OS_VERSION:-}#g" \ -e "s#@OS_VERSION@#${OS_VERSION:-}#g" \
-e "s#@ARCH@#$ARCH#g" \
-e "s#@INSTALL_RUST@#${install_rust//$'\n'/\\n}#g" \ -e "s#@INSTALL_RUST@#${install_rust//$'\n'/\\n}#g" \
-e "s#@SET_PROXY@#${set_proxy:-}#g" \ -e "s#@SET_PROXY@#${set_proxy:-}#g" \
-e "s#@INSTALL_AA_KBC@#${AA_KBC_EXTRAS//$'\n'/\\n}#g" \ -e "s#@INSTALL_AA_KBC@#${AA_KBC_EXTRAS//$'\n'/\\n}#g" \