Skip to content

[Docker] Install the cuRobo image from uv.lock - #7442

Closed
hujc7 wants to merge 25 commits into
isaac-sim:developfrom
hujc7:jichuanh/curobo-uv-install
Closed

[Docker] Install the cuRobo image from uv.lock#7442
hujc7 wants to merge 25 commits into
isaac-sim:developfrom
hujc7:jichuanh/curobo-uv-install

Conversation

@hujc7

@hujc7 hujc7 commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

cuRobo image cold build 1014.4 s → 630.6 s (−38%) and three long-standing workarounds
disappear, by resolving into the venv instead of Isaac Sim's site-packages.

Stacked on #7405. This branch is cut from that PR, so the page below shows its six
commits too. Review only fa8374de371 (Install the cuRobo Docker image from uv.lock)
docker/Dockerfile.curobo plus one changelog fragment. Merge #7405 first.

Description

Dockerfile.curobo was the last CI-built image still installing with pip into Isaac Sim's
site-packages. That shared prefix forced three workarounds, each caused by the previous one:

Removed Why it is no longer needed
rm -rf .../pip_prebundle/torch* the venv has its own torch; Isaac Sim's is not on its path
get-pip.py re-bootstrap (+ a network download) only existed because deleting torch* corrupts pip's vendored _structures.py
pip uninstall -y quadprog quadprog is not a uv.lock entry, so it is never installed
pip install toml pytest install_deps.py uses tomllib; pytest comes from the test-runtime extra
pip install --editable .../isaaclab_teleop a workspace member, installed by the sync

cuRobo itself is deliberately kept out of uv.lock: the lock is shared with the base and
kit-less images, and neither should resolve it. It is installed from its pinned commit after
the sync, with build isolation off so its CUDA extensions build against the environment's torch.

The image also inherits the base image's build changes from #7405 — uv cache mounts,
third-party resolution above the source copy, ownership set in the layer that creates the venv,
and the prebundle repoint that stops Isaac Sim's torch shadowing the venv for launch paths that
never import isaaclab (nvbugs 6343978).

Validation

Built and tested locally on an RTX PRO 6000; CI's exact test-curobo selection:

Check Result
Cold build (--no-cache) 1014.4 s → 630.6 s; 46.0 GB → 45.5 GB
test_curobo_planner_franka.py 5 passed
test_curobo_planner_cube_stack.py 1 passed
test_pink_ik.py 23 passed, 1 skipped
test_no_shadowing_prebundled_torch_in_isaac_sim 1 passed (0 shadowing dirs, 17 repointed)

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Release backport

  • Backport this pull request to the active release branch after it merges into develop

Checklist

  • I have read and understood the contribution guidelines
  • I have run the pre-commit checks with ./isaaclab.sh --format
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Existing tests cover this change (test_curobo_planner_*, test_pink_ik, and the Dockerfile contract tests); no new test was needed
  • I have added a changelog fragment under source/<pkg>/changelog.d/ for every touched package
  • I have added my name to the CONTRIBUTORS.md or my name already exists there

hujc7 added 18 commits August 28, 2026 02:11
Adds a composable teleop-no-isaacsim extra so the lock path selects the teleop
requirements without pulling the isaacsim wheel into an image that already ships
Kit. Derives the submodule extras from OPTIONAL_SUBMODULE_ROOT_EXTRAS instead of a
second hardcoded table, and falls back to pip rather than installing less than was
asked for. Pins the uv pip calls to the venv: UV_PYTHON selects the target
environment, so they were writing into Isaac Sim's site-packages.
Reverts the install CLI lock path: it also caught Conda environments, where uv
sync targets the project environment rather than the active one, breaking the
install_ci Conda tests. The images control VIRTUAL_ENV and UV_PROJECT_ENVIRONMENT
themselves, so Dockerfile.base syncs the lock directly through a named kit-image
extra. imageio-ffmpeg is excluded during the sync instead of uninstalled after.
The extras set gained teleop-no-isaacsim and kit-image. teleop now composes from
the former, so asserting on its literal requirement list no longer sees
isaaclab-mimic; flatten the isaaclab-dev[...] self-reference first so the contract
stays on what the extra resolves to.
run_tests.sh launches the test container with --user ${host_uid}:${host_gid}, so a
venv owned by the image's own user is read-only there and the test-time extras
install (pytetwild for tetrahedralization) fails with EACCES. Widen the mode
instead of chowning to a uid the image cannot know.
The teleop extra now composes through an isaaclab-dev[teleop-no-isaacsim]
self-reference. _root_extra_dependencies strips every isaaclab* requirement as a
workspace self-reference and isaacsim separately, so the list came back empty and
./isaaclab.sh -i teleop installed none of the teleop stack.

Expand root self-references before the workspace filter runs, guarding against a
cycle with a seen set.
The test extra pulls the whole Sphinx docs stack, so the images installed a bare
pytest and CI layered pytest-mock, junitparser, flaky and coverage on top in a
separate post-build docker build.

Split those runners into a test-runtime extra that test composes from, and pull it
into kit-image so both images carry them from the lock. In-image pytest goes from
238 passed / 23 failed to 257 passed / 4 failed; the 4 remaining fail identically
without this change.
Restore the uv cache mount and drop UV_NO_CACHE=1, which disabled the only
working build cache. Resolve the third-party packages from workspace manifests
above the source copy so a source edit re-runs only the workspace install
(240 packages in 6.0s -> 14 in 4ms).

Set ownership in the layer that creates the venv instead of a recursive chown
afterwards: on overlayfs a chown copies up every file it touches, so the base
image stored the 11.5GB venv twice. That layer drops from 1003.9s to 36.1s and
the image from 44.7GB to 33.2GB, with 0 of 98562 common files differing in owner
or mode. Kit-less sets the modes in its builder stage so the stage copy carries
them rather than adding an equivalent layer.

Also hoist the layers that depend on no repo content above the copies, give
isaaclab.sh an explicit 755 (sed -i rewrote it under the build umask, leaving it
unrunnable by other uids), and keep local ruff/pytest caches out of the context.
test_dockerfile_nonroot.py only globs Dockerfile.* and parses their text, but
build.yaml ran it inside the image via /isaac-sim/python.sh in both the
isaaclab_ov and curobo jobs. Kit's interpreter has no pytest once the install
moves to the venv, so those steps failed, and a text lint held a self-hosted GPU
runner in two places.

Move it to a ubuntu-latest job using the invocation kitless-docker.yml already
uses. The steps that verify the running container's uid stay where they are.
Two assumptions broke when the install moved into a venv.

The uv path was derived from site.getuserbase() and bootstrapped with pip install
uv, which only landed there because Isaac Sim's site-packages was read-only; pip
installs into the venv's own bin instead, so $HOME/.local/bin/uv never appeared
and record-video died with No such file or directory. Prefer uv from PATH, which
the image ships, and keep the user-base bootstrap for images that do not.

The [INFO] banner isaaclab.sh writes to stdout now follows the command output
rather than preceding it, so tail -n 1 captured the banner for the interpreter,
user-site and uv paths. Filter the banner instead of skipping by position.
Isaac Sim ships prebundled copies under pip_prebundle that setup_python_env.sh
puts on PYTHONPATH. isaaclab.sh deprioritizes them, but launch paths that never
import isaaclab (runheadless.sh, isaac-sim.streaming.sh) do not, and the
prebundled torch loads a libtorch_cuda.so needing an NCCL symbol the bundled
NCCL does not export (nvbugs 6343978).

The pip install path repointed them itself; installing into a venv leaves them
untouched, so test_no_shadowing_prebundled_torch_in_isaac_sim failed. Reuse the
same repoint after the workspace sync, while the build is still root: 17
packages become symlinks into the venv and the shadowing directory count drops
to 0.
The image installed with pip into Isaac Sim's site-packages, which forced three
workarounds: deleting the prebundled torch so a fresh one would install, re-
bootstrapping pip afterwards because that deletion corrupts its vendored
_structures.py, and uninstalling quadprog. Resolving into the venv removes the
cause of all three - quadprog is not a lock entry at all - and drops the separate
toml/pytest and editable isaaclab_teleop installs, which the sync now provides.

cuRobo stays out of the lock so the kit-less and base images do not resolve it;
it is installed from its pinned commit afterwards, with build isolation off so
its CUDA extensions build against the venv's torch.

Carries the base image's caching and ordering: uv cache mounts, third-party
resolution above the source copy, ownership set in the creating layer, and the
prebundle repoint that keeps Isaac Sim's torch from shadowing the venv.

Cold build 1014.4s -> 630.6s; 30 passed / 1 skipped across
test_curobo_planner_franka, test_curobo_planner_cube_stack and test_pink_ik.
@github-actions github-actions Bot added documentation Improvements or additions to documentation isaac-lab Related to Isaac Lab team infrastructure labels Aug 31, 2026
@hujc7 hujc7 added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Aug 31, 2026
hujc7 added 4 commits August 31, 2026 00:21
The images excluded imageio-ffmpeg, so moviepy.editor - which
isaaclab/envs/utils/video_recorder.py imports - fell through to imageio's TIFF
writer and raised TypeError on write. Video recording only worked because CI
installs moviepy into the container at test time.

Pull the existing video extra into kit-image and drop the exclusion. Costs
31.6 MB (moviepy, imageio-ffmpeg, proglog) on a 33 GB image; verified in-image
that ImageSequenceClip.write_videofile produces a real mp4.
Mirrors the base image: the video extra now comes from kit-image, so the
imageio-ffmpeg exclusion would strip the backend moviepy.editor needs.
@hujc7 hujc7 added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Aug 31, 2026
@hujc7 hujc7 added ci:run-docker Trigger the on-demand Docker and GPU CI workflow and removed ci:run-docker Trigger the on-demand Docker and GPU CI workflow labels Aug 31, 2026
@hujc7 hujc7 closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation infrastructure isaac-lab Related to Isaac Lab team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant