aspect-build / aspect-build/rules_py
[FR]: Expose a stable venv location for non-launcher processes in py_image_layer images
- Dominant language
- Starlark
- Stars
- 145
- Forks
- 97
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 71
Description
### What's the problem?
`py_image_layer` ships a ready-to-run venv plus a compiled launcher at `/app`. The launcher sets `VIRTUAL_ENV` (and effectively puts the venv on `PATH`) for the process **it** spawns. But there's no stable, documented way for *other* processes in the same container — ones that don't go through the `/app` launcher — to locate or activate that venv.
Real cases where this bites:
- **KubeRay**: runs the head/worker `ray start` command through `bash -lc` (a login shell, whose `/etc/profile` resets `PATH`), and injects an **autoscaler sidecar** with its own `bash -c` command. Neither goes through the app launcher, so neither inherits `VIRTUAL_ENV`/`PATH` — yet both must resolve the venv's `ray` console script.
- **k8s health/readiness probes** exec a binary directly in the container (e.g. `wget … | grep`), independent of the launcher.
- Generally: any sidecar, cron-in-container, or login shell that needs the venv's console scripts / `python`.
Today the only handle is the venv directory's **internal** name — `._.venv/bin` (`py/private/py_venv/py_venv.bzl`, `venv_name = "." + safe_name`) — which consumers must reverse-engineer by globbing:
```sh
VENV_BIN=$(find /app.runfiles -type d -path '*/._*.venv/bin' | head -1)
export PATH="$VENV_BIN:$PATH"
```
That's undocumented and version-coupled: the `._.venv` naming is an implementation detail, and this is an alpha. We hit exactly this (an image entrypoint + a `wget` probe shim both globbing that path); it's the kind of thing a rules_py bump can silently break.
### Proposed
Give `py_image_layer` a **stable, documented** way to locate/activate the venv for non-launcher processes. Any one of:
1. **Image-level env** — have `py_image_layer` set `VIRTUAL_ENV` and prepend `$VIRTUAL_ENV/bin` to `PATH` in the image config `Env`, so *every* process in the container inherits it (the OCI analog of what the launcher already does per-process). Most ergonomic.
2. **Stable symlink** — a documented, stable path (e.g. `/.venv`) → the internal `._.venv`, so consumers reference a stable name instead of globbing.
3. At minimum, **document** the in-image venv-location contract.
### Notes
- Related but distinct: #533 (launcher needing a shell — about execution, not locating the venv from other processes). Same family as #1366 (venv omits wheel `share/` data_files) and #1369 (guidance not to hardcode `py_venv_link`'s venv path).
- Filing before the 2.0.0 stable release, since `._.venv` is currently the only handle.
- Environment: `aspect_rules_py` 2.0.0-alpha.5.
Contributor guide
Research direction
Start by reading py/private/py_venv/py_venv.bzl, especially the venv_name definition, and trace how py_image_layer constructs the image configuration. Decide which proposed stable contract fits the project, then verify that non-launcher processes can locate or activate the venv without depending on the internal name; document the resulting contract and add or update relevant coverage if available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- build-system
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100