Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Arch] Shrink runtime image size #3051

Merged
merged 13 commits into from
Jul 21, 2024
Merged

[Arch] Shrink runtime image size #3051

merged 13 commits into from
Jul 21, 2024

Conversation

xingyaoww
Copy link
Collaborator

What is the problem that this fixes or functionality that this introduces? Does it fix any open issues?

Previously, the runtime image was too large (~20+G) and caused a lot of headaches for deployment. @tobitege did a great job shrink the size in #3040.


Give a summary of what the PR does, explaining any non-trivial design decisions

This PR moves these sandbox image shrinking commits out of #3040 and tries to fix some existing issues. This will better prepare for an automated CI to build the Runtime image.


Other references

Comment on lines 124 to 127
# THIS blows up the image by 13 GB!!!
# Install (or update) the dependencies
# dockerfile_content += (
# 'RUN cd /opendevin/code && \\\n'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used result from mamba related package?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I actually made a mistake, it's not only 13 GB, but more like 22 GB on top.
The resulting sandbox was ~ 26GB. And most of that happens when mamba is installing and running poetry.
Idk what is happening there, but it ain't good. 😁

@tobitege
Copy link
Collaborator

Some snippet that may help in _generate_dockerfile:

        dockerfile_content += (
            'ENV DEBIAN_FRONTEND=noninteractive '
            'POETRY_NO_INTERACTION=1 '
            'POETRY_VIRTUALENVS_IN_PROJECT=1 '
            'POETRY_VIRTUALENVS_CREATE=1 '
            'POETRY_CACHE_DIR=/tmp/poetry_cache\n'
        )

The above are used in other dockerfiles and they e.g. assure that poetry install --only main actually creates the virtualenv during image build, which fixes the "toml not found" error we chatted about in Slack.
Also, I had mistakenly removed that flag --only main in my attempts and that alone apparently is the reason for the image size going nuts because it just installed way too much unneeded stuff, doh! 😂

@xingyaoww
Copy link
Collaborator Author

@tobitege I think i finally got it working (at least locally). I did not do anything extra, but just remove that line of rm -rf /root/.cache/poetry 🤣

967d225a7fb986928fd2a111490103a9

@tobitege
Copy link
Collaborator

@tobitege I think i finally got it working (at least locally). I did not do anything extra, but just remove that line of rm -rf /root/.cache/poetry 🤣

I'll send Sonnet the bill then lolol
Glad it works (again), my bad 😔

@tobitege
Copy link
Collaborator

tobitege commented Jul 21, 2024

I've experimented a little bit more and updated my PR's sources.
Marked my PR as experimental and draft now, to be safe.

You might take another peek at:
https://github.com/OpenDevin/OpenDevin/blob/d5ba379599421a5b119a9db83730719830dcbde6/opendevin/runtime/utils/runtime_build.py

  • added new method _generate_dockerfile_nodejs
    you can try that locally with this command line after you pulled the image from the Docker hub manually (I haven't coded that in):
    poetry run python ./opendevin/runtime/utils/runtime_build.py --base_image "nikolaik/python-nodejs:python3.11-nodejs21"
    That image has Python 3.11, poetry, pip and NodeJS pre-installed. Final imagesize ~6GB.
  • For it to work, I had to apply a small change to _get_new_image_name before the final return:
        # Check if the base image already has the 'od_runtime' prefix
        if repo.startswith('od_runtime'):
            return f'{repo}:{tag}'

The way the above "nodejs" method is coded is that it doesn't require all the mamba stuff, so commands could just be run via poetry run ..., but I'm aware that mamba is used in several areas, like the Jupyter plugin.

I'll just wanted to share this as "food for thought", even though experimental code. 😀

@xingyaoww xingyaoww marked this pull request as ready for review July 21, 2024 17:23
@tobitege
Copy link
Collaborator

Btw, I think there's one big thing missing in the source copying: the agenthub folder isn't copied into the sandbox for dev updates? 🤔

@xingyaoww
Copy link
Collaborator Author

@tobitege this itself should be ready for review if it is ok with you!

I'm experimenting with a slightly more general/cleaner way of building OpenDevin runtime images (e.g., using Jinja templates), which hopefully can provide a cleaner way to deal with these docker files in Python, and make it easier to extend these dockerfiles to different languages (e.g., nodejs).

The way the above "nodejs" method is coded is that it doesn't require all the mamba stuff

The only previous reason for including mamba is that it can manage multiple versions of Python easily and can work out of the box when the base image does not contain the right Python version (e.g., py3.11), which is not your case for ubuntu+py3.11, though.

I guess if we get the Jinja template working nicely and cleanly, we could just start building every image with ubuntu+py3.11 and get rid of Mamba completely to save space, and using the mamba workflow as a backup plan for "customized sandbox images."

@xingyaoww
Copy link
Collaborator Author

the agenthub folder isn't copied into the sandbox for dev updates?

Yep, because agents suppose to run outside the sandbox, so probably there's little meaning in copying the code.

@tobitege
Copy link
Collaborator

the agenthub folder isn't copied into the sandbox for dev updates?

Yep, because agents suppose to run outside the sandbox, so probably there's little meaning in copying the code.

Hmm... are you sure? 😂 I don't see how the agentskills, ipython calls and browser stuff will work solely outside of the sandbox and only send commands... but it's getting late and I shouldn't get myself confused in the evening. 😁

Copy link
Collaborator

@tobitege tobitege left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not yet quite ready.

@@ -81,14 +81,15 @@ async def ainit(self, env_vars: dict[str, str] | None = None):
# NOTE: You can need set DEBUG=true to update the source code
# inside the container. This is useful when you want to test/debug the
# latest code in the runtime docker container.
update_source_code=config.debug,
update_source_code=self.sandbox_config.update_source_code,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be helpful! 👍

'/opendevin/miniforge3/bin/mamba run -n base poetry install\n'
# for browser (update if needed)
'RUN apt-get update && cd /opendevin/code && /opendevin/miniforge3/bin/mamba run -n base poetry run playwright install --with-deps chromium\n'
'/opendevin/miniforge3/bin/mamba run -n base poetry install --no-interaction --no-root\n'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add --only main here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no pyproject.toml file in the sandbox with this version of the method.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do have pyproject.toml inside the sandbox

9f34b7f3ee93bc2829a2c0366a048943

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm... how did those get there, the "tar" doesn't copy them over, does it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the .tar does copy that over as part of the python source build

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the .tar does copy that over as part of the python source build

Ok, that I must have missed. Can you point me to where exactly that happens or do you mean "make build" here? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIBGL_MESA = 'libgl1'
else:
LIBGL_MESA = 'libgl1-mesa-glx'

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would add this at the top:

        dockerfile_content = (
            'ENV DEBIAN_FRONTEND=noninteractive '
            'POETRY_NO_INTERACTION=1 '
            'POETRY_VIRTUALENVS_IN_PROJECT=1 '
            'POETRY_VIRTUALENVS_CREATE=1 '
            'POETRY_CACHE_DIR=/tmp/poetry_cache\n'
        )

(and "+=" in the below line then)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason why we should add this when not adding it still works? I'm trying to see if we can make things as simple as possible..

Copy link
Collaborator

@tobitege tobitege Jul 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 https://python-poetry.org/docs/configuration/#virtualenvsin-project

If not set explicitly, poetry by default will create a virtual environment under {cache-dir}/virtualenvs or use the {project-dir}/.venv directory if one already exists.

Now i see why the previous runs fails, because after rm -rf /root/.cache/pypoetry the virtual env will be removed.

I don't think we need this for the sandbox, because we will rm -rf /opendevin/code and copy a new version of the codebase there, if we enable POETRY_VIRTUALENVS_IN_PROJECT, it will delete the virtual env with rm -rf /opendevin/code , and we will have to re-install everything from scratch whenever we update the source code..

Copy link
Collaborator Author

@xingyaoww xingyaoww Jul 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And POETRY_VIRTUALENVS_CREATE also default to true, so we probably don't need to set it either. https://python-poetry.org/docs/configuration/#virtualenvscreate

@xingyaoww xingyaoww merged commit ce8a11a into main Jul 21, 2024
2 checks passed
@xingyaoww xingyaoww deleted the xw/shrink-runtime-img-size branch July 21, 2024 18:34
@xingyaoww
Copy link
Collaborator Author

Thanks @tobitege !

@tobitege
Copy link
Collaborator

Thanks @tobitege !

Thanks to you as well, happy to help! 🤗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants