From 2aa7f8d8d3e924794f83c43d1f5a6817251e2d1f Mon Sep 17 00:00:00 2001 From: Dmitry Meyer Date: Wed, 21 Oct 2026 08:11:48 +0000 Subject: [PATCH] Bump base Docker image to 0.16 A prerequisite for Python 3.15 support --- .../server/services/jobs/configurators/base.py | 12 +++++++++++- src/dstack/version.py | 2 +- src/tests/_internal/server/routers/test_runs.py | 12 ++++++++---- .../server/services/jobs/configurators/test_task.py | 4 +++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/dstack/_internal/server/services/jobs/configurators/base.py b/src/dstack/_internal/server/services/jobs/configurators/base.py index 9b50b67b3e..4259619151 100644 --- a/src/dstack/_internal/server/services/jobs/configurators/base.py +++ b/src/dstack/_internal/server/services/jobs/configurators/base.py @@ -73,6 +73,9 @@ DSTACK_DIR = "/dstack" DSTACK_PROFILE_PATH = f"{DSTACK_DIR}/profile" +# A directory with preinstalled Python builds in dstackai/base image +UV_PYTHON_INSTALL_DIR = "/opt/uv/python" + # A non-existent image name used to signal that the image registry must never be requested # and some dummy defaults should be used instead. # As a job with such an image cannot be started, this special value only makes sense @@ -290,6 +293,7 @@ def _dstack_image_commands(self) -> List[str]: or self.run_spec.configuration.entrypoint is not None ): return [] + python = self._python() return [ f"eval $(echo 'export DSTACK_VENV_DIR={DSTACK_DIR}/venv' | sudo tee -a {DSTACK_PROFILE_PATH})", # Make sure /dstack/venv is owned by the current user. @@ -310,7 +314,13 @@ def _dstack_image_commands(self) -> List[str]: # used for legacy `pip`-based configurations). `--no-active` suppresses the warning. # Alternatively, the user can call `deactivate` once before using `uv`. # If the user really wants to reuse dstack's venv, they must spefify `--active`. - f"uv venv -q --prompt dstack -p {self._python()} --seed $DSTACK_VENV_DIR", + # Use the preinstalled Python build if available, otherwise let `uv` download it. + # The subshell keeps the `UV_*` variables out of the user's commands. + ( + f"(if UV_PYTHON_INSTALL_DIR={UV_PYTHON_INSTALL_DIR} uv python find {python} > /dev/null 2>&1;" + f" then export UV_PYTHON_INSTALL_DIR={UV_PYTHON_INSTALL_DIR} UV_PYTHON_DOWNLOADS=never; fi;" + f" uv venv -q --prompt dstack -p {python} --seed $DSTACK_VENV_DIR)" + ), f"eval $(echo '. $DSTACK_VENV_DIR/bin/activate' | sudo tee -a {DSTACK_PROFILE_PATH})", ] diff --git a/src/dstack/version.py b/src/dstack/version.py index 2aabb7debd..eccb44466a 100644 --- a/src/dstack/version.py +++ b/src/dstack/version.py @@ -5,6 +5,6 @@ __version__ = "0.0.0" __is_release__ = False -docker_base_image = "0.15" +docker_base_image = "0.16" docker_base_image_ubuntu_version = "24.04" vm_base_image = "0.14" diff --git a/src/tests/_internal/server/routers/test_runs.py b/src/tests/_internal/server/routers/test_runs.py index 6bfdb4cd85..d88c802373 100644 --- a/src/tests/_internal/server/routers/test_runs.py +++ b/src/tests/_internal/server/routers/test_runs.py @@ -162,7 +162,9 @@ def get_dev_env_run_plan_dict( " && sudo rm -rf $DSTACK_VENV_DIR" " && sudo mkdir $DSTACK_VENV_DIR" " && sudo chown $(id -u):$(id -g) $DSTACK_VENV_DIR" - " && uv venv -q --prompt dstack -p 3.13 --seed $DSTACK_VENV_DIR" + " && (if UV_PYTHON_INSTALL_DIR=/opt/uv/python uv python find 3.13 > /dev/null 2>&1;" + " then export UV_PYTHON_INSTALL_DIR=/opt/uv/python UV_PYTHON_DOWNLOADS=never; fi;" + " uv venv -q --prompt dstack -p 3.13 --seed $DSTACK_VENV_DIR)" " && eval $(echo '. $DSTACK_VENV_DIR/bin/activate' | sudo tee -a /dstack/profile)" " && (echo 'uv pip install ipykernel...'" " && uv pip install -q --no-cache-dir ipykernel 2> /dev/null)" @@ -180,7 +182,7 @@ def get_dev_env_run_plan_dict( " && tail -f /dev/null" ), ] - image_name = "dstackai/base:0.15-base-ubuntu24.04" + image_name = "dstackai/base:0.16-base-ubuntu24.04" run_spec = { "configuration": { @@ -409,7 +411,9 @@ def get_dev_env_run_dict( " && sudo rm -rf $DSTACK_VENV_DIR" " && sudo mkdir $DSTACK_VENV_DIR" " && sudo chown $(id -u):$(id -g) $DSTACK_VENV_DIR" - " && uv venv -q --prompt dstack -p 3.13 --seed $DSTACK_VENV_DIR" + " && (if UV_PYTHON_INSTALL_DIR=/opt/uv/python uv python find 3.13 > /dev/null 2>&1;" + " then export UV_PYTHON_INSTALL_DIR=/opt/uv/python UV_PYTHON_DOWNLOADS=never; fi;" + " uv venv -q --prompt dstack -p 3.13 --seed $DSTACK_VENV_DIR)" " && eval $(echo '. $DSTACK_VENV_DIR/bin/activate' | sudo tee -a /dstack/profile)" " && (echo 'uv pip install ipykernel...'" " && uv pip install -q --no-cache-dir ipykernel 2> /dev/null)" @@ -427,7 +431,7 @@ def get_dev_env_run_dict( " && tail -f /dev/null" ), ] - image_name = "dstackai/base:0.15-base-ubuntu24.04" + image_name = "dstackai/base:0.16-base-ubuntu24.04" return { "id": run_id, diff --git a/src/tests/_internal/server/services/jobs/configurators/test_task.py b/src/tests/_internal/server/services/jobs/configurators/test_task.py index 6abb17e6da..74d2d83a7c 100644 --- a/src/tests/_internal/server/services/jobs/configurators/test_task.py +++ b/src/tests/_internal/server/services/jobs/configurators/test_task.py @@ -220,7 +220,9 @@ async def test_with_commands_no_image(self, shell: Optional[str], expected_shell " && sudo rm -rf $DSTACK_VENV_DIR" " && sudo mkdir $DSTACK_VENV_DIR" " && sudo chown $(id -u):$(id -g) $DSTACK_VENV_DIR" - " && uv venv -q --prompt dstack -p 3.12 --seed $DSTACK_VENV_DIR" + " && (if UV_PYTHON_INSTALL_DIR=/opt/uv/python uv python find 3.12 > /dev/null 2>&1;" + " then export UV_PYTHON_INSTALL_DIR=/opt/uv/python UV_PYTHON_DOWNLOADS=never; fi;" + " uv venv -q --prompt dstack -p 3.12 --seed $DSTACK_VENV_DIR)" " && eval $(echo '. $DSTACK_VENV_DIR/bin/activate' | sudo tee -a /dstack/profile)" " && sleep inf" ),