diff --git a/openhands/runtime/builder/docker.py b/openhands/runtime/builder/docker.py index d599673698..c44ec684fe 100644 --- a/openhands/runtime/builder/docker.py +++ b/openhands/runtime/builder/docker.py @@ -37,7 +37,7 @@ class DockerRuntimeBuilder(RuntimeBuilder): @staticmethod def check_buildx(is_podman: bool = False) -> bool: - """Check if Docker Buildx is available""" + """Check if Docker Buildx is available.""" try: result = subprocess.run( ['docker' if not is_podman else 'podman', 'buildx', 'version'], @@ -176,29 +176,32 @@ class DockerRuntimeBuilder(RuntimeBuilder): bufsize=1, ) + output_lines = [] if process.stdout: for line in iter(process.stdout.readline, ''): line = line.strip() if line: + output_lines.append(line) # Store all output lines self._output_logs(line) return_code = process.wait() if return_code != 0: + # Use the collected output for error reporting + output_str = '\n'.join(output_lines) raise subprocess.CalledProcessError( return_code, process.args, - output=process.stdout.read() if process.stdout else None, - stderr=process.stderr.read() if process.stderr else None, + output=output_str, # Use the collected output + stderr=None, ) except subprocess.CalledProcessError as e: - logger.error(f'Image build failed:\n{e}') # TODO: {e} is empty - logger.error(f'Command output:\n{e.output}') - if self.rolling_logger.is_enabled(): - logger.error( - 'Docker build output:\n' + self.rolling_logger.all_lines - ) # Show the error + logger.error(f'Image build failed with exit code {e.returncode}') + if e.output: + logger.error(f'Command output:\n{e.output}') + elif self.rolling_logger.is_enabled() and self.rolling_logger.all_lines: + logger.error(f'Docker build output:\n{self.rolling_logger.all_lines}') raise except subprocess.TimeoutExpired: diff --git a/openhands/runtime/utils/runtime_templates/Dockerfile.j2 b/openhands/runtime/utils/runtime_templates/Dockerfile.j2 index 2a4c7efa9f..ecc99d792f 100644 --- a/openhands/runtime/utils/runtime_templates/Dockerfile.j2 +++ b/openhands/runtime/utils/runtime_templates/Dockerfile.j2 @@ -1,5 +1,7 @@ FROM {{ base_image }} +SHELL ["/bin/bash", "-c"] + # Shared environment variables ENV POETRY_VIRTUALENVS_PATH=/openhands/poetry \ MAMBA_ROOT_PREFIX=/openhands/micromamba \ @@ -94,13 +96,8 @@ RUN \ install -m 0755 -d /etc/apt/keyrings && \ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \ chmod a+r /etc/apt/keyrings/docker.asc && \ - # Add the repository to Apt sources - # For Debian, if it's noble (testing/unstable), use bookworm (stable) repository - if [ "$(lsb_release -cs)" = "noble" ]; then \ - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null; \ - else \ - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null; \ - fi; \ + # Add the repository to Apt sources (default to bookworm for stability) + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null; \ fi && \ # Install Docker Engine, containerd, and Docker Compose apt-get update && \