Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Overview

Kernel provides containerized, ready-to-use Chrome browser environments for agentic workflows that need to access the Internet. `containers/docker/Dockerfile` is the core technology that powers our [hosted services](https://docs.onkernel.com/introduction).
Kernel provides containerized, ready-to-use Chrome browser environments for agentic workflows that need to access the Internet. `containers/docker/Dockerfile` and `unikernels/unikraft-cu` are the core infra that powers our [hosted services](https://docs.onkernel.com/introduction).

### Key Features

Expand Down Expand Up @@ -33,6 +33,7 @@ docker run -p 8501:8501 -p 8080:8080 -p 6080:6080 -p 9222:9222 kernel-chromium
```

This exposes three ports:

- `8080`: Anthropic's Computer Use web application, which includes a chat interface and remote GUI
- `6080`: NoVNC interface for visual monitoring via browser-based VNC client
- `9222`: Chrome DevTools Protocol for browser automation via Playwright and Puppeteer
Expand All @@ -45,25 +46,29 @@ This exposes three ports:
You can connect to the browser using any CDP client.

First, fetch the browser's CDP websocket endpoint:

```typescript
const response = await fetch("http://localhost:9222/json/version");
if (response.status !== 200) {
throw new Error(
throw new Error(
`Failed to retrieve browser instance: ${
response.statusText
response.statusText
} ${await response.text()}`
);
);
}
const { webSocketDebuggerUrl } = await response.json();
```

Then, connect a remote Playwright or Puppeteer client to it:

```typescript
const browser = await puppeteer.connect({
browserWSEndpoint:webSocketDebuggerUrl,
browserWSEndpoint: webSocketDebuggerUrl,
});
```

or:

```typescript
browser = await chromium.connectOverCDP(cdp_ws_url);
```
Expand Down
76 changes: 76 additions & 0 deletions unikernels/unikraft-cu/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
FROM docker.io/ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive
ENV DEBIAN_PRIORITY=high

RUN apt-get update && \
apt-get -y upgrade && \
apt-get -y install \
# UI Requirements
xvfb \
xterm \
xdotool \
scrot \
imagemagick \
sudo \
mutter \
x11vnc \
# Python/pyenv reqs
build-essential \
libssl-dev \
zlib1g-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
curl \
git \
libncursesw5-dev \
xz-utils \
tk-dev \
libxml2-dev \
libxmlsec1-dev \
libffi-dev \
liblzma-dev \
# Network tools
net-tools \
netcat \
# PPA req
software-properties-common && \
# Userland apps
sudo add-apt-repository ppa:mozillateam/ppa && \
sudo apt-get install -y --no-install-recommends \
chromium-browser \
libreoffice \
x11-apps \
xpdf \
gedit \
xpaint \
tint2 \
galculator \
pcmanfm \
wget \
xdg-utils \
libvulkan1 \
fonts-liberation \
unzip && \
apt-get clean

# install chromium & ncat for proxying the remote debugging port
RUN add-apt-repository -y ppa:xtradeb/apps
RUN apt update -y && apt install -y chromium ncat

# Install noVNC
RUN git clone --branch v1.5.0 https://github.com/novnc/noVNC.git /opt/noVNC && \
git clone --branch v0.12.0 https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \
ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html

# setup desktop env & app
ENV DISPLAY_NUM=1
ENV HEIGHT=768
ENV WIDTH=1024

COPY image-chromium/ /
COPY ./wrapper.sh /wrapper.sh

ENTRYPOINT [ "/wrapper.sh" ]

12 changes: 12 additions & 0 deletions unikernels/unikraft-cu/Kraftfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
spec: v0.6

runtime: base-compat:latest

labels:
cloud.unikraft.v1.instances/scale_to_zero.policy: "on"
cloud.unikraft.v1.instances/scale_to_zero.stateful: "true"
cloud.unikraft.v1.instances/scale_to_zero.cooldown_time_ms: 4000

rootfs: ./Dockerfile

cmd: ["/wrapper.sh"]
6 changes: 6 additions & 0 deletions unikernels/unikraft-cu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Originally taken and modified from: https://github.com/anthropics/anthropic-quickstarts/tree/main/computer-use-demo

To build / deploy:

1. export UKC_METRO=was1 and UKC_TOKEN=`<secret>`.
2. run `./deploy.sh`
14 changes: 14 additions & 0 deletions unikernels/unikraft-cu/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should be here and not in kernel-deployment right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

kraft makes this a hard call since there's no kraft cloud build command, only kraft cloud deploy which does both build + deploy. I think we keep it here since the deployment part is basically thrown away (actual deployments are done programmatically in the API via kraft cloud instance create) and all we care about is the image artifact it creates


name="kernel-cu"

kraft cloud deploy \
-M 8192 \
-p 443:6080/http+tls \
-p 9222:9222/tls \
-e DISPLAY_NUM=1 \
-e HEIGHT=768 \
-e WIDTH=1024 \
-e HOME=/ \
-n "$name" \
.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Desktop Entry]
Name=Gedit
Comment=Open gedit
Exec=gedit
Icon=text-editor-symbolic
Terminal=false
Type=Application
Categories=TextEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Desktop Entry]
Name=Terminal
Comment=Open Terminal
Exec=xterm
Icon=utilities-terminal
Terminal=false
Type=Application
Categories=System;TerminalEmulator;
100 changes: 100 additions & 0 deletions unikernels/unikraft-cu/image-chromium/.config/tint2/tint2rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#-------------------------------------
# Panel
panel_items = TL
panel_size = 100% 60
panel_margin = 0 0
panel_padding = 2 0 2
panel_background_id = 1
wm_menu = 0
panel_dock = 0
panel_position = bottom center horizontal
panel_layer = top
panel_monitor = all
panel_shrink = 0
autohide = 0
autohide_show_timeout = 0
autohide_hide_timeout = 0.5
autohide_height = 2
strut_policy = follow_size
panel_window_name = tint2
disable_transparency = 1
mouse_effects = 1
font_shadow = 0
mouse_hover_icon_asb = 100 0 10
mouse_pressed_icon_asb = 100 0 0
scale_relative_to_dpi = 0
scale_relative_to_screen_height = 0

#-------------------------------------
# Taskbar
taskbar_mode = single_desktop
taskbar_hide_if_empty = 0
taskbar_padding = 0 0 2
taskbar_background_id = 0
taskbar_active_background_id = 0
taskbar_name = 1
taskbar_hide_inactive_tasks = 0
taskbar_hide_different_monitor = 0
taskbar_hide_different_desktop = 0
taskbar_always_show_all_desktop_tasks = 0
taskbar_name_padding = 4 2
taskbar_name_background_id = 0
taskbar_name_active_background_id = 0
taskbar_name_font_color = #e3e3e3 100
taskbar_name_active_font_color = #ffffff 100
taskbar_distribute_size = 0
taskbar_sort_order = none
task_align = left

#-------------------------------------
# Launcher
launcher_padding = 4 8 4
launcher_background_id = 0
launcher_icon_background_id = 0
launcher_icon_size = 48
launcher_icon_asb = 100 0 0
launcher_icon_theme_override = 0
startup_notifications = 1
launcher_tooltip = 1

#-------------------------------------
# Launcher icon
launcher_item_app = /usr/share/applications/libreoffice-calc.desktop
launcher_item_app = /.config/tint2/applications/terminal.desktop
launcher_item_app = /.config/tint2/applications/chromium-custom.desktop
launcher_item_app = /usr/share/applications/xpaint.desktop
launcher_item_app = /usr/share/applications/xpdf.desktop
launcher_item_app = /.config/tint2/applications/gedit.desktop
launcher_item_app = /usr/share/applications/galculator.desktop

#-------------------------------------
# Background definitions
# ID 1
rounded = 0
border_width = 0
background_color = #000000 60
border_color = #000000 30

# ID 2
rounded = 4
border_width = 1
background_color = #777777 20
border_color = #777777 30

# ID 3
rounded = 4
border_width = 1
background_color = #777777 20
border_color = #ffffff 40

# ID 4
rounded = 4
border_width = 1
background_color = #aa4400 100
border_color = #aa7733 100

# ID 5
rounded = 4
border_width = 1
background_color = #aaaa00 100
border_color = #aaaa00 100
6 changes: 6 additions & 0 deletions unikernels/unikraft-cu/image-chromium/.streamlit/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[server]
fileWatcherType = "auto"
runOnSave = true

[browser]
gatherUsageStats = false
15 changes: 15 additions & 0 deletions unikernels/unikraft-cu/image-chromium/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
set -e

./start_all.sh
./novnc_startup.sh

python http_server.py > /tmp/server_logs.txt 2>&1 &

STREAMLIT_SERVER_PORT=8501 python -m streamlit run computer_use_demo/streamlit.py > /tmp/streamlit_stdout.log &

echo "✨ Computer Use Demo is ready!"
echo "➡️ Open http://localhost:8080 in your browser to begin"

# Keep the container running
tail -f /dev/null
19 changes: 19 additions & 0 deletions unikernels/unikraft-cu/image-chromium/http_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os
import socket
from http.server import HTTPServer, SimpleHTTPRequestHandler


class HTTPServerV6(HTTPServer):
address_family = socket.AF_INET6


def run_server():
os.chdir(os.path.dirname(__file__) + "/static_content")
server_address = ("::", 8080)
httpd = HTTPServerV6(server_address, SimpleHTTPRequestHandler)
print("Starting HTTP server on port 8080...") # noqa: T201
httpd.serve_forever()


if __name__ == "__main__":
run_server()
43 changes: 43 additions & 0 deletions unikernels/unikraft-cu/image-chromium/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!doctype html>
<html>
<head>
<title>Computer Use Demo</title>
<meta name="permissions-policy" content="fullscreen=*" />
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.container {
display: flex;
height: 100vh;
width: 100vw;
}
.left {
flex: 1;
border: none;
height: 100vh;
}
.right {
flex: 2;
border: none;
height: 100vh;
}
</style>
</head>
<body>
<div class="container">
<iframe
src="http://localhost:8501"
class="left"
allow="fullscreen"
></iframe>
<iframe
src="http://localhost:6080/vnc.html?view_only=1&autoconnect=1&resize=scale"
class="right"
allow="fullscreen"
></iframe>
</div>
</body>
</html>
20 changes: 20 additions & 0 deletions unikernels/unikraft-cu/image-chromium/mutter_startup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
echo "starting mutter"
XDG_SESSION_TYPE=x11 mutter --replace --sm-disable 2>/tmp/mutter_stderr.log &

# Wait for tint2 window properties to appear
timeout=30
while [ $timeout -gt 0 ]; do
if xdotool search --class "mutter" >/dev/null 2>&1; then
break
fi
sleep 1
((timeout--))
done

if [ $timeout -eq 0 ]; then
echo "mutter stderr output:" >&2
cat /tmp/mutter_stderr.log >&2
exit 1
fi

rm /tmp/mutter_stderr.log
Loading