feat: switch default base image to nikolaik slim variant

Switch the default base container image from nikolaik/python-nodejs:python3.12-nodejs22
to nikolaik/python-nodejs:python3.12-nodejs22-slim.

Benefits:
- ~500 MB smaller image size on disk (16% reduction)
- ~62% smaller compressed size for faster downloads
- Faster Kubernetes node autoscaling due to reduced pull times
- Full functional parity with the non-slim variant

The slim variant is based on Debian slim, which removes non-essential
packages while maintaining all functionality needed for OpenHands runtime.

Files updated:
- openhands/core/config/sandbox_config.py: Default base image
- openhands/runtime/utils/runtime_build.py: CLI default
- .github/workflows/ghcr-build.yml: CI/CD builds
- config.template.toml: Documentation
- tests/*: Test assertions
This commit is contained in:
openhands
2026-03-05 20:05:42 +00:00
parent 59b369047f
commit 4aa021a511
7 changed files with 11 additions and 11 deletions

View File

@@ -40,11 +40,11 @@ jobs:
run: |
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
json=$(jq -n -c '[
{ image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik" }
{ image: "nikolaik/python-nodejs:python3.12-nodejs22-slim", tag: "nikolaik" }
]')
else
json=$(jq -n -c '[
{ image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik" },
{ image: "nikolaik/python-nodejs:python3.12-nodejs22-slim", tag: "nikolaik" },
{ image: "ubuntu:24.04", tag: "ubuntu" }
]')
fi

View File

@@ -296,7 +296,7 @@ classpath = "my_package.my_module.MyCustomAgent"
#user_id = 1000
# Container image to use for the sandbox
#base_container_image = "nikolaik/python-nodejs:python3.12-nodejs22"
#base_container_image = "nikolaik/python-nodejs:python3.12-nodejs22-slim"
# Use host network
#use_host_network = false

View File

@@ -60,7 +60,7 @@ class SandboxConfig(BaseModel):
rm_all_containers: bool = Field(default=False)
api_key: str | None = Field(default=None)
base_container_image: str | None = Field(
default='nikolaik/python-nodejs:python3.12-nodejs22'
default='nikolaik/python-nodejs:python3.12-nodejs22-slim'
)
runtime_container_image: str | None = Field(default=None)
user_id: int = Field(default=os.getuid() if hasattr(os, 'getuid') else 1000)
@@ -126,5 +126,5 @@ class SandboxConfig(BaseModel):
@model_validator(mode='after')
def set_default_base_image(self) -> 'SandboxConfig':
if self.base_container_image is None:
self.base_container_image = 'nikolaik/python-nodejs:python3.12-nodejs22'
self.base_container_image = 'nikolaik/python-nodejs:python3.12-nodejs22-slim'
return self

View File

@@ -403,7 +403,7 @@ def _build_sandbox_image(
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--base_image', type=str, default='nikolaik/python-nodejs:python3.12-nodejs22'
'--base_image', type=str, default='nikolaik/python-nodejs:python3.12-nodejs22-slim'
)
parser.add_argument('--build_folder', type=str, default=None)
parser.add_argument('--force_rebuild', action='store_true', default=False)

View File

@@ -195,7 +195,7 @@ def base_container_image(request):
request.param = None
if request.param is None:
request.param = pytest.param(
'nikolaik/python-nodejs:python3.12-nodejs22',
'nikolaik/python-nodejs:python3.12-nodejs22-slim',
'golang:1.23-bookworm',
)
print(f'Container image: {request.param}')

View File

@@ -432,7 +432,7 @@ def test_defaults_dict_after_updates(default_config):
assert defaults_after_updates['sandbox']['timeout']['default'] == 120
assert (
defaults_after_updates['sandbox']['base_container_image']['default']
== 'nikolaik/python-nodejs:python3.12-nodejs22'
== 'nikolaik/python-nodejs:python3.12-nodejs22-slim'
)
assert defaults_after_updates == initial_defaults

View File

@@ -28,7 +28,7 @@ from openhands.runtime.utils.runtime_build import (
)
OH_VERSION = f'oh_v{oh_version}'
DEFAULT_BASE_IMAGE = 'nikolaik/python-nodejs:python3.12-nodejs22'
DEFAULT_BASE_IMAGE = 'nikolaik/python-nodejs:python3.12-nodejs22-slim'
@pytest.fixture
@@ -266,7 +266,7 @@ def test_get_runtime_image_repo_and_tag_eventstream():
assert (
img_repo == f'{get_runtime_image_repo()}'
and img_tag
== f'{OH_VERSION}_image_nikolaik_s_python-nodejs_tag_python3.12-nodejs22'
== f'{OH_VERSION}_image_nikolaik_s_python-nodejs_tag_python3.12-nodejs22-slim'
)
base_image = 'ubuntu'
@@ -299,7 +299,7 @@ def test_generate_dockerfile_channel_alias_not_in_non_scratch(monkeypatch):
assert (
img_repo == f'{get_runtime_image_repo()}'
and img_tag
== f'{OH_VERSION}_image_nikolaik_s_python-nodejs_tag_python3.12-nodejs22'
== f'{OH_VERSION}_image_nikolaik_s_python-nodejs_tag_python3.12-nodejs22-slim'
)
base_image = 'ubuntu'