Skip to content

Commit b1af917

Browse files
ivanbasovclaude
andcommitted
Harden CI container options and cluster training scripts
GPU CI jobs: drop the explicit root user and the disabled seccomp profile from the container options; the ubuntu image already runs as root for the apt-get steps and the default seccomp profile is sufficient. SLURM/Docker path: the base-image fallback no longer makes the shared output directory world-writable (chmod 1777). Instead sbatch_train.sh passes the submitting user's UID/GID into the container and cluster_container_install_and_train.sh drops privileges with setpriv before running training, so output files are owned by the user. Verified in a local ubuntu:22.04 container that files written under the mounted output directory are owned by the host UID. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Ivan Basov <ibasov@nvidia.com>
1 parent 33acb15 commit b1af917

5 files changed

Lines changed: 36 additions & 15 deletions

File tree

‎.github/workflows/ci-gpu.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
contents: write
4848
container:
4949
image: ubuntu:24.04
50-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
50+
options: --shm-size 16g
5151
env:
5252
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
5353
timeout-minutes: 45
@@ -129,7 +129,7 @@ jobs:
129129
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
130130
container:
131131
image: ubuntu:24.04
132-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
132+
options: --shm-size 16g
133133
env:
134134
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
135135
timeout-minutes: 40
@@ -197,7 +197,7 @@ jobs:
197197
runs-on: linux-amd64-gpu-rtxpro6000-latest-2
198198
container:
199199
image: ubuntu:24.04
200-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
200+
options: --shm-size 16g
201201
env:
202202
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
203203
timeout-minutes: 35
@@ -303,7 +303,7 @@ jobs:
303303
contents: write
304304
container:
305305
image: ubuntu:24.04
306-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
306+
options: --shm-size 16g
307307
env:
308308
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
309309
timeout-minutes: 20

‎.github/workflows/long-running-tests.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ jobs:
9090
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
9191
container:
9292
image: ubuntu:24.04
93-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
93+
options: --shm-size 16g
9494
env:
9595
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
9696
timeout-minutes: 30
@@ -140,7 +140,7 @@ jobs:
140140
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
141141
container:
142142
image: ubuntu:24.04
143-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
143+
options: --shm-size 16g
144144
env:
145145
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
146146
timeout-minutes: 90
@@ -219,7 +219,7 @@ jobs:
219219
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
220220
container:
221221
image: ubuntu:24.04
222-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
222+
options: --shm-size 16g
223223
env:
224224
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
225225
timeout-minutes: 60
@@ -271,7 +271,7 @@ jobs:
271271
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
272272
container:
273273
image: ubuntu:24.04
274-
options: -u root --security-opt seccomp=unconfined --shm-size 16g
274+
options: --shm-size 16g
275275
env:
276276
NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }}
277277
timeout-minutes: 90

‎TRAINING.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,10 @@ $SHARED_OUTPUT_DIR/
296296
3. **Docker base image**: set `DOCKER_BASE_IMAGE` if your cluster uses a different CUDA runtime.
297297

298298
4. **File systems**: `SHARED_OUTPUT_DIR` should be on a shared/persistent filesystem
299-
visible from all nodes (NFS, Lustre, etc.). The sbatch script sets `chmod 1777` for
300-
NFS compatibility when using Docker.
299+
visible from all nodes (NFS, Lustre, etc.). When using Docker, the training
300+
process runs as the submitting user's UID/GID (the base-image path installs
301+
dependencies as root, then drops privileges), so no special directory
302+
permissions are needed.
301303

302304
5. **No Docker?** The scripts fall back to bare-metal install automatically.
303305
Ensure the node has internet access (for pip) or pre-install deps via `cluster_install_deps.sh`.

‎code/scripts/cluster_container_install_and_train.sh‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,24 @@ if [ -z "${PREDECODER_PYTHON:-}" ]; then
6666
[ -x "${INSTALL_DIR}/miniconda3/envs/predecoder/bin/python" ] && export PREDECODER_PYTHON="${INSTALL_DIR}/miniconda3/envs/predecoder/bin/python"
6767
fi
6868
log "PREDECODER_PYTHON=${PREDECODER_PYTHON:-<unset>}"
69+
70+
# Drop privileges for training when the container was started as root on behalf
71+
# of a host user (HOST_UID/HOST_GID set by sbatch_train.sh). Installation above
72+
# needs root; training does not, and files written to the shared output
73+
# directory should be owned by the submitting user.
74+
RUN_AS=()
75+
if [ "$(id -u)" -eq 0 ] && [ -n "${HOST_UID:-}" ] && [ "${HOST_UID}" != "0" ] && command -v setpriv >/dev/null 2>&1; then
76+
HOST_GID="${HOST_GID:-$HOST_UID}"
77+
TRAIN_HOME="${TRAIN_HOME:-/tmp/predecoder-home}"
78+
mkdir -p "$TRAIN_HOME" && chown "${HOST_UID}:${HOST_GID}" "$TRAIN_HOME"
79+
export HOME="$TRAIN_HOME" USER="predecoder" LOGNAME="predecoder"
80+
RUN_AS=(setpriv --reuid="$HOST_UID" --regid="$HOST_GID" --clear-groups --inh-caps=-all)
81+
log "Training as uid:gid ${HOST_UID}:${HOST_GID} (HOME=$HOME)."
82+
fi
83+
6984
if command -v stdbuf >/dev/null 2>&1; then
70-
stdbuf -oL -eL bash "$REPO_ROOT/code/scripts/cluster_train.sh"
85+
"${RUN_AS[@]}" stdbuf -oL -eL bash "$REPO_ROOT/code/scripts/cluster_train.sh"
7186
else
72-
bash "$REPO_ROOT/code/scripts/cluster_train.sh"
87+
"${RUN_AS[@]}" bash "$REPO_ROOT/code/scripts/cluster_train.sh"
7388
fi
7489
log "Done."

‎code/scripts/sbatch_train.sh‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,17 @@ if command -v docker >/dev/null 2>&1 && docker image inspect "$DOCKER_IMAGE" >/d
152152
"${COMMON_ENV[@]}" \
153153
"$DOCKER_IMAGE" 2>&1
154154
elif command -v docker >/dev/null 2>&1 && docker run --rm --gpus all "$DOCKER_BASE_IMAGE" nvidia-smi -L >/dev/null 2>&1; then
155-
log "Setting sticky bit on $SHARED_OUTPUT_DIR for NFS/Docker UID compatibility."
156-
chmod 1777 "$SHARED_OUTPUT_DIR" 2>/dev/null || true
157-
log "Using Docker base image $DOCKER_BASE_IMAGE (install + train)."
155+
log "Using Docker base image $DOCKER_BASE_IMAGE (install as root, train as ${HOST_UID}:${HOST_GID})."
156+
# The container starts as root to apt-get/pip install, then
157+
# cluster_container_install_and_train.sh drops to HOST_UID:HOST_GID before
158+
# training so files written to the shared output directory are owned by the
159+
# submitting user (and NFS root-squash is not an issue).
158160
docker run --rm --gpus all \
159161
-v "${REPO_ROOT}:/app:ro" \
160162
-v "${SHARED_OUTPUT_DIR}:/data" \
161163
-e INSTALL_DIR=/opt/predecoder_env \
164+
-e "HOST_UID=${HOST_UID}" \
165+
-e "HOST_GID=${HOST_GID}" \
162166
"${COMMON_ENV[@]}" \
163167
"$DOCKER_BASE_IMAGE" \
164168
bash -c 'export DEBIAN_FRONTEND=noninteractive; apt-get update -qq && apt-get install -y -qq python3.11 python3.11-venv python3.11-dev curl git coreutils build-essential cmake >/dev/null 2>&1; exec stdbuf -oL -eL bash /app/code/scripts/cluster_container_install_and_train.sh 2>&1'

0 commit comments

Comments
 (0)