Skip to content
49 changes: 45 additions & 4 deletions docker/Dockerfile.curobo
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ ENV DOCKER_USER_HOME=${DOCKER_USER_HOME_ARG}
ENV LANG=C.UTF-8
ENV DEBIAN_FRONTEND=noninteractive

# Base image ends with USER isaac-sim (uid 1234); switch to root for
# system-level setup (apt, cuda, /bin/nvidia-* placeholders, etc.).
USER root

# Install dependencies
Expand Down Expand Up @@ -145,9 +147,48 @@ RUN rm -rf ${ISAACSIM_ROOT_PATH}/kit/python/lib/python3.12/site-packages/pip* &&
${ISAACLAB_PATH}/_isaac_sim/kit/python/bin/python3 get-pip.py && \
rm get-pip.py

# Create a non-root runtime user with uid/gid 1000 to match the CI runner
# host user that owns the bind-mounted /workspace/isaaclab. Without this
# match, runtime `mkdir tests` etc. fail with EACCES on the bind-mount
# overlay. The base image already provisions an isaac-sim user (uid 1234)
# which keeps ownership of /isaac-sim; we only chown the paths the new user
# needs to write to so we don't trigger an OverlayFS copy-up of the multi-GB
# Isaac Sim install. /isaac-sim stays mode 755 so isaaclab can still
# read+exec it.
#
# --non-unique (-o) on both groupadd and useradd is required because some
# base image revisions already carry a group/user at gid/uid 1000 (e.g. an
# `ubuntu`/`kit`-style account). The file system only cares about numeric
# IDs, so two names mapping to the same numeric ID is fine; resolving
# "isaaclab" via /etc/passwd still returns our /home/isaaclab entry, so
# build-time ${HOME}/.bashrc writes land where we own the path. We pin the
# group's GID explicitly to 1000 (instead of letting useradd auto-pick one
# when the default GID is taken) so that the BuildKit pip cache mount's
# `gid=1000` matches the user's primary group.
RUN groupadd --non-unique --gid 1000 isaaclab \
&& useradd --non-unique --uid 1000 --gid 1000 -m -l -s /bin/bash -d /home/isaaclab isaaclab

RUN chown -R isaaclab:isaaclab \
${ISAACLAB_PATH} \
${ISAACSIM_ROOT_PATH}/kit/python/lib/python3.12/site-packages \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded Python version will break on base-image upgrade

python3.12 is hard-coded in the chown path. If the upstream Isaac Sim base image ships Python 3.13 (or any other version), this path won't exist and the RUN chown -R layer will fail at build time with "No such file or directory," breaking the entire image build.

Use a glob or a shell expansion to resolve the versioned directory dynamically:

Suggested change
${ISAACSIM_ROOT_PATH}/kit/python/lib/python3.12/site-packages \
$(ls -d ${ISAACSIM_ROOT_PATH}/kit/python/lib/python3.*/site-packages 2>/dev/null | head -1) \

${DOCKER_USER_HOME} \
/home/isaaclab

# Open up traversal of ${ISAACSIM_ROOT_PATH} for non-owner users. The base
# image creates /isaac-sim as the isaac-sim user's home directory, which on
# recent Ubuntu defaults to mode 0700 (HOME_MODE in /etc/login.defs). Without
# at least exec for "other", isaaclab cannot enter the directory to find
# python.sh or the Kit runtime, and `isaaclab.sh -p` falls back to the
# nonexistent system python3. Inner files retain their original perms (NVIDIA
# ships them world-readable per standard distribution conventions), so we
# only need to relax the top-level directory.
RUN chmod 755 ${ISAACSIM_ROOT_PATH}

USER isaaclab

# installing Isaac Lab dependencies
# use pip caching to avoid reinstalling large packages
RUN --mount=type=cache,target=${DOCKER_USER_HOME}/.cache/pip \
RUN --mount=type=cache,target=${DOCKER_USER_HOME}/.cache/pip,uid=1000,gid=1000 \
${ISAACLAB_PATH}/isaaclab.sh --install
Comment on lines +191 to 192
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pip cache mount target mismatches the isaaclab user's $HOME

After USER isaaclab, pip resolves its cache via ${HOME} — which points to /home/isaaclab (the user's home directory from /etc/passwd). The --mount target is ${DOCKER_USER_HOME}/.cache/pip which expands to /root/.cache/pip in CI. Pip will therefore write to /home/isaaclab/.cache/pip and never read from (or populate) the BuildKit cache mounted at /root/.cache/pip, making the cache layer a no-op.

The mount target should follow the user's actual $HOME:

RUN --mount=type=cache,target=/home/isaaclab/.cache/pip,uid=1000,gid=1000 \
    ${ISAACLAB_PATH}/isaaclab.sh --install

If keeping DOCKER_USER_HOME as the single source of truth is preferred, ENV HOME=${DOCKER_USER_HOME} (after updating DOCKER_USER_HOME_ARG to /home/isaaclab in CI) would reconcile both variables.


# HACK: Uninstall quadprog as it causes issues with some reinforcement learning frameworks
Expand All @@ -169,11 +210,11 @@ RUN echo "export ISAACLAB_PATH=${ISAACLAB_PATH}" >> ${HOME}/.bashrc && \
echo "alias pip3='${ISAACLAB_PATH}/_isaac_sim/python.sh -m pip'" >> ${HOME}/.bashrc && \
echo "alias tensorboard='${ISAACLAB_PATH}/_isaac_sim/python.sh ${ISAACLAB_PATH}/_isaac_sim/tensorboard'" >> ${HOME}/.bashrc && \
echo "export TZ=$(date +%Z)" >> ${HOME}/.bashrc && \
echo "shopt -s histappend" >> /root/.bashrc && \
echo "PROMPT_COMMAND='history -a'" >> /root/.bashrc
echo "shopt -s histappend" >> ${HOME}/.bashrc && \
echo "PROMPT_COMMAND='history -a'" >> ${HOME}/.bashrc

# copy the rest of the files
COPY ../ ${ISAACLAB_PATH}/
COPY --chown=isaaclab:isaaclab ../ ${ISAACLAB_PATH}/

# make working directory as the Isaac Lab directory
# this is the default directory when the container is run
Expand Down
Loading