@@ -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# ###################################################################################
2430FROM python:3.13-bookworm AS builder
2531ARG USERNAME UID GID
@@ -40,6 +46,51 @@ COPY --chown=${USERNAME}:${USERNAME} openhands-agent-server ./openhands-agent-se
4046RUN --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}
272323FROM base-image AS source
273324ARG USERNAME
274325COPY --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}
275328ENTRYPOINT ["/agent-server/.venv/bin/python" , "-m" , "openhands.agent_server" ]
276329
277330FROM base-image-minimal AS source-minimal
278331ARG USERNAME
279332COPY --chown=${USERNAME}:${USERNAME} --from=builder /agent-server /agent-server
333+ ENV LD_LIBRARY_PATH=/agent-server/.python/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
280334ENTRYPOINT ["/agent-server/.venv/bin/python" , "-m" , "openhands.agent_server" ]
281335
282336# ###########################
0 commit comments