diff --git a/container-entrypoint b/container-entrypoint index ab81b5ec..0d14be63 100755 --- a/container-entrypoint +++ b/container-entrypoint @@ -35,13 +35,43 @@ 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() +{ + _CHOWN_DIRS="/build /work" + if [ -d "/sstate" ]; then + _CHOWN_DIRS="$_CHOWN_DIRS /sstate" + fi + if [ -d "/downloads" ]; then + _CHOWN_DIRS="$_CHOWN_DIRS /downloads" + fi + if [ -d "/repo-ref" ]; then + _CHOWN_DIRS="$_CHOWN_DIRS /repo-ref" + fi + # SC2086: Double quote to prevent globbing and word splitting. + # shellcheck disable=2086 + chown "$1":"$2" $_CHOWN_DIRS +} + +restore_managed_dirs_owner() +{ + if [ "$KAS_DOCKER_ROOTLESS" = "1" ]; then + chown_managed_dirs 0 0 + fi +} + 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="" @@ -58,6 +88,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 @@ -65,11 +104,17 @@ fi if [ -n "$1" ]; then case "$1" in - build|checkout|clean*|dump|for-all-repos|lock|menu|purge|shell|-*) + build|checkout|clean*|dump|for-all-repos|lock|menu|shell|-*) # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=2086 exec $GOSU kas "$@" ;; + purge) + trap restore_managed_dirs_owner EXIT INT TERM + # SC2086: Double quote to prevent globbing and word splitting. + # shellcheck disable=2086 + $GOSU kas "$@" + ;; *) # SC2086: Double quote to prevent globbing and word splitting. # shellcheck disable=2086 diff --git a/docs/userguide/kas-container-description.inc b/docs/userguide/kas-container-description.inc index accab109..b6be5bef 100644 --- a/docs/userguide/kas-container-description.inc +++ b/docs/userguide/kas-container-description.inc @@ -13,3 +13,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 `_ +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. diff --git a/kas-container b/kas-container index ee9c431a..9368ffd7 100755 --- a/kas-container +++ b/kas-container @@ -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 } @@ -157,6 +163,26 @@ enable_unpriv_userns_docker() 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 + KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e KAS_DOCKER_ROOTLESS=1" +} + KAS_GIT_OVERLAY_FILE="" kas_container_cleanup() { @@ -211,6 +237,7 @@ case "${KAS_CONTAINER_ENGINE}" in docker) KAS_CONTAINER_COMMAND="docker" enable_unpriv_userns_docker + check_docker_rootless ;; podman) KAS_CONTAINER_COMMAND="podman" @@ -459,6 +486,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')" @@ -469,6 +499,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 \ -v "${KAS_BUILD_DIR}":/build:rw \