Skip to content

[core][sandbox] Preserve archived mtimes when extracting image layers - #65737

Merged
pcmoritz merged 4 commits into
ray-project:masterfrom
xyuzh:sandbox-preserve-mtimes
Aug 28, 2026
Merged

[core][sandbox] Preserve archived mtimes when extracting image layers#65737
pcmoritz merged 4 commits into
ray-project:masterfrom
xyuzh:sandbox-preserve-mtimes

Conversation

@xyuzh

@xyuzh xyuzh commented Aug 26, 2026

Copy link
Copy Markdown
Member

Why are these changes needed?

extract_tar_layer writes regular files with copyfileobj and never calls os.utime, so every file in an extracted sandbox rootfs carries the extraction time as its mtime instead of the archived one.

That breaks in-sandbox tools that trust timestamps. The most visible victim is apt: it revalidates /var/lib/apt/lists with If-Modified-Since derived from the file mtime, so with a reset-to-now mtime the mirror answers 304 Not Modified for image-baked lists whose Release files expired long ago — and every apt-get install then 404s on package versions that no longer exist. Docker-extracted images don't have this problem because layer extraction preserves mtimes.

Found while running Terminal-Bench 2.1 oracle evaluations under Harbor against a Ray Sandbox deployment: every TB verifier bootstraps with apt-get install curl, and ~30% of the suite failed with this signature (verified in a live sandbox: rm -rf /var/lib/apt/lists/* && apt-get update immediately fixes it).

Fix: apply os.utime from the tar member after writing each regular file; directory mtimes are applied after the extraction loop (extracting children would bump them), best-effort.

Related issue number

Follow-up to #65570.

Checks

  • Signed off (DCO); pre-commit hooks pass on the changed files.
  • Unit test included: test_extract_tar_layer_preserves_mtimes (pure, no runsc needed).

extract_tar_layer wrote files with copyfileobj and never called
os.utime, so every file in the sandbox rootfs carried the extraction
time as its mtime. That breaks tools that trust timestamps — most
visibly apt, which revalidates its package lists with
If-Modified-Since derived from the file mtime: with a reset-to-now
mtime, mirrors answer 304 and apt keeps stale image-baked lists whose
Release files have long expired, failing every 'apt-get install' with
404s. Found running Terminal-Bench 2.1 under Harbor, where every
verifier bootstraps with apt-get and ~30% of tasks failed on this.

Directory mtimes are applied after the extraction loop (extracting
children would bump them) and are best-effort.

Signed-off-by: xyuzh <xinyzng@gmail.com>
@xyuzh
xyuzh requested a review from a team as a code owner August 26, 2026 08:12

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request updates the container image extraction logic to preserve archived modification times (mtimes) for files and directories, ensuring tools like apt inside the sandbox can correctly validate package lists. A corresponding unit test was also added to verify this behavior. The review feedback suggests two robust improvements: wrapping the file mtime update in a try-except block to handle potential OS errors gracefully, and checking if a directory path is a symlink before applying mtime updates to avoid corrupting target directories in UsrMerge environments.

Comment thread python/ray/experimental/sandbox/_internal/image_utils.py Outdated
Comment thread python/ray/experimental/sandbox/_internal/image_utils.py Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 9657d20. Configure here.

Comment thread python/ray/experimental/sandbox/_internal/image_utils.py Outdated
@ray-gardener ray-gardener Bot added the core Issues that should be addressed in Ray Core label Aug 26, 2026

@pcmoritz pcmoritz left a comment

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.

Looks great!

@pcmoritz pcmoritz added the go add ONLY when ready to merge, run all tests label Aug 26, 2026
Comment thread python/ray/experimental/sandbox/_internal/image_utils.py Outdated
Comment thread python/ray/experimental/sandbox/_internal/image_utils.py
xyuzh and others added 2 commits August 27, 2026 17:29
Review feedback: wrap the per-file utime in try/except OSError like
the directory pass (preserving mtimes is best-effort), and skip
preserved symlinks in the directory pass — under UsrMerge images
(/bin -> usr/bin) utime would follow the link and stamp the target
with the wrong time.

Signed-off-by: xyuzh <xinyzng@gmail.com>
Fix another small nit pointed out by Andrew

Signed-off-by: Philipp Moritz <pcmoritz@gmail.com>
@pcmoritz
pcmoritz merged commit edc419a into ray-project:master Aug 28, 2026
6 checks passed
pcmoritz pushed a commit that referenced this pull request Aug 31, 2026
## Why are these changes needed?

Two filesystem-behavior divergences from Docker, both found running
Terminal-Bench 2.1 oracle evaluations in Ray sandboxes (via the Harbor
integration):

1. **`localhost` does not resolve.** Container engines inject
`/etc/hosts` at run time, so images do not ship a usable one — and the
sandbox never provided it either. glibc consults hosts files before DNS,
and public resolvers will not answer for `localhost`, so every task that
starts a local server and connects to it fails with `Name or service not
known` (6 of 89 TB tasks). Fix: generate a per-sandbox hosts file next
to the generated `resolv.conf` (seeded from the node's file under host
networking) and bind-mount it **read-write**, matching engine behavior —
the source is always a per-sandbox copy, never the node's file.

2. **`/tmp` sits on a different device than the rootfs.** runsc mounts a
private tmpfs over an *empty* `/tmp`, so the common
tempfile-then-`rename(2)` pattern fails with `EXDEV` where it works
under Docker (plain rootfs `/tmp`). Fix: seed the extracted rootfs
`/tmp` with a placeholder so runsc keeps it on the rootfs; **readonly**
sandboxes get an explicit tmpfs mount instead, preserving the
always-writable `/tmp` they have today.

## Related issue number

Follow-up to #65570, sibling of #65737.

## Checks

- [x] Signed off (DCO); pre-commit hooks pass on the changed files.
- [ ] Unit tests included (`test_oci_spec_docker_parity_hosts_and_tmp`,
`test_prepare_oci_bundle_writes_hosts_file`); both run without gVisor.

---------

Signed-off-by: xyuzh <xinyzng@gmail.com>
pcmoritz added a commit that referenced this pull request Sep 1, 2026
## Why are these changes needed?

Sandbox image pulls are anonymous Docker Hub pulls. A cluster of nodes
pulling distinct multi-GB benchmark images concurrently runs straight
into Docker Hub's anonymous rate limits and pays WAN latency on every
node — during a Terminal-Bench 2.1 evaluation under Harbor, big-image
tasks failed in the concurrent sweep but passed in isolation.

`RAY_SANDBOX_REGISTRY_MIRROR` names a registry that mirrors Docker Hub,
as `host[:port][/repo-prefix]`:

- an **ECR pull-through cache**
(`<acct>.dkr.ecr.<region>.amazonaws.com/dockerhub`),
- an **Artifact Registry remote repository**, or
- an in-cluster `registry:2` proxy.

Docker Hub pulls are rewritten to the mirror (the prefix prepended to
the repository, as ECR requires); other registries pass through
untouched. This mirrors Docker's own `registry-mirrors` semantics, minus
the fallback: when set, the mirror is authoritative, and it uses the
same anonymous token flow as any registry.

## Related issue number

Follow-up to #65570; sibling of #65737 and #65744.

## Checks

- [x] Signed off (DCO); pre-commit hooks pass on the changed files.
- [ ] Unit test included
(`test_registry_mirror_rewrites_docker_hub_only`); runs without gVisor
or network.

---------

Signed-off-by: xyuzh <xinyzng@gmail.com>
Signed-off-by: Philipp Moritz <pcmoritz@gmail.com>
Co-authored-by: Philipp Moritz <pcmoritz@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Issues that should be addressed in Ray Core go add ONLY when ready to merge, run all tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants