Skip to content

Commit 4551023

Browse files
Debug Agentclaude
andcommitted
fix(docker): bundle Python runtime for portable /agent-server
After building the venv with system Python, copy the interpreter binary, standard library, and libpython shared objects into /agent-server/.python/. Re-point the venv symlinks and pyvenv.cfg at the bundled copy so that the entire /agent-server directory is self-contained. This means eval images (and any other consumer) can COPY /agent-server onto any base image — even one without Python at /usr/local/bin — and the entrypoint will resolve. Without this fix, commit0 eval images (Ubuntu 22.04 base, Python at /usr/bin/python3) fail to start because the venv symlinks point to the builder's /usr/local/bin/python3 which doesn't exist in the target image. Fixes OpenHands/benchmarks#607 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1f58208 commit 4551023

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

  • openhands-agent-server/openhands/agent_server/docker

openhands-agent-server/openhands/agent_server/docker/Dockerfile

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ ARG PORT=8000
2020
# Docker-in-Docker) reject dlopen() on such libraries with:
2121
# "cannot enable executable stack as shared object requires: Invalid argument"
2222
# Debian's CPython packages do not have this issue.
23+
#
24+
# PORTABILITY: After the venv is built we bundle the interpreter, stdlib,
25+
# and libpython into /agent-server/.python/ and repoint the venv at it.
26+
# This makes /agent-server fully self-contained — downstream consumers
27+
# (e.g. eval images) can COPY it onto any base image without needing a
28+
# compatible system Python.
2329
####################################################################################
2430
FROM python:3.13-bookworm AS builder
2531
ARG USERNAME UID GID
@@ -40,6 +46,51 @@ COPY --chown=${USERNAME}:${USERNAME} openhands-agent-server ./openhands-agent-se
4046
RUN --mount=type=cache,target=/home/${USERNAME}/.cache,uid=${UID},gid=${GID} \
4147
uv venv --python-preference only-system .venv && uv sync --frozen --no-editable --extra boto3
4248

49+
# Bundle the Python runtime inside /agent-server so that the entire directory
50+
# is self-contained and portable. Eval images (and any other consumer) can
51+
# COPY /agent-server onto *any* base image without requiring that base image
52+
# to ship a compatible system Python.
53+
#
54+
# What we copy:
55+
# .python/bin/python3.13 – the interpreter binary
56+
# .python/lib/python3.13/ – the standard library (minus tests)
57+
# .python/lib/libpython*.so* – shared libraries (Debian builds --enable-shared)
58+
#
59+
# We then repoint the venv's symlinks and pyvenv.cfg at the bundled copy.
60+
RUN set -eux; \
61+
REAL_PYTHON=$(readlink -f .venv/bin/python3); \
62+
PY_VER=$("${REAL_PYTHON}" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"); \
63+
PYTHON_PREFIX=$("${REAL_PYTHON}" -c "import sys; print(sys.base_prefix)"); \
64+
# --- copy interpreter binary ------------------------------------------------- \
65+
mkdir -p .python/bin; \
66+
cp "${REAL_PYTHON}" ".python/bin/python${PY_VER}"; \
67+
ln -s "python${PY_VER}" .python/bin/python3; \
68+
ln -s "python${PY_VER}" .python/bin/python; \
69+
# --- copy standard library (skip test suite to save ~30 MB) ------------------ \
70+
mkdir -p .python/lib; \
71+
cp -a "${PYTHON_PREFIX}/lib/python${PY_VER}" ".python/lib/python${PY_VER}"; \
72+
rm -rf ".python/lib/python${PY_VER}/test" \
73+
".python/lib/python${PY_VER}/tests" \
74+
".python/lib/python${PY_VER}/idle_test" \
75+
".python/lib/python${PY_VER}/idlelib"; \
76+
# --- copy shared libraries (libpython) --------------------------------------- \
77+
for lib in "${PYTHON_PREFIX}"/lib/libpython*.so*; do \
78+
[ -e "$lib" ] && cp -a "$lib" .python/lib/; \
79+
done; \
80+
# --- repoint venv at the bundled Python -------------------------------------- \
81+
for f in .venv/bin/python*; do \
82+
[ -L "$f" ] || continue; \
83+
name=$(basename "$f"); \
84+
rm "$f"; \
85+
ln -s "../../.python/bin/${name}" "$f"; \
86+
done; \
87+
# Ensure canonical names resolve (some venvs only create python3 + python) \
88+
[ -L .venv/bin/python ] || ln -s "../../.python/bin/python" .venv/bin/python; \
89+
[ -L .venv/bin/python3 ] || ln -s "../../.python/bin/python3" .venv/bin/python3; \
90+
sed -i "s|^home = .*|home = /agent-server/.python/bin|" .venv/pyvenv.cfg; \
91+
# --- quick smoke-test inside the builder ------------------------------------- \
92+
.venv/bin/python -c "import sys; print('bundled python:', sys.executable, sys.version)"
93+
4394
####################################################################################
4495
# Binary Builder (binary mode)
4596
# We run pyinstaller here to produce openhands-agent-server
@@ -272,11 +323,14 @@ EXPOSE ${PORT} ${NOVNC_PORT}
272323
FROM base-image AS source
273324
ARG USERNAME
274325
COPY --chown=${USERNAME}:${USERNAME} --from=builder /agent-server /agent-server
326+
# Bundled Python's libpython*.so lives under /agent-server/.python/lib
327+
ENV LD_LIBRARY_PATH=/agent-server/.python/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
275328
ENTRYPOINT ["/agent-server/.venv/bin/python", "-m", "openhands.agent_server"]
276329

277330
FROM base-image-minimal AS source-minimal
278331
ARG USERNAME
279332
COPY --chown=${USERNAME}:${USERNAME} --from=builder /agent-server /agent-server
333+
ENV LD_LIBRARY_PATH=/agent-server/.python/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
280334
ENTRYPOINT ["/agent-server/.venv/bin/python", "-m", "openhands.agent_server"]
281335

282336
############################

0 commit comments

Comments
 (0)