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
77 changes: 77 additions & 0 deletions chromium-cdp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Chromium CDP

This example uses Chromium, a headless browser exposing a [CDP (Chrome DevTools Protocol)](https://chromedevtools.github.io/devtools-protocol/) websocket interface.

To run this example, follow these steps:

1. Install the `kraft` CLI tool and a container runtime engine, for example [Docker](https://docs.docker.com/get-docker/).

1. Clone the examples repository and `cd` into the `examples/chromium-cdp/` directory:

```console
git clone https://github.com/unikraft-cloud/examples
cd examples/chromium-cdp/
```

1. Make sure to log into Unikraft Cloud by setting your token and a metro close to you.
This guide uses `fra` (Frankfurt, DE):

```console
export UKC_TOKEN=token
# Set metro to Frankfurt, 🇩🇪
export UKC_METRO=fra
```

1. When done, deploy this app on Unikraft Cloud.
You can run the deploy script (which builds an erofs root filesystem and deploys it):

```console
./deploy.sh
```

The output shows the instance address and other details.

```ansi
[●] Deployed successfully!
├─────── name: chromium-cdp-d0l6y
├─────── uuid: debe81b0-8418-4e01-b795-b3546e0e5aac
├────── state: starting
├───── domain: https://spring-dream-p5wxwwl0.fra.unikraft.app
├────── image: chromium-cdp@sha256:9e22546a9234efbd586b3cc3ff2ab71d64b56e87b8af431a3dfffd4aff274cc3
├───── memory: 4096 MiB
├──── service: spring-dream-p5wxwwl0
├─ private ip: 10.0.4.141
└─────── args: /usr/bin/wrapper.sh /usr/bin/node /app/proxy.js
```

In this case, the instance name is `chromium-cdp-d0l6y` and the address is `https://spring-dream-p5wxwwl0.fra.unikraft.app`. They're different for each run.

1. To query the service you need to use a CDP client.
You can use the Python-based implementation in the `test/` directory.

1. You can list information about the instance by running:

```console
kraft cloud instance list
```

1. When done, you can remove the instance:

```console
kraft cloud instance remove <instance-name>
```

## Learn more

- [CDP Documentation](https://chromedevtools.github.io/devtools-protocol/)
- [Unikraft Cloud's Documentation](https://unikraft.cloud/docs/)
- [Building `Dockerfile` Images with `Buildkit`](https://unikraft.org/guides/building-dockerfile-images-with-buildkit)

Use the `--help` option for detailed information on using Unikraft Cloud:

```console
kraft cloud --help
```

Or visit the [CLI Reference](https://unikraft.org/docs/cli/reference).
4 changes: 4 additions & 0 deletions chromium-cdp/chromium-cdp/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/node_modules/
/.unikraft/
/.rootfs/
/*.png
5 changes: 5 additions & 0 deletions chromium-cdp/chromium-cdp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/node_modules/
/.unikraft/
/.rootfs/
/*.png
/initrd
239 changes: 239 additions & 0 deletions chromium-cdp/chromium-cdp/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
FROM debian:bookworm AS build

ARG NODE_VERSION=22.8.0

RUN set -xe; \
apt-get -yqq update; \
apt-get -yqq install \
libcups2 \
libnss3 \
libatk1.0-0 \
libnspr4 \
libpango1.0-0 \
libasound2 \
libatspi2.0-0 \
libxdamage1 \
libatk-bridge2.0-0 \
libxkbcommon0 \
libdrm2 \
libxcomposite1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libnss3; \
apt-get -yqq install \
ca-certificates \
curl \
build-essential \
libssl-dev \
git \
;

RUN set -xe; \
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION%%.*}.x | bash -; \
apt-get -yqq install nodejs \
;

WORKDIR /app
COPY package* .

RUN set -xe; \
npm install \
;

# Strip some binaries
RUN cd /root/.cache/ms-playwright/chromium-*/chrome-linux; \
strip chrome \
chrome_crashpad_handler \
chrome_sandbox \
chrome-wrapper \
libEGL.so \
libGLESv2.so \
libvk_swiftshader.so \
libvulkan.so.1 \
xdg-mime \
xdg-settings \
; \
cd /root/.cache/ms-playwright/chromium_headless_shell-*/chrome-linux; \
strip chrome \
headless_shell \
libEGL.so \
libGLESv2.so \
libvk_swiftshader.so \
libvulkan.so.1 \
; \
strip /usr/bin/node \
;

RUN mkdir /home/tmp

FROM scratch

# Create required directories.
COPY --from=build /home/tmp /tmp

# Chrome binary
COPY --from=build /root/.cache/ms-playwright /root/.cache/ms-playwright

# Chrome libraries
COPY --from=build /lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libpthread.so.0 \
/lib/x86_64-linux-gnu/libgobject-2.0.so.0 \
/lib/x86_64-linux-gnu/libglib-2.0.so.0 \
/lib/x86_64-linux-gnu/libnss3.so \
/lib/x86_64-linux-gnu/libnssutil3.so \
/lib/x86_64-linux-gnu/libsmime3.so \
/lib/x86_64-linux-gnu/libnspr4.so \
/lib/x86_64-linux-gnu/libatk-1.0.so.0 \
/lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0 \
/lib/x86_64-linux-gnu/libcups.so.2 \
/lib/x86_64-linux-gnu/libgio-2.0.so.0 \
/lib/x86_64-linux-gnu/libdrm.so.2 \
/lib/x86_64-linux-gnu/libdbus-1.so.3 \
/lib/x86_64-linux-gnu/libexpat.so.1 \
/lib/x86_64-linux-gnu/libxcb.so.1 \
/lib/x86_64-linux-gnu/libxkbcommon.so.0 \
/lib/x86_64-linux-gnu/libatspi.so.0 \
/lib/x86_64-linux-gnu/libm.so.6 \
/lib/x86_64-linux-gnu/libX11.so.6 \
/lib/x86_64-linux-gnu/libXcomposite.so.1 \
/lib/x86_64-linux-gnu/libXdamage.so.1 \
/lib/x86_64-linux-gnu/libXext.so.6 \
/lib/x86_64-linux-gnu/libXfixes.so.3 \
/lib/x86_64-linux-gnu/libXrandr.so.2 \
/lib/x86_64-linux-gnu/libgbm.so.1 \
/lib/x86_64-linux-gnu/libpango-1.0.so.0 \
/lib/x86_64-linux-gnu/libcairo.so.2 \
/lib/x86_64-linux-gnu/libasound.so.2 \
/lib/x86_64-linux-gnu/libgcc_s.so.1 \
/lib/x86_64-linux-gnu/libc.so.6 \
/lib/x86_64-linux-gnu/libffi.so.8 \
/lib/x86_64-linux-gnu/libpcre2-8.so.0 \
/lib/x86_64-linux-gnu/libplc4.so \
/lib/x86_64-linux-gnu/libplds4.so \
/lib/x86_64-linux-gnu/libgssapi_krb5.so.2 \
/lib/x86_64-linux-gnu/libavahi-common.so.3 \
/lib/x86_64-linux-gnu/libavahi-client.so.3 \
/lib/x86_64-linux-gnu/libgnutls.so.30 \
/lib/x86_64-linux-gnu/libz.so.1 \
/lib/x86_64-linux-gnu/libgmodule-2.0.so.0 \
/lib/x86_64-linux-gnu/libmount.so.1 \
/lib/x86_64-linux-gnu/libselinux.so.1 \
/lib/x86_64-linux-gnu/libsystemd.so.0 \
/lib/x86_64-linux-gnu/libXau.so.6 \
/lib/x86_64-linux-gnu/libXdmcp.so.6 \
/lib/x86_64-linux-gnu/libXi.so.6 \
/lib/x86_64-linux-gnu/libXrender.so.1 \
/lib/x86_64-linux-gnu/libwayland-server.so.0 \
/lib/x86_64-linux-gnu/libfribidi.so.0 \
/lib/x86_64-linux-gnu/libthai.so.0 \
/lib/x86_64-linux-gnu/libharfbuzz.so.0 \
/lib/x86_64-linux-gnu/libpixman-1.so.0 \
/lib/x86_64-linux-gnu/libfontconfig.so.1 \
/lib/x86_64-linux-gnu/libfreetype.so.6 \
/lib/x86_64-linux-gnu/libpng16.so.16 \
/lib/x86_64-linux-gnu/libxcb-shm.so.0 \
/lib/x86_64-linux-gnu/libxcb-render.so.0 \
/lib/x86_64-linux-gnu/libkrb5.so.3 \
/lib/x86_64-linux-gnu/libk5crypto.so.3 \
/lib/x86_64-linux-gnu/libcom_err.so.2 \
/lib/x86_64-linux-gnu/libkrb5support.so.0 \
/lib/x86_64-linux-gnu/libp11-kit.so.0 \
/lib/x86_64-linux-gnu/libidn2.so.0 \
/lib/x86_64-linux-gnu/libunistring.so.2 \
/lib/x86_64-linux-gnu/libtasn1.so.6 \
/lib/x86_64-linux-gnu/libnettle.so.8 \
/lib/x86_64-linux-gnu/libhogweed.so.6 \
/lib/x86_64-linux-gnu/libgmp.so.10 \
/lib/x86_64-linux-gnu/libblkid.so.1 \
/lib/x86_64-linux-gnu/libcap.so.2 \
/lib/x86_64-linux-gnu/libgcrypt.so.20 \
/lib/x86_64-linux-gnu/liblzma.so.5 \
/lib/x86_64-linux-gnu/libzstd.so.1 \
/lib/x86_64-linux-gnu/liblz4.so.1 \
/lib/x86_64-linux-gnu/libbsd.so.0 \
/lib/x86_64-linux-gnu/libdatrie.so.1 \
/lib/x86_64-linux-gnu/libgraphite2.so.3 \
/lib/x86_64-linux-gnu/libbrotlidec.so.1 \
/lib/x86_64-linux-gnu/libkeyutils.so.1 \
/lib/x86_64-linux-gnu/libresolv.so.2 \
/lib/x86_64-linux-gnu/libgpg-error.so.0 \
/lib/x86_64-linux-gnu/libmd.so.0 \
/lib/x86_64-linux-gnu/libbrotlicommon.so.1 \
/lib/x86_64-linux-gnu/libXcomposite.so.1 \
/lib/x86_64-linux-gnu/libXfixes.so.3 \
/lib/x86_64-linux-gnu/libXrandr.so.2 \
/lib/x86_64-linux-gnu/libgbm.so.1 \
/lib/x86_64-linux-gnu/

# Other Chrome-related libraries
COPY --from=build /usr/lib/x86_64-linux-gnu/libsoftokn3.so \
/usr/lib/x86_64-linux-gnu/libsqlite3.so.0 \
/usr/lib/x86_64-linux-gnu/libudev.so.1 \
/usr/lib/x86_64-linux-gnu/libfreebl3.so \
/usr/lib/x86_64-linux-gnu/libfreeblpriv3.so \
/usr/lib/x86_64-linux-gnu/libudev.so.1.7.5 \
/usr/lib/x86_64-linux-gnu/libnssckbi.so \
/usr/lib/x86_64-linux-gnu/

# Node binary
COPY --from=build /usr/bin/node /usr/bin/node

# System libraries
COPY --from=build /lib/x86_64-linux-gnu/libc.so.6 \
/lib/x86_64-linux-gnu/libz.so.1 \
/lib/x86_64-linux-gnu/libbrotlidec.so.1 \
/lib/x86_64-linux-gnu/libbrotlienc.so.1 \
/lib/x86_64-linux-gnu/libnghttp2.so.14 \
/lib/x86_64-linux-gnu/libcrypto.so.3 \
/lib/x86_64-linux-gnu/libssl.so.3 \
/lib/x86_64-linux-gnu/libicui18n.so.72 \
/lib/x86_64-linux-gnu/libicuuc.so.72 \
/lib/x86_64-linux-gnu/libstdc++.so.6 \
/lib/x86_64-linux-gnu/libm.so.6 \
/lib/x86_64-linux-gnu/libgcc_s.so.1 \
/lib/x86_64-linux-gnu/libpthread.so.0 \
/lib/x86_64-linux-gnu/libdl.so.2 \
/lib/x86_64-linux-gnu/libbrotlicommon.so.1 \
/lib/x86_64-linux-gnu/libicudata.so.72 \
/lib/x86_64-linux-gnu/librt.so.1 \
/lib/x86_64-linux-gnu/libtinfo.so.6 \
/lib/x86_64-linux-gnu/libproc2.so.0 \
/lib/x86_64-linux-gnu/

COPY --from=build /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=build /etc/ld.so.cache /etc/ld.so.cache

# Dbus and system files
COPY --from=build /usr/lib/dbus-1.0 /usr/lib/dbus-1.0
COPY --from=build /usr/lib/systemd /usr/lib/systemd
COPY --from=build /usr/lib/tmpfiles.d /usr/lib/tmpfiles.d
COPY --from=build /usr/lib/sysusers.d /usr/lib/sysusers.d
COPY --from=build /usr/lib/sysctl.d /usr/lib/sysctl.d

# Data files
COPY --from=build /usr/share/fonts /usr/share/fonts

COPY --from=build /run /run

# Distro definition
COPY --from=build /etc/os-release /etc/os-release
COPY --from=build /usr/lib/os-release /usr/lib/os-release

# Configuration files
COPY --from=build /etc /etc

# Required by wrapper script
COPY --from=build /bin/sh /bin/sh

# Required by Playwright / Chrome
COPY --from=build /usr/bin/ps /usr/bin/ps

# Node application, including Playwright.
COPY --from=build /app /app

# Actual server implementation
COPY ./proxy.js /app/proxy.js

# Wrapper script set environment
COPY ./wrapper.sh /usr/bin/wrapper.sh
13 changes: 13 additions & 0 deletions chromium-cdp/chromium-cdp/Kraftfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
spec: v0.6

runtime: base-compat:latest

labels:
cloud.unikraft.v1.instances/scale_to_zero.policy: "idle"
cloud.unikraft.v1.instances/scale_to_zero.stateful: "true"
cloud.unikraft.v1.instances/scale_to_zero.cooldown_time_ms: 1000

#rootfs: ./Dockerfile
rootfs: ./initrd

cmd: ["/usr/bin/wrapper.sh", "/usr/bin/node", "/app/proxy.js"]
43 changes: 43 additions & 0 deletions chromium-cdp/chromium-cdp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
DOCKERFILE ?= Dockerfile
IMAGE_NAME ?= playwright-chromium-cdp
CONTAINER_NAME ?= cnt-$(IMAGE_NAME)
CMD ?= /usr/bin/wrapper.sh /usr/bin/node /app/proxy.js
PORT_MAPPING = 8081:8080

build:
docker build -f $(DOCKERFILE) -t $(IMAGE_NAME) .

run_anon: build
docker run --rm -p $(PORT_MAPPING) --interactive --tty $(IMAGE_NAME) $(CMD)

create: build
-docker container inspect $(CONTAINER_NAME) > /dev/null 2>&1 || docker create --name $(CONTAINER_NAME) -p $(PORT_MAPPING) --tty $(IMAGE_NAME) $(CMD)

run: create
-test "$(shell docker container inspect -f '{{{{.State.Running}}}}' $(CONTAINER_NAME) 2> /dev/null)" = "false" || docker exec --interactive --tty $(CONTAINER_NAME) $(CMD) && docker start --interactive $(CONTAINER_NAME)

stop:
-test "$(shell docker container inspect -f '{{{{.State.Running}}}}' $(CONTAINER_NAME) 2> /dev/null)" = "true" && docker stop $(CONTAINER_NAME)

clean: stop
-docker container inspect $(CONTAINER_NAME) > /dev/null 2>&1 && docker rm $(CONTAINER_NAME)

export: clean create cleanfs
mkdir rootfs
docker export $(CONTAINER_NAME) | tar -x -C rootfs

export_build: clean
mkdir rootfs
docker build -o rootfs -f $(DOCKERFILE) .

rootfs: export

rootfs.cpio: rootfs
cd rootfs/ && find -depth -print | tac | bsdcpio -o --format newc > ../rootfs.cpio

initrd: rootfs.cpio

cleanfs:
-test -d rootfs && rm -fr rootfs

.PHONY: build build run_anon create run stop clean export initrd cleanfs
Loading