OpenHands
OpenHands copied to clipboard
Create Dockerfile for running OpenDevin end to end
THROW IT INTO A DOCKER CONTAINER!!!!!
we need to
if you all provide me with steps into doing thiis i can make a script to do this
Ideally we'd be able to docker run ghcr.io/opendevin/opendevin -p 3000:3000 and have a fully functional app at localhost:3000.
Some considerations:
- we'd need docker-in-docker, since the terminal creates docker containers
- https://hub.docker.com/_/docker
- we'd probably want to run
opendevin/main.pyfor now - eventually we'll want to run server.py and the frontend as well
We could use docker-compose up -d to bring up everything, frontend---port 3001 and backend---port 3000. I tried some, the backend container is fat, few G. I don't know if docker-in-docker is restricted required, sandbox? Can we make it outside container?
Can I take this as my task as it says good first issue?
🎉 go for it!
Draft PR here: https://github.com/OpenDevin/OpenDevin/pull/377
I've been working on this in parrallel. I got it working end-to-end with docker with a lot of learnings. There are still some bugs to work out, but it runs and outputs. I committed only additions to https://github.com/kjenney/OpenDevin.
The DinD sandbox mount is not working.
Please check, https://opendevin.slack.com/archives/C06QQ7DSYTD/p1711944261527419 and https://github.com/OpenDevin/OpenDevin/pull/479
Are you folks making backend and frontend separate containers? or jamming them into 1 container?
For what it is worth, I managed to get everything working inside a Docker container. Here is my Dockerfile. To get around the Docker-in-Docker, I chose to have my Docker daemon exposed on TCP port 2375 (on ip 192.168.1.2), that could probably be a build arg. I'm not entirely sure why all the Cuda stuff was necessary... The resulting image is huge but it works.
Oh, and I have a slightly unusual setup, I'm running this on a server with other apps, so I use the www-data user (UID 33) to make sure all mounted volumes have the same permissions. A minor detail, its easy enough to change, but thats why you will see www-data things in the Dockerfile.
FROM python:3.11-bookworm
# Install Cuda
RUN apt update && \
apt install -y --no-install-recommends software-properties-common && \
add-apt-repository contrib -y && \
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb && \
dpkg -i cuda-keyring_1.0-1_all.deb && \
apt-get update && \
apt-get -y --no-install-recommends install cuda-12-1 libcudnn8 libnccl2 && \
apt clean
# Install Docker
# https://docs.docker.com/engine/install/debian/
RUN apt-get update && \
apt-get install -y --no-install-recommends sudo git netcat-traditional ca-certificates curl && \
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 && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && \
apt-get install -y --no-install-recommends docker-ce-cli=5:24.0.9-1~debian.12~bookworm && \
apt clean && \
groupadd -g 1101 docker && \
usermod -aG docker www-data
# Use external Docker daemon
ENV DOCKER_HOST=192.168.1.2:2375
# Allow sudo
RUN echo 'www-data ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/www-data
USER www-data
# Install Node
# https://nodejs.org/en/download/package-manager
RUN sudo mkdir -p /var/www && \
sudo chown -R www-data:www-data /var/www && \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash && \
export NVM_DIR="$HOME/.nvm" && \
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \
nvm install 18
# Install OpenDevin
RUN sudo mkdir -p /OpenDevin && \
sudo chown -R www-data:www-data /OpenDevin && \
git clone https://github.com/OpenDevin/OpenDevin /OpenDevin
WORKDIR /OpenDevin
RUN mkdir -p /var/www/.local/bin && \
export PATH=$PATH:/var/www/.local/bin && \
export NVM_DIR="$HOME/.nvm" && \
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && \
echo "Y" | make build
# Predownload files
RUN /var/www/.cache/pypoetry/virtualenvs/opendevin-*/bin/python3 -c 'import agenthub'
# Patch files
RUN sed -i 's@pnpm run start -- --port@pnpm run start --host 0.0.0.0 -- --port@g' Makefile
# Frontend
EXPOSE 3001
# Run both the frontend and backend
COPY entrypoint.sh /
CMD /entrypoint.sh
entrypoint.sh
#!/bin/bash
export PATH=$PATH:/var/www/.local/bin
export NVM_DIR="$HOME/.nvm"
. "$NVM_DIR/nvm.sh"
make run
I already made DinD work. But taking it to update code takes time. Because it has to work for Docker way and original way; and catch up project progress. It may take me a week to do it, then share to you guys.
Are you folks making backend and frontend separate containers? or jamming them into 1 container?
What's your prefer? Logically, they are separated.
Not to take away from @jrruethe 's excellent work, but I feel like this whole OpenDevin in a container could be a lot simpler -
- Is docker on docker absolutely necessary? I can see why sandbox is necessary when OpenDevin is running as a regular OS process. You'll want to protect the host machine from dangerous things the LLM might end up doing, so you stick it in an isolated sandbox. But when OpenDevin itself is running in a container, it would be a lot simpler for it to just write to the filesystem. Sure it could bork the container, but that's no different from borking the sandbox, you just reset and start over. Is there any OpenDevin state worth retaining that I'm overlooking?
Proposal: If sandbox interface is an abstract class, one of its implementations could be a simple filesystem location, and OpenDevin running in a container uses the filesystem implementation.
(The argument against this is that in a multi-session scenario, sessions could affect each other, there isn't sufficient isolation. But multi-session isn't really a thing yet, I'm inclined to cross that bridge when necessary)
- Backand and Frontend run as separate processes. Managing multiple processes in one docker container is possible, but tricky at best.
It's best practice to separate areas of concern by using one service per container. [...] It's ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application.
There are multiple things to manage, starting multiple processes, monitoring and managing their health, collecting and outputting logs from each processes etc.
Proposal: export the react app into a static SPA, and serve it on a fastAPI endpoint. Then the fastAPI is the only process that needs to be started in any situation, but greatly helps to simply running OpenDevin in a container as well.
@rbren I would appreciate your thoughts on this ^^ also, who can I bug about getting into the Slack channel (I already filled the form)
Some agree with you, Sandbox and Backend containers could be one, that's what I commit in https://github.com/OpenDevin/OpenDevin/pull/479, frontend and backend are separated within docker-compose.yml Robert's concern is my commit has different codes between Sandbox and Backend container without sandbox. So I also test DinD, which also worked. Multiple tasks concern is a good point!
Are you doing Docker in docker by mapping the docker socket from host to OpenDevin container?
Hi everyone, I'm one of the authors of E2B and working on integrating it in #727. I wanted to chime in here, especially to the comment from @foragerr.
A lot of the things @foragerr mentioned are exactly on our roadmap. Specifically
There are multiple things to manage, starting multiple processes, monitoring and managing their health, collecting and outputting logs from each processes etc.
Is exactly something we want to make it really easy for developers. The integration I'm working on in the PR is already about half of the size of the original Docker sandbox. You can even have each agent with it's own sandbox if needed and they can communicate together.
I don't want to just shill our solution here but one of the reasons for what we're building is security and specific features that agent needs. You don't need to do hacks like Docker in Docker (which will then introduce a lot of edge cases). That's exactly why we're using Firecracker as the core of our sandboxes. You give OpenDevin root privileges, full access to the filesystem, and ability to start process and it's okay in terms of the security of the machine. Since Firecracker is a VM, we can also run Docker in it.
I think for OpenDevin it's important to focus on the product - OpenDevin itself - and not worry about underlying infrastructure so you can maximize your chance on winning.
I'm very much open to any feedback. I don't want my comment to sound like I ignore all the great work people have done here, definitely want to find common ground for both solutions if possible. I just wanted to offer my perspective after talking to many agent developers in the past year.
A few comments here--hopefully I didn't miss anything.
when OpenDevin itself is running in a container, it would be a lot simpler for it to just write to the filesystem. Sure it could bork the container, but that's no different from borking the sandbox, you just reset and start over.
For an MVP, sure. But eventually we'll want OD to run in a multi-tenant-ish way (think e.g. your company hosting opendevin.acme.com for you and all your coworkers to use). It'd be really easy to compromise that container, see code you're not supposed to, etc.
That said, I'd totally accept this solution for now.
Are you folks making backend and frontend separate containers? or jamming them into 1 container?
I'd love to tell folks to just docker run opendevin -p 3000:3000 and have a fully working instance. Much easier than all the make stuff we're doing right now, or using docker-compose.
But we probably will want Frontend and Backend specific containers as well. Or maybe just backend, since the frontend can be served statically.
Proposal: export the react app into a static SPA, and serve it on a fastAPI endpoint.
Yeah for a built container this would work great. This is exactly how I'd do it for the docker run opendevin solution.
Sounds like you'll want to eventually support multiple deployment modes -
- If you're an OpenDevin developer; do something very close to what's available today, Makefiles, poetry, pnpm etc
- If you're spinning up a multi-tenant production setup, you may get separate backend, frontend images, perhaps externalized vector store, perhaps E2B for sandboxes
- If you're just looking to kick the tires on OpenDevin the simplest/fastest not-prodution-safe way, run this
docker runcommand.
I'm going to focus on creating a proof-of-concept for # 3
Awesome! Yeah I think you nailed it @foragerr
Plan:
- [x] Stage 1 : Create a docker image that combines UI and backend into 1 process, exposes a single port; but still relies on an external docker based sandbox
- [x] Stage 2 : Move sandbox to filesystem inside OpenDevin container; goal is to launch fully self contained OpenDevin with the invocation:
docker run -p 3000:3000 -e LLM_KEY OpenDevin
@chensihai Are you able to share any details about how you're using DinD? I'm having trouble with it on a mac.
I'm tempted to abandon DinD and just go to Stage2 using your command_manager_without_sandbox
@foragerr The goal is no command_manager_without_sandbox but command_manager only. For the process, it's complicated, still work on it. I can't share more until I submit a full function code, sorry for this.
not a problem.
I got DinD working.
( Turns out I was getting thrown by this : https://github.com/OpenDevin/OpenDevin/commit/c34517be2bb7c3aa8f0a5ab6db674e6b0ca8acce I couldn't figure out why my workspace was suddenly called en 🤦 )
Could some try this for me please 👇 👇 :
- Create folder
/tmp/workspace- needs to be exactly that. export LLM_API_KEY=<openai-key>- needs to be OpenAI- Run:
docker run \
-e LLM_API_KEY \
-e WORKSPACE_DIR="/tmp/workspace" \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock \
--rm ghcr.io/foragerr/opendevin-lite:0.1
- There's still an issue with workspace mapping, the agent creates files, but it cant see them, I think they're getting lost in one of the two containers and never make it back to the host.
- I dropped a bunch of dependencies to make the image ~1 G smaller, only OpenAI LLMs may work.
Code here: https://github.com/foragerr/OpenDevin/pull/10/files Beware, There's a couple of messy hacks in there.
I have stage 2 working. A fully self-contained OpenDevin container. Try:
docker run \
-e LLM_API_KEY \
-p 3000:3000 \
-v <some-local-folder>:/app/workspace \
--rm ghcr.io/foragerr/opendevin-lite:latest
Caveat: Experimental, work in progress. Only tested with OpenAI. Probably works with Claude, Gemini. Definitely does not work with Local LLM.
^^ @chensihai @rbren @kjenney Could you try this out please?
This docker run command works however it does produce some warnings and errors:
Thanks for trying it out, the warnings near the top are a known issue, pending an LiteLLm fix.
The JWT one is unexpected though - I'm wondering how to reproduce. I'm not on windows but that shouldn't matter, the app is running in a container. What browser are you using? @mist0706