From 7a4ea23b9d87ecb6351550fcf1c7c1436c88e33a Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Thu, 15 May 2025 10:29:15 -0400 Subject: [PATCH] Revert "Add Docker, Java, Golang, and other programming languages to runtime image" (#8518) --- .github/workflows/ghcr-build.yml | 15 ++-- openhands/runtime/utils/runtime_build.py | 30 +------- .../utils/runtime_templates/Dockerfile.j2 | 68 +------------------ tests/unit/test_runtime_build.py | 12 +--- 4 files changed, 12 insertions(+), 113 deletions(-) diff --git a/.github/workflows/ghcr-build.yml b/.github/workflows/ghcr-build.yml index 55a2842957..eb3d15494a 100644 --- a/.github/workflows/ghcr-build.yml +++ b/.github/workflows/ghcr-build.yml @@ -37,18 +37,17 @@ jobs: shell: bash id: define-base-images run: | - # Only build nikolaik on PRs, otherwise build both nikolaik, nikolaik-full, ubuntu, and ubuntu-full. + # Only build nikolaik on PRs, otherwise build both nikolaik and ubuntu. if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then json=$(jq -n -c '[ - { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik", include_languages: false }, - { image: "ubuntu:24.04", tag: "ubuntu", include_languages: false } + { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik" }, + { image: "ubuntu:24.04", tag: "ubuntu" } + ]') else json=$(jq -n -c '[ - { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik", include_languages: false }, - { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik-full", include_languages: true }, - { image: "ubuntu:24.04", tag: "ubuntu", include_languages: false }, - { image: "ubuntu:24.04", tag: "ubuntu-full", include_languages: true } + { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik" }, + { image: "ubuntu:24.04", tag: "ubuntu" } ]') fi echo "base_image=$json" >> "$GITHUB_OUTPUT" @@ -150,7 +149,7 @@ jobs: - name: Install Python dependencies using Poetry run: make install-python-dependencies POETRY_GROUP=main INSTALL_PLAYWRIGHT=0 - name: Create source distribution and Dockerfile - run: poetry run python3 openhands/runtime/utils/runtime_build.py --base_image ${{ matrix.base_image.image }} --build_folder containers/runtime --force_rebuild ${{ matrix.base_image.include_languages && '--include_programming_languages' || '' }} + run: poetry run python3 openhands/runtime/utils/runtime_build.py --base_image ${{ matrix.base_image.image }} --build_folder containers/runtime --force_rebuild - name: Lowercase Repository Owner run: | echo REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV diff --git a/openhands/runtime/utils/runtime_build.py b/openhands/runtime/utils/runtime_build.py index c37db3808f..0f2b26174d 100644 --- a/openhands/runtime/utils/runtime_build.py +++ b/openhands/runtime/utils/runtime_build.py @@ -32,15 +32,13 @@ def _generate_dockerfile( base_image: str, build_from: BuildFromImageType = BuildFromImageType.SCRATCH, extra_deps: str | None = None, - include_programming_languages: bool = False, ) -> str: """Generate the Dockerfile content for the runtime image based on the base image. Parameters: - base_image (str): The base image provided for the runtime image - build_from (BuildFromImageType): The build method for the runtime image. - - extra_deps (str): Extra dependencies to install - - include_programming_languages (bool): Whether to include programming language dependencies + - extra_deps (str): Returns: - str: The resulting Dockerfile content @@ -57,7 +55,6 @@ def _generate_dockerfile( build_from_scratch=build_from == BuildFromImageType.SCRATCH, build_from_versioned=build_from == BuildFromImageType.VERSIONED, extra_deps=extra_deps if extra_deps is not None else '', - include_programming_languages=include_programming_languages, ) return dockerfile_content @@ -114,7 +111,6 @@ def build_runtime_image( dry_run: bool = False, force_rebuild: bool = False, extra_build_args: list[str] | None = None, - include_programming_languages: bool = False, ) -> str: """Prepares the final docker build folder. @@ -124,12 +120,11 @@ def build_runtime_image( - base_image (str): The name of the base Docker image to use - runtime_builder (RuntimeBuilder): The runtime builder to use - platform (str): The target platform for the build (e.g. linux/amd64, linux/arm64) - - extra_deps (str): Extra dependencies to install + - extra_deps (str): - build_folder (str): The directory to use for the build. If not provided a temporary directory will be used - dry_run (bool): if True, it will only ready the build folder. It will not actually build the Docker image - force_rebuild (bool): if True, it will create the Dockerfile which uses the base_image - extra_build_args (List[str]): Additional build arguments to pass to the builder - - include_programming_languages (bool): Whether to include programming language dependencies Returns: - str: :. Where MD5 hash is the hash of the docker build folder @@ -147,7 +142,6 @@ def build_runtime_image( force_rebuild=force_rebuild, platform=platform, extra_build_args=extra_build_args, - include_programming_languages=include_programming_languages, ) return result @@ -160,7 +154,6 @@ def build_runtime_image( force_rebuild=force_rebuild, platform=platform, extra_build_args=extra_build_args, - include_programming_languages=include_programming_languages, ) return result @@ -174,7 +167,6 @@ def build_runtime_image_in_folder( force_rebuild: bool, platform: str | None = None, extra_build_args: list[str] | None = None, - include_programming_languages: bool = False, ) -> str: runtime_image_repo, _ = get_runtime_image_repo_and_tag(base_image) lock_tag = f'oh_v{oh_version}_{get_hash_for_lock_files(base_image)}' @@ -196,7 +188,6 @@ def build_runtime_image_in_folder( base_image, build_from=BuildFromImageType.SCRATCH, extra_deps=extra_deps, - include_programming_languages=include_programming_languages, ) if not dry_run: _build_sandbox_image( @@ -235,13 +226,7 @@ def build_runtime_image_in_folder( else: logger.debug(f'Build [{hash_image_name}] from scratch') - prep_build_folder( - build_folder, - base_image, - build_from, - extra_deps, - include_programming_languages=include_programming_languages, - ) + prep_build_folder(build_folder, base_image, build_from, extra_deps) if not dry_run: _build_sandbox_image( build_folder, @@ -266,7 +251,6 @@ def prep_build_folder( base_image: str, build_from: BuildFromImageType, extra_deps: str | None, - include_programming_languages: bool = False, ) -> None: # Copy the source code to directory. It will end up in build_folder/code # If package is not found, build from source code @@ -298,7 +282,6 @@ def prep_build_folder( base_image, build_from=build_from, extra_deps=extra_deps, - include_programming_languages=include_programming_languages, ) dockerfile_path = Path(build_folder, 'Dockerfile') with open(str(dockerfile_path), 'w') as f: @@ -395,12 +378,6 @@ if __name__ == '__main__': parser.add_argument('--build_folder', type=str, default=None) parser.add_argument('--force_rebuild', action='store_true', default=False) parser.add_argument('--platform', type=str, default=None) - parser.add_argument( - '--include_programming_languages', - action='store_true', - default=False, - help='Include programming language dependencies (Java, Go, PHP, Ruby)', - ) args = parser.parse_args() if args.build_folder is not None: @@ -432,7 +409,6 @@ if __name__ == '__main__': dry_run=True, force_rebuild=args.force_rebuild, platform=args.platform, - include_programming_languages=args.include_programming_languages, ) _runtime_image_repo, runtime_image_source_tag = ( diff --git a/openhands/runtime/utils/runtime_templates/Dockerfile.j2 b/openhands/runtime/utils/runtime_templates/Dockerfile.j2 index c6ff746bdc..d192c180ab 100644 --- a/openhands/runtime/utils/runtime_templates/Dockerfile.j2 +++ b/openhands/runtime/utils/runtime_templates/Dockerfile.j2 @@ -10,13 +10,6 @@ ENV POETRY_VIRTUALENVS_PATH=/openhands/poetry \ GIT_EDITOR="code --wait" \ OPENVSCODE_SERVER_ROOT=/openhands/.openvscode-server -{% if include_programming_languages %} -ENV GOPATH=/go \ - GOROOT=/usr/local/go \ - PATH="/usr/local/go/bin:/go/bin:/root/.cargo/bin:${PATH}" \ - JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 -{% endif %} - {% macro setup_base_system() %} # Install base system dependencies @@ -34,53 +27,10 @@ RUN apt-get update && \ TZ=Etc/UTC DEBIAN_FRONTEND=noninteractive \ apt-get install -y --no-install-recommends nodejs python3.12 python-is-python3 python3-pip python3.12-venv && \ corepack enable yarn && \ - {% endif %} + {% endif -%} apt-get clean && \ rm -rf /var/lib/apt/lists/* -# Install Docker -RUN apt-get update && \ - apt-get install -y apt-transport-https ca-certificates gnupg lsb-release && \ - if grep -q "Debian" /etc/os-release; then \ - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null; \ - else \ - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null; \ - fi && \ - apt-get update && \ - apt-get install -y docker-ce docker-ce-cli containerd.io && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -{% if include_programming_languages %} -# Install Java -RUN apt-get update && \ - apt-get install -y openjdk-17-jdk maven gradle && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install Golang -RUN curl -OL https://golang.org/dl/go1.21.0.linux-amd64.tar.gz && \ - tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz && \ - rm go1.21.0.linux-amd64.tar.gz && \ - echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/profile && \ - echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/bash.bashrc - -# Install PHP -RUN apt-get update && \ - apt-get install -y php && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install Ruby -RUN apt-get update && \ - apt-get install -y ruby-full ruby-bundler && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* -{% endif %} - - {% if 'ubuntu' in base_image %} RUN ln -s "$(dirname $(which node))/corepack" /usr/local/bin/corepack && \ npm install -g corepack && corepack enable yarn && \ @@ -102,11 +52,6 @@ RUN mkdir -p /openhands && \ mkdir -p /openhands/logs && \ mkdir -p /openhands/poetry -{% if include_programming_languages %} -RUN mkdir -p /go && \ - chmod -R 777 /go -{% endif %} - {% endmacro %} {% macro setup_vscode_server() %} @@ -166,19 +111,8 @@ RUN /openhands/micromamba/bin/micromamba config set changeps1 False && \ /openhands/micromamba/bin/micromamba run -n openhands poetry env use python3.12 # Install project dependencies in smaller chunks -# Ensure we have all necessary build dependencies for pydantic-core -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - gcc \ - g++ \ - python3-dev \ - && apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install main dependencies first RUN /openhands/micromamba/bin/micromamba run -n openhands poetry install --only main --no-interaction --no-root -# Then install runtime dependencies RUN /openhands/micromamba/bin/micromamba run -n openhands poetry install --only runtime --no-interaction --no-root # Install playwright and its dependencies diff --git a/tests/unit/test_runtime_build.py b/tests/unit/test_runtime_build.py index 5c63044dae..ae04f499e3 100644 --- a/tests/unit/test_runtime_build.py +++ b/tests/unit/test_runtime_build.py @@ -87,7 +87,6 @@ def test_prep_build_folder(temp_dir): base_image=DEFAULT_BASE_IMAGE, build_from=BuildFromImageType.SCRATCH, extra_deps=None, - include_programming_languages=False, ) # make sure that the code was copied @@ -134,7 +133,6 @@ def test_generate_dockerfile_build_from_scratch(): dockerfile_content = _generate_dockerfile( base_image, build_from=BuildFromImageType.SCRATCH, - include_programming_languages=False, ) assert base_image in dockerfile_content assert 'apt-get update' in dockerfile_content @@ -155,7 +153,6 @@ def test_generate_dockerfile_build_from_lock(): dockerfile_content = _generate_dockerfile( base_image, build_from=BuildFromImageType.LOCK, - include_programming_languages=False, ) # These commands SHOULD NOT include in the dockerfile if build_from_scratch is False @@ -174,7 +171,6 @@ def test_generate_dockerfile_build_from_versioned(): dockerfile_content = _generate_dockerfile( base_image, build_from=BuildFromImageType.VERSIONED, - include_programming_languages=False, ) # these commands should not exist when build from versioned @@ -251,11 +247,7 @@ def test_build_runtime_image_from_scratch(): == f'{get_runtime_image_repo()}:{OH_VERSION}_mock-lock-tag_mock-source-tag' ) mock_prep_build_folder.assert_called_once_with( - ANY, - base_image, - BuildFromImageType.SCRATCH, - None, - include_programming_languages=False, + ANY, base_image, BuildFromImageType.SCRATCH, None ) @@ -350,7 +342,6 @@ def test_build_runtime_image_exact_hash_not_exist_and_lock_exist(): f'{get_runtime_image_repo()}:{OH_VERSION}_mock-lock-tag', BuildFromImageType.LOCK, None, - include_programming_languages=False, ) @@ -410,7 +401,6 @@ def test_build_runtime_image_exact_hash_not_exist_and_lock_not_exist_and_version f'{get_runtime_image_repo()}:{OH_VERSION}_mock-versioned-tag', BuildFromImageType.VERSIONED, None, - include_programming_languages=False, )