Skip to content

Commit

Permalink
kas-container: add limited support for docker rootless
Browse files Browse the repository at this point in the history
Docker rootless mode is similar to podman rootless mode, except that it
does not support to share the userid namespace. By that, the bind
mounted directories (like /repo, /work, /build) which are owned by the
calling user, are mapped with uid==gid==0 inside the container.
While we could align this by running as root inside the container, this
is not an option as bitbake does not allow this.

This comes with the following limitations:

- /repo must be mounted ro to not destroy the uid mappings on the host
- /work, /build must be an exclusive dir on the host that is only
  written to by the tooling inside kas-container
- a git safe.dirs exception is needed as git operates as builder on
  repos owned by root
- only operations that do not strictly require /repo:rw are supported.
- ISAR mode is not supported in rootless mode, fallback to system docker

Closes: siemens#124

Signed-off-by: Felix Moessbauer <[email protected]>
  • Loading branch information
fmoessbauer committed Jan 24, 2025
1 parent 86dad4f commit d04daa8
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 4 deletions.
45 changes: 41 additions & 4 deletions container-entrypoint
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,33 @@ may also need to update the host distribution (e.g. Debian Jessie -> Stretch).
EOF
fi

git_disable_safe_dir()
{
# allow git to operate on non-owned directories
sudo git config --system safe.directory "*"
}

chown_managed_dirs()
{
for DIR in /build /work /sstate /downloads /repo-ref; do
if [ -d "$DIR" ]; then
chown -R "$1":"$2" "$DIR"
fi
done
}

restore_managed_dirs_owner()
{
chown_managed_dirs 0 0
}

if [ -z "$USER_ID" ]; then
# Not a kas-container call
GOSU=""

# Work around gitlab-runner not aligning checked out repo ownership
# with our builder user
sudo git config --system safe.directory "*"
git_disable_safe_dir
elif [ "$USER_ID" = 0 ]; then
# We shall run everything as root
GOSU=""
Expand All @@ -58,6 +78,15 @@ else

GOSU="gosu builder"
fi
# kas-container on rootless docker workaround
if [ -n "$USER_ID" ] && [ "$USER_ID" -ne 0 ] && \
[ "$KAS_DOCKER_ROOTLESS" = "1" ] && [ "$(stat -c %u /repo)" -eq 0 ]; then
# Docker rootless does not support keeping the user namespace
# (podman option --userns=keep-id). By that, the bind mounts
# are owned by root.
git_disable_safe_dir
chown_managed_dirs "$USER_ID" "$GROUP_ID"
fi

if [ "$PWD" = / ]; then
cd /builder || exit 1
Expand All @@ -66,9 +95,17 @@ fi
if [ -n "$1" ]; then
case "$1" in
build|checkout|clean*|dump|for-all-repos|lock|menu|purge|shell|-*)
# SC2086: Double quote to prevent globbing and word splitting.
# shellcheck disable=2086
exec $GOSU kas "$@"
# We must only restore the dir owner if it is empty, however
# we cannot reliably distinguish between kas commands. Hence
# we need a hint from the kas-container script.
if [ "$KAS_DOCKER_ROOTLESS_PURGE" = "1" ]; then
trap restore_managed_dirs_owner EXIT INT TERM
$GOSU kas "$@"
else
# SC2086: Double quote to prevent globbing and word splitting.
# shellcheck disable=2086
exec $GOSU kas "$@"
fi
;;
*)
# SC2086: Double quote to prevent globbing and word splitting.
Expand Down
11 changes: 11 additions & 0 deletions docs/userguide/kas-container-description.inc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,14 @@ By default ``kas-container`` uses the official images provided by the kas projec
``KAS_CONTAINER_IMAGE`` environment variable. As container backends, Docker and
Podman are supported. To force the use of podman over docker, set
``KAS_CONTAINER_ENGINE=podman``. For details, see :ref:`env-vars-label`.

Running under docker in `rootless mode <https://docs.docker.com/engine/security/rootless/>`_
is partially supported and requires a distinct ``KAS_WORK_DIR`` outside of the
calling directory (repo-dir). The ``KAS_WORK_DIR`` is exclusively managed by the
tooling inside the container and must not be written to from the host. To completely
remove all data managed by kas, use ``kas-container purge``. This also restores the
directory owners of the dirs passed to kas, so they can be removed from the host.

.. note::
The ISAR build system is not compatible with rootless execution. By that,
we fall back to the system docker or podman instance.
38 changes: 38 additions & 0 deletions kas-container
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ enable_isar_mode()
KAS_CONTAINER_COMMAND="sudo --preserve-env ${KAS_CONTAINER_COMMAND}"
# preserved user PATH may lack sbin needed by privileged podman
export PATH="${PATH}:/usr/sbin"
elif [ "${KAS_DOCKER_ROOTLESS}" = "1" ]; then
export DOCKER_HOST="${DOCKER_HOST:-unix:///var/run/docker.sock}"
debug "kas-isar does not support rootless docker. Using system docker"
# force use of well-known system docker socket
KAS_CONTAINER_COMMAND="sudo --preserve-env ${KAS_CONTAINER_COMMAND}"
KAS_DOCKER_ROOTLESS=0
fi
}

Expand Down Expand Up @@ -180,6 +186,30 @@ forward_dir_if_set()
fi
}

check_docker_rootless()
{
KAS_DOCKER_ROOTLESS=0
if [ "$(docker context show)" = "rootless" ]; then
KAS_DOCKER_ROOTLESS=1
fi
}

enable_docker_rootless()
{
warning "Rootless docker used, only limited functionality available."
if [ "${KAS_WORK_DIR}" = "${KAS_REPO_DIR}" ]; then
fatal_error "Docker rootless requires an exclusive KAS_WORK_DIR."
fi
if [ "${KAS_REPO_MOUNT_OPT}" = "rw" ]; then
fatal_error "Docker rootless requires read-only repo."
fi
# on prune the entry point restores the original dir owners
if [ "${KAS_CMD}" = "purge" ]; then
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e KAS_DOCKER_ROOTLESS_PURGE=1"
fi
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e KAS_DOCKER_ROOTLESS=1"
}

KAS_GIT_OVERLAY_FILE=""
kas_container_cleanup()
{
Expand Down Expand Up @@ -237,6 +267,7 @@ case "${KAS_CONTAINER_ENGINE}" in
docker)
KAS_CONTAINER_COMMAND="docker"
enable_unpriv_userns_docker
check_docker_rootless
;;
podman)
KAS_CONTAINER_COMMAND="podman"
Expand Down Expand Up @@ -480,6 +511,9 @@ fi

set_container_image_var

if [ "${KAS_DOCKER_ROOTLESS}" = "1" ]; then
KAS_REPO_MOUNT_OPT_DEFAULT="ro"
fi
KAS_REPO_MOUNT_OPT="${KAS_REPO_MOUNT_OPT:-${KAS_REPO_MOUNT_OPT_DEFAULT}}"

KAS_FILES="$(echo "${KAS_FILES}" | sed 's|'"${KAS_REPO_DIR}"'/|/repo/|g')"
Expand All @@ -490,6 +524,10 @@ if [ "$(id -u)" -eq 0 ] && [ "${KAS_ALLOW_ROOT}" != "yes" ] ; then
"KAS_ALLOW_ROOT=yes to override."
fi

if [ "${KAS_DOCKER_ROOTLESS}" = "1" ]; then
enable_docker_rootless
fi

set -- "$@" -v "${KAS_REPO_DIR}:/repo:${KAS_REPO_MOUNT_OPT}" \
-v "${KAS_WORK_DIR}":/work:rw -e KAS_WORK_DIR=/work \
--workdir=/repo \
Expand Down

0 comments on commit d04daa8

Please sign in to comment.