diff --git a/container-entrypoint b/container-entrypoint index 0b6a5e1a..915a747b 100755 --- a/container-entrypoint +++ b/container-entrypoint @@ -24,6 +24,20 @@ # kas-isar: sudo update-binfmts --enable && [ -f /proc/sys/fs/binfmt_misc/status ] +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 mount | grep -q "on / type aufs"; then cat <&2 WARNING: Generation of wic images will fail! @@ -51,6 +65,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. + sudo git config --system safe.directory /repo + chown_managed_dirs "$USER_ID" "$GROUP_ID" +fi if [ "$PWD" = / ]; then cd /builder || exit 1 @@ -59,9 +82,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. diff --git a/docs/userguide/kas-container-description.inc b/docs/userguide/kas-container-description.inc index ac8397a9..ad8e5030 100644 --- a/docs/userguide/kas-container-description.inc +++ b/docs/userguide/kas-container-description.inc @@ -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 `_ +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. diff --git a/kas-container b/kas-container index 329abeab..f786d35b 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 } @@ -216,6 +222,27 @@ forward_dir() 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() { @@ -277,6 +304,7 @@ case "${KAS_CONTAINER_ENGINE}" in docker) KAS_CONTAINER_COMMAND="docker" enable_unpriv_userns_docker + check_docker_rootless ;; podman) KAS_CONTAINER_COMMAND="podman" @@ -520,6 +548,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')" @@ -530,6 +561,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 \