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
78 changes: 78 additions & 0 deletions unikernels/unikraft-cu/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# webrtc client
FROM node:22-bullseye-slim AS client
WORKDIR /src
COPY client/package*.json ./
RUN npm install
COPY client/ .
RUN npm run build

# xorg dependencies
FROM docker.io/ubuntu:22.04 AS xorg-deps
WORKDIR /xorg
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
apt-get install -y \
git gcc pkgconf autoconf automake libtool make xorg-dev xutils-dev \
&& rm -rf /var/lib/apt/lists/*;
COPY xorg-deps/ /xorg/
# build xf86-video-dummy v0.3.8 with RandR support
RUN set -eux; \
cd xf86-video-dummy/v0.3.8; \
patch -p1 < ../01_v0.3.8_xdummy-randr.patch; \
autoreconf -v --install; \
./configure; \
make -j$(nproc); \
make install;
# build custom input driver
RUN set -eux; \
cd xf86-input-neko; \
./autogen.sh --prefix=/usr; \
./configure; \
make -j$(nproc); \
make install;

FROM ghcr.io/m1k1o/neko/chromium:3.0.6 AS neko
FROM docker.io/ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive
Expand Down Expand Up @@ -55,6 +90,41 @@ RUN apt-get update && \
unzip && \
apt-get clean

# runtime
ENV USERNAME=root
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
wget ca-certificates python2 supervisor xclip \
pulseaudio dbus-x11 xserver-xorg-video-dummy \
libcairo2 libxcb1 libxrandr2 libxv1 libopus0 libvpx7 \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
gstreamer1.0-pulseaudio gstreamer1.0-omx; \
#
# install libxcvt0 (not available in debian:bullseye)
ARCH=$(dpkg --print-architecture); \
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_${ARCH}.deb; \
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_${ARCH}.deb; \
rm ./libxcvt0_0.1.2-1_${ARCH}.deb; \
#
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
mkdir /tmp/.X11-unix; \
chmod 1777 /tmp/.X11-unix; \
chown $USERNAME /tmp/.X11-unix/; \
#
# make directories for neko
mkdir -p /etc/neko /var/www /var/log/neko \
/tmp/runtime-$USERNAME \
/home/$USERNAME/.config/pulse \
/home/$USERNAME/.local/share/xorg; \
chmod 1777 /var/log/neko; \
chown $USERNAME /var/log/neko/ /tmp/runtime-$USERNAME; \
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/

# 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
Expand All @@ -68,6 +138,14 @@ RUN git clone --branch v1.5.0 https://github.com/novnc/noVNC.git /opt/noVNC && \
ENV DISPLAY_NUM=1
ENV HEIGHT=768
ENV WIDTH=1024
ENV WITHDOCKER=true

COPY xorg.conf /etc/neko/xorg.conf
COPY neko.yaml /etc/neko/neko.yaml
COPY --from=neko /usr/bin/neko /usr/bin/neko
COPY --from=client /src/dist/ /var/www
COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so

COPY image-chromium/ /
COPY ./wrapper.sh /wrapper.sh
Expand Down
35 changes: 35 additions & 0 deletions unikernels/unikraft-cu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ Deployed successfully!
└───────── args: /wrapper.sh
```

### 3.1 Deploy the Implementation with WebRTC desktop streaming enabled
```sh
ENABLE_WEBRTC=true NEKO_ICESERVERS=xxx ./run.sh
```

`NEKO_ICESERVERS`
* Describes multiple STUN and TURN server that can be used by the ICEAgent to establish a connection with a peer.
* e.g. `[{"urls": ["turn:turn.example.com:19302", "stun:stun.example.com:19302"], "username": "name", "credential": "password"}, {"urls": ["stun:stun.example2.com:19302"]}]`

WebRTC web client will run at port `8080`.

## 🧑‍💻 Connect via remote GUI (noVNC)

This implementation maps a noVNC remote GUI to the host port. You can access it by visiting the `domain` listed in Kraft's CLI output above. The remote GUI supports both read and write actions on the browser.
Expand Down Expand Up @@ -95,6 +106,30 @@ const browser = await chromium.connectOverCDP(finalWSUrl);
- You can call `browser.close()` to disconnect to the browser, and the unikernel will go into standby after network activity ends. You can then reconnect to the instance using CDP. `browser.close()` ends the websocket connection but doesn't actually close the browser.
- See this repo's [homepage](/README.md) for some benefits of putting Chromium on a unikernel.

## Docker

You can also run the Dockerfile directly as a docker container:

```sh
docker build -t kernel-docker .
docker run -d \
-p 8080:8080 \
-p 9222:9222 \
--cap-add SYS_ADMIN \
-p 56000-56100:56000-56100/udp \
-e ENABLE_WEBRTC=true \
-e CHROMIUM_FLAGS="--no-sandbox --disable-dev-shm-usage --disable-gpu --start-maximized --disable-software-rasterizer --remote-allow-origins=* --no-zygote" \
-e NEKO_WEBRTC_EPR=56000-56100 \
-e NEKO_WEBRTC_NAT1TO1=127.0.0.1 \
kernel-docker
```

## 📞 WebRTC Notes

- Deploying to Unikraft Cloud requires the usage of a [TURN](https://webrtc.org/getting-started/turn-server), as direct exposure of UDP ports is not currently supported.
- WebRTC functionality is enabled through customized components of [neko](https://github.com/m1k1o/neko).
- TODO: Audio streaming is currently non-functional and needs to be fixed.

## 🤝 License & Contributing
See [here](/README.md) for license and contributing details.

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.

going through and testing this all and noticed that containers/docker/README.md probably needs an update too?

Expand Down
3 changes: 3 additions & 0 deletions unikernels/unikraft-cu/client/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@vue/cli-plugin-babel/preset"]
}
2 changes: 2 additions & 0 deletions unikernels/unikraft-cu/client/.browserslistrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
> 1%
last 2 versions
9 changes: 9 additions & 0 deletions unikernels/unikraft-cu/client/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
18 changes: 18 additions & 0 deletions unikernels/unikraft-cu/client/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"root": true,
"env": {
"node": true
},
"extends": ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"],
"parserOptions": {
"parser": "@typescript-eslint/parser"
},
"rules": {
"vue/valid-v-for": "off",
"no-case-declarations": "off",
"no-dupe-class-members": "off",
"no-console": "off",
"no-empty": "off"
}
}

8 changes: 8 additions & 0 deletions unikernels/unikraft-cu/client/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": false,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2,
"vueIndentScriptAndStyle": true
}
37 changes: 37 additions & 0 deletions unikernels/unikraft-cu/client/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"files.encoding": "utf8",
"files.eol": "\n",
"typescript.tsdk": "./node_modules/typescript/lib",
"todo-tree.filtering.excludeGlobs": ["**/node_modules/**"],
"eslint.validate": [
"vue",
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
],
"vetur.validation.template": true,
"vetur.useWorkspaceDependencies": true,
"remote.extensionKind": {
"ms-azuretools.vscode-docker": "ui"
},
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"remote.containers.defaultExtensions": [
"octref.vetur",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode-remote.vscode-remote-extensionpack",
"ms-vscode-remote.remote-containers",
"ms-azuretools.vscode-docker",
"editorconfig.editorconfig",
"gruntfuggly.todo-tree",
"eamodio.gitlens",
"swyphcosmo.spellchecker"
],
}
18 changes: 18 additions & 0 deletions unikernels/unikraft-cu/client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ARG BASE_IMAGE=node:18-bullseye-slim
FROM $BASE_IMAGE AS client

WORKDIR /src

#
# install dependencies
COPY package*.json ./
RUN npm install

#
# build client
COPY . .
RUN npm run build

#
# artifacts from this stage
# COPY --from=client /src/dist/ /var/www
10 changes: 10 additions & 0 deletions unikernels/unikraft-cu/client/dev/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
cd "$(dirname "$0")"

# start component watch
docker run --rm -it \
--user "$(id -u):$(id -g)" \
--volume "${PWD}/../:/app" \
--entrypoint="npm" \
--workdir="/app" \
node:18-bullseye-slim run build
10 changes: 10 additions & 0 deletions unikernels/unikraft-cu/client/dev/exec
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
cd "$(dirname "$0")"

# start component watch
docker run --rm -it \
--user "$(id -u):$(id -g)" \
--volume "${PWD}/../:/app" \
--entrypoint="/bin/bash" \
--workdir="/app" \
node:18-bullseye-slim
10 changes: 10 additions & 0 deletions unikernels/unikraft-cu/client/dev/npm
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
cd "$(dirname "$0")"

# npm
docker run --rm -it \
--user "$(id -u):$(id -g)" \
--volume "${PWD}/../:/app" \
--entrypoint="npm" \
--workdir="/app" \
node:18-bullseye-slim "$@"
27 changes: 27 additions & 0 deletions unikernels/unikraft-cu/client/dev/serve
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash
cd "$(dirname "$0")"

if [ -z $VUE_APP_SERVER_PORT ]; then
VUE_APP_SERVER_PORT="3000"
fi

echo "Using VUE_APP_SERVER_PORT: ${VUE_APP_SERVER_PORT}"

# use -i to install
if [ ! -d "${PWD}/../node_modules" ] || [ "$1" == "-i" ]; then
docker run --rm -it \
--volume "${PWD}/../:/app" \
--workdir="/app" \
--entrypoint="npm" \
node:18-bullseye-slim install
fi

# npm run serve
docker run --rm -it \
-p 3001:3001 \
-e "VUE_APP_SERVER_PORT=$VUE_APP_SERVER_PORT" \
--user "$(id -u):$(id -g)" \
--volume "${PWD}/../:/app" \
--entrypoint="npm" \
--workdir="/app" \
node:18-bullseye-slim run serve -- --port 3001
Loading