mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
chore: Add docker files for developing inside container. (#3911)
This commit is contained in:
parent
8a419b5c45
commit
f7ebc1cf1f
@ -97,3 +97,28 @@ Please refer to [this README](./tests/integration/README.md) for details.
|
||||
### 9. Add or update dependency
|
||||
1. Add your dependency in `pyproject.toml` or use `poetry add xxx`
|
||||
2. Update the poetry.lock file via `poetry lock --no-update`
|
||||
|
||||
## Develop inside Docker container
|
||||
|
||||
TL;DR
|
||||
|
||||
```bash
|
||||
make docker-dev
|
||||
```
|
||||
|
||||
See more details [here](./containers/dev/README.md)
|
||||
|
||||
If you are just interested in running `OpenHands` without installing all the required tools on your host.
|
||||
|
||||
```bash
|
||||
make docker-run
|
||||
```
|
||||
|
||||
If you do not have `make` on your host, run:
|
||||
|
||||
```bash
|
||||
cd ./containers/dev
|
||||
./dev.sh
|
||||
```
|
||||
|
||||
You do need [Docker](https://docs.docker.com/engine/install/) installed on your host though.
|
||||
|
||||
36
Makefile
36
Makefile
@ -2,8 +2,9 @@ SHELL=/bin/bash
|
||||
# Makefile for OpenHands project
|
||||
|
||||
# Variables
|
||||
BACKEND_HOST ?= "127.0.0.1"
|
||||
BACKEND_PORT = 3000
|
||||
BACKEND_HOST = "127.0.0.1:$(BACKEND_PORT)"
|
||||
BACKEND_HOST_PORT = "$(BACKEND_HOST):$(BACKEND_PORT)"
|
||||
FRONTEND_PORT = 3001
|
||||
DEFAULT_WORKSPACE_DIR = "./workspace"
|
||||
DEFAULT_MODEL = "gpt-4o"
|
||||
@ -189,12 +190,12 @@ build-frontend:
|
||||
# Start backend
|
||||
start-backend:
|
||||
@echo "$(YELLOW)Starting backend...$(RESET)"
|
||||
@poetry run uvicorn openhands.server.listen:app --port $(BACKEND_PORT) --reload --reload-exclude "workspace/*"
|
||||
@poetry run uvicorn openhands.server.listen:app --host $(BACKEND_HOST) --port $(BACKEND_PORT) --reload --reload-exclude "workspace/*"
|
||||
|
||||
# Start frontend
|
||||
start-frontend:
|
||||
@echo "$(YELLOW)Starting frontend...$(RESET)"
|
||||
@cd frontend && VITE_BACKEND_HOST=$(BACKEND_HOST) VITE_FRONTEND_PORT=$(FRONTEND_PORT) npm run start
|
||||
@cd frontend && VITE_BACKEND_HOST=$(BACKEND_HOST_PORT) VITE_FRONTEND_PORT=$(FRONTEND_PORT) npm run start
|
||||
|
||||
# Common setup for running the app (non-callable)
|
||||
_run_setup:
|
||||
@ -204,7 +205,7 @@ _run_setup:
|
||||
fi
|
||||
@mkdir -p logs
|
||||
@echo "$(YELLOW)Starting backend server...$(RESET)"
|
||||
@poetry run uvicorn openhands.server.listen:app --port $(BACKEND_PORT) &
|
||||
@poetry run uvicorn openhands.server.listen:app --host $(BACKEND_HOST) --port $(BACKEND_PORT) &
|
||||
@echo "$(YELLOW)Waiting for the backend to start...$(RESET)"
|
||||
@until nc -z localhost $(BACKEND_PORT); do sleep 0.1; done
|
||||
@echo "$(GREEN)Backend started successfully.$(RESET)"
|
||||
@ -216,6 +217,20 @@ run:
|
||||
@cd frontend && echo "$(BLUE)Starting frontend with npm...$(RESET)" && npm run start -- --port $(FRONTEND_PORT)
|
||||
@echo "$(GREEN)Application started successfully.$(RESET)"
|
||||
|
||||
# Run the app (in docker)
|
||||
docker-run: WORKSPACE_BASE ?= $(PWD)/workspace
|
||||
docker-run:
|
||||
@if [ -f /.dockerenv ]; then \
|
||||
echo "Running inside a Docker container. Exiting..."; \
|
||||
exit 0; \
|
||||
else \
|
||||
echo "$(YELLOW)Running the app in Docker $(OPTIONS)...$(RESET)"; \
|
||||
export WORKSPACE_BASE=${WORKSPACE_BASE}; \
|
||||
export SANDBOX_USER_ID=$(shell id -u); \
|
||||
export DATE=$(shell date +%Y%m%d%H%M%S); \
|
||||
docker compose up $(OPTIONS); \
|
||||
fi
|
||||
|
||||
# Run the app (WSL mode)
|
||||
run-wsl:
|
||||
@echo "$(YELLOW)Running the app in WSL mode...$(RESET)"
|
||||
@ -280,6 +295,16 @@ setup-config-prompts:
|
||||
fi
|
||||
|
||||
|
||||
# Develop in container
|
||||
docker-dev:
|
||||
@if [ -f /.dockerenv ]; then \
|
||||
echo "Running inside a Docker container. Exiting..."; \
|
||||
exit 0; \
|
||||
else \
|
||||
echo "$(YELLOW)Build and run in Docker $(OPTIONS)...$(RESET)"; \
|
||||
./containers/dev/dev.sh $(OPTIONS); \
|
||||
fi
|
||||
|
||||
# Clean up all caches
|
||||
clean:
|
||||
@echo "$(YELLOW)Cleaning up caches...$(RESET)"
|
||||
@ -298,7 +323,10 @@ help:
|
||||
@echo " $(GREEN)start-frontend$(RESET) - Start the frontend server for the OpenHands project."
|
||||
@echo " $(GREEN)run$(RESET) - Run the OpenHands application, starting both backend and frontend servers."
|
||||
@echo " Backend Log file will be stored in the 'logs' directory."
|
||||
@echo " $(GREEN)docker-dev$(RESET) - Build and run the OpenHands application in Docker."
|
||||
@echo " $(GREEN)docker-run$(RESET) - Run the OpenHands application, starting both backend and frontend servers in Docker."
|
||||
@echo " $(GREEN)help$(RESET) - Display this help message, providing information on available targets."
|
||||
|
||||
# Phony targets
|
||||
.PHONY: build check-dependencies check-python check-npm check-docker check-poetry install-python-dependencies install-frontend-dependencies install-pre-commit-hooks lint start-backend start-frontend run run-wsl setup-config setup-config-prompts help
|
||||
.PHONY: docker-dev docker-run
|
||||
|
||||
22
compose.yml
Normal file
22
compose.yml
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
services:
|
||||
openhands:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./containers/app/Dockerfile
|
||||
image: openhands:latest
|
||||
container_name: openhands-app-${DATE:-}
|
||||
environment:
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.9-nikolaik}
|
||||
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${WORKSPACE_BASE:-$PWD/workspace}:/opt/workspace_base
|
||||
pull_policy: build
|
||||
stdin_open: true
|
||||
tty: true
|
||||
124
containers/dev/Dockerfile
Normal file
124
containers/dev/Dockerfile
Normal file
@ -0,0 +1,124 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
###
|
||||
FROM ubuntu:22.04 AS dind
|
||||
|
||||
# https://docs.docker.com/engine/install/ubuntu/
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ca-certificates \
|
||||
curl \
|
||||
&& install -m 0755 -d /etc/apt/keyrings \
|
||||
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
|
||||
&& chmod a+r /etc/apt/keyrings/docker.asc \
|
||||
&& echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
|
||||
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
docker-ce \
|
||||
docker-ce-cli \
|
||||
containerd.io \
|
||||
docker-buildx-plugin \
|
||||
docker-compose-plugin \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
###
|
||||
FROM dind AS openhands
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
#
|
||||
RUN apt-get update && apt-get install -y \
|
||||
bash \
|
||||
build-essential \
|
||||
curl \
|
||||
git \
|
||||
git-lfs \
|
||||
software-properties-common \
|
||||
make \
|
||||
netcat \
|
||||
sudo \
|
||||
wget \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md
|
||||
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
||||
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
|
||||
&& apt-get update && apt-get -y install \
|
||||
gh \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
# Python 3.11
|
||||
RUN add-apt-repository ppa:deadsnakes/ppa \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y python3.11 python3.11-venv python3.11-dev python3-pip \
|
||||
&& ln -s /usr/bin/python3.11 /usr/bin/python
|
||||
|
||||
# NodeJS >= 18.17.1
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
|
||||
&& apt-get install -y nodejs
|
||||
|
||||
# Poetry >= 1.8
|
||||
RUN curl -fsSL https://install.python-poetry.org | python3.11 - \
|
||||
&& ln -s ~/.local/bin/poetry /usr/local/bin/poetry
|
||||
|
||||
#
|
||||
RUN <<EOF
|
||||
#!/bin/bash
|
||||
printf "#!/bin/bash
|
||||
set +x
|
||||
uname -a
|
||||
docker --version
|
||||
gh --version | head -n 1
|
||||
git --version
|
||||
#
|
||||
python --version
|
||||
echo node `node --version`
|
||||
echo npm `npm --version`
|
||||
poetry --version
|
||||
netcat -h 2>&1 | head -n 1
|
||||
" > /version.sh
|
||||
chmod a+x /version.sh
|
||||
EOF
|
||||
|
||||
###
|
||||
FROM openhands AS dev
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
dnsutils \
|
||||
file \
|
||||
iproute2 \
|
||||
jq \
|
||||
lsof \
|
||||
ripgrep \
|
||||
silversearcher-ag \
|
||||
vim \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& apt-get autoremove -y
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# cache build dependencies
|
||||
RUN \
|
||||
--mount=type=bind,source=./,target=/app/ \
|
||||
<<EOF
|
||||
#!/bin/bash
|
||||
make -s clean
|
||||
make -s check-dependencies
|
||||
make -s install-python-dependencies
|
||||
|
||||
# NOTE
|
||||
# node_modules are .dockerignore-d therefore not mountable
|
||||
# make -s install-frontend-dependencies
|
||||
EOF
|
||||
|
||||
#
|
||||
CMD ["bash"]
|
||||
54
containers/dev/README.md
Normal file
54
containers/dev/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Develop in Docker
|
||||
|
||||
Install [Docker](https://docs.docker.com/engine/install/) on your host machine and run:
|
||||
|
||||
```bash
|
||||
make docker-dev
|
||||
# same as:
|
||||
cd ./containers/dev
|
||||
./dev.sh
|
||||
```
|
||||
|
||||
It could take some time if you are running for the first time as Docker will pull all the tools required for building OpenHands. The next time you run again, it should be instant.
|
||||
|
||||
## Build and run
|
||||
|
||||
If everything goes well, you should be inside a container after Docker finishes building the `openhands:dev` image similar to the following:
|
||||
|
||||
```bash
|
||||
Build and run in Docker ...
|
||||
root@93fc0005fcd2:/app#
|
||||
```
|
||||
|
||||
You may now proceed with the normal [build and run](../../Development.md) workflow as if you were on the host.
|
||||
|
||||
## Make changes
|
||||
|
||||
The source code on the host is mounted as `/app` inside docker. You may edit the files as usual either inside the Docker container or on your host with your favorite IDE/editors.
|
||||
|
||||
The following are also mapped as readonly from your host:
|
||||
|
||||
```yaml
|
||||
# host credentials
|
||||
- $HOME/.git-credentials:/root/.git-credentials:ro
|
||||
- $HOME/.gitconfig:/root/.gitconfig:ro
|
||||
- $HOME/.npmrc:/root/.npmrc:ro
|
||||
```
|
||||
|
||||
## VSCode
|
||||
|
||||
Alternatively, if you use VSCode, you could also [attach to the running container](https://code.visualstudio.com/docs/devcontainers/attach-container).
|
||||
|
||||
See details for [developing in docker](https://code.visualstudio.com/docs/devcontainers/containers) or simply ask `OpenHands` ;-)
|
||||
|
||||
## Rebuild dev image
|
||||
|
||||
You could optionally pass additional options to the build script.
|
||||
|
||||
```bash
|
||||
make docker-dev OPTIONS="--build"
|
||||
# or
|
||||
./containers/dev/dev.sh --build
|
||||
```
|
||||
|
||||
See [docker compose run](https://docs.docker.com/reference/cli/docker/compose/run/) for more options.
|
||||
38
containers/dev/compose.yml
Normal file
38
containers/dev/compose.yml
Normal file
@ -0,0 +1,38 @@
|
||||
#
|
||||
services:
|
||||
dev:
|
||||
privileged: true
|
||||
build:
|
||||
context: ${OPENHANDS_WORKSPACE:-../../}
|
||||
dockerfile: ./containers/dev/Dockerfile
|
||||
image: openhands:dev
|
||||
container_name: openhands-dev
|
||||
environment:
|
||||
- BACKEND_HOST=${BACKEND_HOST:-"0.0.0.0"}
|
||||
- SANDBOX_API_HOSTNAME=host.docker.internal
|
||||
#
|
||||
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.9-nikolaik}
|
||||
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
|
||||
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ${WORKSPACE_BASE:-$PWD/workspace}:/opt/workspace_base
|
||||
# source code
|
||||
- ${OPENHANDS_WORKSPACE:-../../}:/app
|
||||
# host credentials
|
||||
- $HOME/.git-credentials:/root/.git-credentials:ro
|
||||
- $HOME/.gitconfig:/root/.gitconfig:ro
|
||||
- $HOME/.npmrc:/root/.npmrc:ro
|
||||
# cache
|
||||
- cache-data:/root/.cache
|
||||
pull_policy: never
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
||||
##
|
||||
volumes:
|
||||
cache-data:
|
||||
39
containers/dev/dev.sh
Executable file
39
containers/dev/dev.sh
Executable file
@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
set -o pipefail
|
||||
|
||||
function get_docker() {
|
||||
echo "Docker is required to build and run OpenHands."
|
||||
echo "https://docs.docker.com/get-started/get-docker/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function check_tools() {
|
||||
command -v docker &>/dev/null || get_docker
|
||||
}
|
||||
|
||||
function exit_if_indocker() {
|
||||
if [ -f /.dockerenv ]; then
|
||||
echo "Running inside a Docker container. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
exit_if_indocker
|
||||
|
||||
check_tools
|
||||
|
||||
##
|
||||
OPENHANDS_WORKSPACE=$(git rev-parse --show-toplevel)
|
||||
|
||||
cd "$OPENHANDS_WORKSPACE/containers/dev/" || exit 1
|
||||
|
||||
##
|
||||
export BACKEND_HOST="0.0.0.0"
|
||||
#
|
||||
export SANDBOX_USER_ID=$(id -u)
|
||||
export WORKSPACE_BASE=${WORKSPACE_BASE:-$OPENHANDS_WORKSPACE/workspace}
|
||||
|
||||
docker compose run --rm --service-ports "$@" dev
|
||||
|
||||
##
|
||||
Loading…
x
Reference in New Issue
Block a user