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 shall be exclusive dirs 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 Feb 7, 2025
1 parent b136c67 commit f713507
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 4 deletions.
44 changes: 40 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 "$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,16 @@ 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 restore the dir owner after every kas invocation.
# This is cheap as only the top-level dirs are changed (non recursive).
if [ "$KAS_DOCKER_ROOTLESS" = "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
12 changes: 12 additions & 0 deletions docs/userguide/kas-container-description.inc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ 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. It is recommended to use a distinct ``KAS_WORK_DIR`` outside of the
calling directory (repo-dir), as kas temporarily changes the ownership of the working
directory during its operation. All files managed by kas (including the repos) 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.
35 changes: 35 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 @@ -190,6 +196,27 @@ 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
warning "On docker rootless a exclusive KAS_WORK_DIR should be used" \
"as kas temporarily changes the ownership of this directory."
fi
if [ "${KAS_REPO_MOUNT_OPT}" = "rw" ]; then
fatal_error "Docker rootless requires read-only repo."
fi
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e KAS_DOCKER_ROOTLESS=1"
}

KAS_GIT_OVERLAY_FILE=""
kas_container_cleanup()
{
Expand Down Expand Up @@ -247,6 +274,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 @@ -490,6 +518,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 @@ -500,6 +531,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 f713507

Please sign in to comment.