From e3e96fa75e31de1c46f1634951a7b4c5e1b2454b Mon Sep 17 00:00:00 2001 From: David Boreham Date: Thu, 23 Feb 2023 20:50:20 -0700 Subject: [PATCH 1/4] Work around docker uid/gid insanity Former-commit-id: b84a28592df56104fc25ab6337ab5c53bfd658bd --- app/build_npms.py | 6 +++++- .../container-build/cerc-builder-js/Dockerfile | 1 + .../cerc-builder-js/entrypoint.sh | 1 + .../cerc-builder-js/fixup-for-uid.sh | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100755 app/data/container-build/cerc-builder-js/fixup-for-uid.sh diff --git a/app/build_npms.py b/app/build_npms.py index 83f87ede..877916be 100644 --- a/app/build_npms.py +++ b/app/build_npms.py @@ -116,7 +116,11 @@ def command(ctx, include, exclude): if not dry_run: if verbose: print(f"Executing: {build_command}") - envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token} | ({"CERC_SCRIPT_DEBUG": "true"} if debug else {}) + # Originally we used the PEP 584 merge operator: + # envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token} | ({"CERC_SCRIPT_DEBUG": "true"} if debug else {}) + # but that isn't available in Python 3.8 (default in Ubuntu 20) so for now we use dict.update: + envs = {"CERC_NPM_AUTH_TOKEN": npm_registry_url_token} + envs.update({"CERC_SCRIPT_DEBUG": "true"} if debug else {}) try: docker.run(builder_js_image_name, remove=True, diff --git a/app/data/container-build/cerc-builder-js/Dockerfile b/app/data/container-build/cerc-builder-js/Dockerfile index 9f460375..9a1cf680 100644 --- a/app/data/container-build/cerc-builder-js/Dockerfile +++ b/app/data/container-build/cerc-builder-js/Dockerfile @@ -39,6 +39,7 @@ RUN mkdir /scripts COPY build-npm-package.sh /scripts COPY yarn-local-registry-fixup.sh /scripts COPY build-npm-package-local-dependencies.sh /scripts +COPY fixup-for-uid.sh /scripts ENV PATH="${PATH}:/scripts" COPY entrypoint.sh . diff --git a/app/data/container-build/cerc-builder-js/entrypoint.sh b/app/data/container-build/cerc-builder-js/entrypoint.sh index 311cb8cb..cfbce454 100755 --- a/app/data/container-build/cerc-builder-js/entrypoint.sh +++ b/app/data/container-build/cerc-builder-js/entrypoint.sh @@ -1,2 +1,3 @@ #!/bin/sh +/scripts/fixup-for-uid.sh exec "$@" diff --git a/app/data/container-build/cerc-builder-js/fixup-for-uid.sh b/app/data/container-build/cerc-builder-js/fixup-for-uid.sh new file mode 100755 index 00000000..04089d08 --- /dev/null +++ b/app/data/container-build/cerc-builder-js/fixup-for-uid.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Make the container usable for uid/gid != 1000 +if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then + set -x +fi +current_uid=$(id -u) +current_gid=$(id -g) +user_name="hostuser" +# First check the current uid. If == 1000 then exit, nothing needed because that uid already exists +if [[ ${current_uid} == 1000 ]]; then + exit 0 +fi +# Also exit for root +if [[ ${current_uid} == 0 ]]; then + exit 0 +fi +# Create the user with home dir +useradd -m -d /home/${user_name} -s /bin/bash -g ${current_gid} -u ${current_uid} ${user_name} From 25a755982eb526f1a002abac09ad5ec6d189868d Mon Sep 17 00:00:00 2001 From: David Boreham Date: Fri, 24 Feb 2023 22:14:28 -0700 Subject: [PATCH 2/4] Implement new approach: build a uid-specific container Former-commit-id: 6704cd752703159530775718d6d61fdeed027bdb --- app/build_containers.py | 6 ++++-- .../cerc-builder-js/Dockerfile | 18 +++++++++++++++- .../cerc-builder-js/check-uid.sh | 21 +++++++++++++++++++ .../cerc-builder-js/entrypoint.sh | 2 +- .../cerc-builder-js/fixup-for-uid.sh | 18 ---------------- 5 files changed, 43 insertions(+), 22 deletions(-) create mode 100755 app/data/container-build/cerc-builder-js/check-uid.sh delete mode 100755 app/data/container-build/cerc-builder-js/fixup-for-uid.sh diff --git a/app/build_containers.py b/app/build_containers.py index 7ecf4a82..04cecd62 100644 --- a/app/build_containers.py +++ b/app/build_containers.py @@ -83,7 +83,9 @@ def command(ctx, include, exclude): container_build_env = { "CERC_NPM_URL": "http://gitea.local:3000/api/packages/cerc-io/npm/", "CERC_NPM_AUTH_TOKEN": config("CERC_NPM_AUTH_TOKEN", default=""), - "CERC_REPO_BASE_DIR": dev_root_path + "CERC_REPO_BASE_DIR": dev_root_path, + "CERC_HOST_UID": f"{os.getuid()}", + "CERC_HOST_GID": f"{os.getgid()}" } def process_container(container): @@ -106,7 +108,7 @@ def command(ctx, include, exclude): build_command = os.path.join(container_build_dir, "default-build.sh") + f" {container}:local {repo_dir_or_build_dir}" if not dry_run: if verbose: - print(f"Executing: {build_command}") + print(f"Executing: {build_command} with environment: {container_build_env}") build_result = subprocess.run(build_command, shell=True, env=container_build_env) if verbose: print(f"Return code is: {build_result.returncode}") diff --git a/app/data/container-build/cerc-builder-js/Dockerfile b/app/data/container-build/cerc-builder-js/Dockerfile index 9a1cf680..fb7043c9 100644 --- a/app/data/container-build/cerc-builder-js/Dockerfile +++ b/app/data/container-build/cerc-builder-js/Dockerfile @@ -1,14 +1,30 @@ # Originally from: https://github.com/devcontainers/images/blob/main/src/javascript-node/.devcontainer/Dockerfile +# Which depends on: https://github.com/nodejs/docker-node/blob/main/Dockerfile-debian.template # [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster ARG VARIANT=16-bullseye FROM node:${VARIANT} +# Set these args to change the uid/gid for the base container's "node" user to match that of the host user (so bind mounts work as expected). +ARG CERC_HOST_UID=1000 +ARG CERC_HOST_GID=1000 +# Make these values available at runtime to allow a consistency check. +ENV HOST_UID=${CERC_HOST_UID} +ENV HOST_GID=${CERC_HOST_GID} + ARG USERNAME=node ARG NPM_GLOBAL=/usr/local/share/npm-global # Add NPM global to PATH. ENV PATH=${NPM_GLOBAL}/bin:${PATH} +RUN \ + if [ ${CERC_HOST_GID} -ne 1000 ] ; then \ + groupmod -g ${CERC_HOST_GID} ${USERNAME} ; \ + fi \ + && if [ ${CERC_HOST_UID} -ne 1000 ] ; then \ + usermod -u ${CERC_HOST_UID} -g ${CERC_HOST_GID} ${USERNAME} ; \ + fi + RUN \ # Configure global npm install location, use group to adapt to UID/GID changes if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \ @@ -39,7 +55,7 @@ RUN mkdir /scripts COPY build-npm-package.sh /scripts COPY yarn-local-registry-fixup.sh /scripts COPY build-npm-package-local-dependencies.sh /scripts -COPY fixup-for-uid.sh /scripts +COPY check-uid.sh /scripts ENV PATH="${PATH}:/scripts" COPY entrypoint.sh . diff --git a/app/data/container-build/cerc-builder-js/check-uid.sh b/app/data/container-build/cerc-builder-js/check-uid.sh new file mode 100755 index 00000000..a8cbc324 --- /dev/null +++ b/app/data/container-build/cerc-builder-js/check-uid.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Make the container usable for uid/gid != 1000 +if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then + set -x +fi +current_uid=$(id -u) +current_gid=$(id -g) +# Don't check if running as root +if [[ ${current_uid} == 0 ]]; then + exit 0 +fi +# Check the current uid/gid vs the uid/gid used to build the container. +# We do this because both bind mounts and npm tooling require the uid/gid to match. +if [[ ${current_gid} != ${HOST_GID} ]]; then + echo "Warning: running with gid: ${current_gid} which is not the gid for which this container was built (${HOST_GID})" + exit 0 +fi +if [[ ${current_uid} != ${HOST_UID} ]]; then + echo "Warning: running with gid: ${current_uid} which is not the uid for which this container was built (${HOST_UID})" + exit 0 +fi diff --git a/app/data/container-build/cerc-builder-js/entrypoint.sh b/app/data/container-build/cerc-builder-js/entrypoint.sh index cfbce454..ab80737a 100755 --- a/app/data/container-build/cerc-builder-js/entrypoint.sh +++ b/app/data/container-build/cerc-builder-js/entrypoint.sh @@ -1,3 +1,3 @@ #!/bin/sh -/scripts/fixup-for-uid.sh +/scripts/check-uid.sh exec "$@" diff --git a/app/data/container-build/cerc-builder-js/fixup-for-uid.sh b/app/data/container-build/cerc-builder-js/fixup-for-uid.sh deleted file mode 100755 index 04089d08..00000000 --- a/app/data/container-build/cerc-builder-js/fixup-for-uid.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# Make the container usable for uid/gid != 1000 -if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then - set -x -fi -current_uid=$(id -u) -current_gid=$(id -g) -user_name="hostuser" -# First check the current uid. If == 1000 then exit, nothing needed because that uid already exists -if [[ ${current_uid} == 1000 ]]; then - exit 0 -fi -# Also exit for root -if [[ ${current_uid} == 0 ]]; then - exit 0 -fi -# Create the user with home dir -useradd -m -d /home/${user_name} -s /bin/bash -g ${current_gid} -u ${current_uid} ${user_name} From 467ff235baf3894bed78f081561a8710ec236734 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Fri, 24 Feb 2023 22:26:02 -0700 Subject: [PATCH 3/4] Propagate build env vars Former-commit-id: 5022e355ed9a88658e786a569ff1069ad31ecb56 --- app/data/container-build/default-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/data/container-build/default-build.sh b/app/data/container-build/default-build.sh index 3d5d9919..c52dd043 100755 --- a/app/data/container-build/default-build.sh +++ b/app/data/container-build/default-build.sh @@ -11,4 +11,4 @@ fi image_tag=$1 build_dir=$2 echo "Building ${image_tag} in ${build_dir}" -docker build -t ${image_tag} ${build_dir} +docker build -t ${image_tag} --build-arg CERC_HOST_UID=${CERC_HOST_UID} --build-arg CERC_HOST_GID=${CERC_HOST_GID} ${build_dir} From 9480b4082eeac25e55bbc68a538c65109a820ed4 Mon Sep 17 00:00:00 2001 From: David Boreham Date: Fri, 24 Feb 2023 22:44:50 -0700 Subject: [PATCH 4/4] usermod does not change group ownership of home dir Former-commit-id: 17355c9e4292a042e7c8416aafafb044e0fde3e2 --- app/data/container-build/cerc-builder-js/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/data/container-build/cerc-builder-js/Dockerfile b/app/data/container-build/cerc-builder-js/Dockerfile index fb7043c9..35c9a972 100644 --- a/app/data/container-build/cerc-builder-js/Dockerfile +++ b/app/data/container-build/cerc-builder-js/Dockerfile @@ -22,7 +22,7 @@ RUN \ groupmod -g ${CERC_HOST_GID} ${USERNAME} ; \ fi \ && if [ ${CERC_HOST_UID} -ne 1000 ] ; then \ - usermod -u ${CERC_HOST_UID} -g ${CERC_HOST_GID} ${USERNAME} ; \ + usermod -u ${CERC_HOST_UID} -g ${CERC_HOST_GID} ${USERNAME} && chown ${CERC_HOST_UID}:${CERC_HOST_GID} /home/${USERNAME} ; \ fi RUN \