File size: 4,443 Bytes
bbdb7f0
 
 
a49e5c3
bbdb7f0
 
 
 
 
 
 
 
 
 
a49e5c3
bbdb7f0
 
a49e5c3
bbdb7f0
a49e5c3
 
bbdb7f0
 
a49e5c3
 
 
bbdb7f0
a49e5c3
 
 
 
 
bbdb7f0
 
 
 
 
 
 
 
a49e5c3
bbdb7f0
 
 
 
 
a49e5c3
 
bbdb7f0
 
 
 
 
a49e5c3
 
 
bbdb7f0
a49e5c3
bbdb7f0
 
a49e5c3
 
 
 
 
 
 
 
bbdb7f0
 
 
 
a49e5c3
 
 
 
bbdb7f0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a49e5c3
bbdb7f0
 
a49e5c3
bbdb7f0
 
a49e5c3
bbdb7f0
 
a49e5c3
bbdb7f0
 
a49e5c3
bbdb7f0
 
 
a49e5c3
bbdb7f0
a49e5c3
 
bbdb7f0
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# ===== MULTI-STAGE DOCKERFILE FOR OPENHANDS WEBAPP =====
# This Dockerfile builds and runs the complete OpenHands application
# including both the React frontend and Python FastAPI backend

# ===== FRONTEND BUILD STAGE =====
FROM node:22.13.1-bookworm-slim AS frontend-builder

WORKDIR /app/frontend

# Copy package files first for better layer caching
COPY frontend/package.json frontend/package-lock.json ./

# Install frontend dependencies
RUN npm ci --only=production

# Copy frontend source code
COPY frontend/ ./

# Build the React application
RUN npm run build

# ===== BACKEND BUILD STAGE =====
FROM python:3.12.8-slim AS backend-builder

WORKDIR /app

# Set Poetry environment variables
ENV POETRY_NO_INTERACTION=1 \
    POETRY_VIRTUALENVS_IN_PROJECT=1 \
    POETRY_VIRTUALENVS_CREATE=1 \
    POETRY_CACHE_DIR=/tmp/poetry_cache

# Install system dependencies for building Python packages
RUN apt-get update -y \
    && apt-get install -y --no-install-recommends \
        curl \
        make \
        git \
        build-essential \
    && rm -rf /var/lib/apt/lists/*

# Install Poetry
RUN python3 -m pip install poetry==1.8.2 --break-system-packages

# Copy Python dependency files first for better layer caching
COPY pyproject.toml poetry.lock ./
RUN touch README.md

# Install Python dependencies
RUN poetry install --no-root --no-dev && rm -rf $POETRY_CACHE_DIR

# ===== FINAL RUNTIME STAGE =====
FROM python:3.12.8-slim AS runtime

WORKDIR /app

# Build arguments
ARG OPENHANDS_BUILD_VERSION=dev

# Environment variables for OpenHands
ENV RUN_AS_OPENHANDS=true \
    OPENHANDS_USER_ID=42420 \
    SANDBOX_LOCAL_RUNTIME_URL=http://host.docker.internal \
    USE_HOST_NETWORK=false \
    WORKSPACE_BASE=/opt/workspace_base \
    OPENHANDS_BUILD_VERSION=$OPENHANDS_BUILD_VERSION \
    SANDBOX_USER_ID=0 \
    FILE_STORE=local \
    FILE_STORE_PATH=/.openhands-state \
    PYTHONPATH='/app' \
    VIRTUAL_ENV=/app/.venv \
    PATH="/app/.venv/bin:$PATH"

# Create necessary directories
RUN mkdir -p $FILE_STORE_PATH $WORKSPACE_BASE

# Install runtime system dependencies
RUN apt-get update -y \
    && apt-get install -y --no-install-recommends \
        curl \
        ssh \
        sudo \
        git \
    && rm -rf /var/lib/apt/lists/*

# Configure user management for different UID ranges
RUN sed -i 's/^UID_MIN.*/UID_MIN 499/' /etc/login.defs \
    && sed -i 's/^UID_MAX.*/UID_MAX 1000000/' /etc/login.defs

# Create app group and openhands user
RUN groupadd app \
    && useradd -l -m -u $OPENHANDS_USER_ID -s /bin/bash openhands \
    && usermod -aG app openhands \
    && usermod -aG sudo openhands \
    && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

# Set ownership and permissions
RUN chown -R openhands:app /app && chmod -R 770 /app \
    && chown -R openhands:app $WORKSPACE_BASE && chmod -R 770 $WORKSPACE_BASE

# Switch to openhands user for application setup
USER openhands

# Copy Python virtual environment from builder stage
COPY --chown=openhands:app --chmod=770 --from=backend-builder /app/.venv /app/.venv

# Copy Python application code
COPY --chown=openhands:app --chmod=770 ./microagents ./microagents
COPY --chown=openhands:app --chmod=770 ./openhands ./openhands
COPY --chown=openhands:app --chmod=777 ./openhands/runtime/plugins ./openhands/runtime/plugins
COPY --chown=openhands:app --chmod=770 ./openhands/agenthub ./openhands/agenthub

# Copy configuration and metadata files
COPY --chown=openhands:app ./pyproject.toml ./poetry.lock ./README.md ./MANIFEST.in ./LICENSE ./

# Download assets (run as openhands user to set correct ownership)
RUN python openhands/core/download.py

# Copy built frontend from frontend-builder stage
COPY --chown=openhands:app --chmod=770 --from=frontend-builder /app/frontend/build ./frontend/build

# Copy entrypoint script
COPY --chown=openhands:app --chmod=770 ./containers/app/entrypoint.sh /app/entrypoint.sh

# Ensure all files are in the app group
RUN find /app \! -group app -exec chgrp app {} + 2>/dev/null || true

# Switch back to root for entrypoint execution
USER root

# Health check to ensure the application is running
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:3000/ || exit 1

# Expose the application port
EXPOSE 3000

# Set entrypoint and default command
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["uvicorn", "openhands.server.listen:app", "--host", "0.0.0.0", "--port", "3000"]