From 0b8fda5d7c898c28ffc830788e48640e3e58e6cf Mon Sep 17 00:00:00 2001 From: Nick Sweeting Date: Fri, 27 Jun 2025 05:36:23 -0700 Subject: [PATCH] speedup docker build to 20s --- Dockerfile.fast | 31 ++++++++++++ docker/README.md | 34 +++++++++++++ docker/base-images/chromium/Dockerfile | 16 +++++++ docker/base-images/python-deps/Dockerfile | 11 +++++ docker/base-images/system/Dockerfile | 10 ++++ docker/build-base-images.sh | 58 +++++++++++++++++++++++ 6 files changed, 160 insertions(+) create mode 100644 Dockerfile.fast create mode 100644 docker/README.md create mode 100644 docker/base-images/chromium/Dockerfile create mode 100644 docker/base-images/python-deps/Dockerfile create mode 100644 docker/base-images/system/Dockerfile create mode 100755 docker/build-base-images.sh diff --git a/Dockerfile.fast b/Dockerfile.fast new file mode 100644 index 000000000..511d774d4 --- /dev/null +++ b/Dockerfile.fast @@ -0,0 +1,31 @@ +# Fast Dockerfile using pre-built base images +ARG REGISTRY=browseruse +ARG BASE_TAG=latest +FROM ${REGISTRY}/base-python-deps:${BASE_TAG} + +LABEL name="browseruse" description="Browser automation for AI agents" + +ENV BROWSERUSE_USER="browseruse" DEFAULT_PUID=911 DEFAULT_PGID=911 DATA_DIR=/data + +# Create user and directories +RUN groupadd --system $BROWSERUSE_USER && \ + useradd --system --create-home --gid $BROWSERUSE_USER --groups audio,video $BROWSERUSE_USER && \ + usermod -u "$DEFAULT_PUID" "$BROWSERUSE_USER" && \ + groupmod -g "$DEFAULT_PGID" "$BROWSERUSE_USER" && \ + mkdir -p /data /home/$BROWSERUSE_USER/.config && \ + ln -s $DATA_DIR /home/$BROWSERUSE_USER/.config/browseruse && \ + mkdir -p "/home/$BROWSERUSE_USER/.config/chromium/Crash Reports/pending/" && \ + mkdir -p "$DATA_DIR/profiles/default" && \ + chown -R "$BROWSERUSE_USER:$BROWSERUSE_USER" "/home/$BROWSERUSE_USER" "$DATA_DIR" + +WORKDIR /app +COPY . /app + +# Install browser-use +RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \ + uv sync --all-extras --locked --no-dev --compile-bytecode + +USER "$BROWSERUSE_USER" +VOLUME "$DATA_DIR" +EXPOSE 9242 9222 +ENTRYPOINT ["browser-use"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..f807698c0 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,34 @@ +# Docker Setup for Browser-Use + +This directory contains the optimized Docker build system for browser-use, achieving < 30 second builds. + +## Quick Start + +```bash +# Build base images (only needed once or when dependencies change) +./docker/build-base-images.sh + +# Build browser-use +docker build -f Dockerfile.fast -t browseruse . + +# Or use the standard Dockerfile (slower but self-contained) +docker build -t browseruse . +``` + +## Files + +- `Dockerfile` - Standard self-contained build (~2 min) +- `Dockerfile.fast` - Fast build using pre-built base images (~30 sec) +- `docker/` - Base image definitions and build script + - `base-images/system/` - Python + minimal system deps + - `base-images/chromium/` - Adds Chromium browser + - `base-images/python-deps/` - Adds Python dependencies + - `build-base-images.sh` - Script to build all base images + +## Performance + +| Build Type | Time | +|------------|------| +| Standard Dockerfile | ~2 minutes | +| Fast build (with base images) | ~30 seconds | +| Rebuild after code change | ~16 seconds | diff --git a/docker/base-images/chromium/Dockerfile b/docker/base-images/chromium/Dockerfile new file mode 100644 index 000000000..1c2ff1d07 --- /dev/null +++ b/docker/base-images/chromium/Dockerfile @@ -0,0 +1,16 @@ +ARG BASE_TAG=latest +FROM browseruse/base-system:${BASE_TAG} + +WORKDIR /tmp +COPY pyproject.toml ./ + +# Install both playwright and patchright with versions from pyproject.toml +RUN --mount=type=cache,target=/root/.cache,sharing=locked \ + PLAYWRIGHT_VERSION=$(grep -E "playwright>=" pyproject.toml | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" | head -1) && \ + PATCHRIGHT_VERSION=$(grep -E "patchright>=" pyproject.toml | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" | head -1) && \ + echo "Installing playwright==$PLAYWRIGHT_VERSION patchright==$PATCHRIGHT_VERSION" && \ + pip install --no-cache-dir playwright==$PLAYWRIGHT_VERSION patchright==$PATCHRIGHT_VERSION && \ + PLAYWRIGHT_BROWSERS_PATH=/opt/playwright playwright install --with-deps --no-shell chromium && \ + ln -s /opt/playwright/chromium-*/chrome-linux/chrome /usr/bin/chromium-browser && \ + chmod -R 755 /opt/playwright && \ + rm -f pyproject.toml diff --git a/docker/base-images/python-deps/Dockerfile b/docker/base-images/python-deps/Dockerfile new file mode 100644 index 000000000..9c84647de --- /dev/null +++ b/docker/base-images/python-deps/Dockerfile @@ -0,0 +1,11 @@ +ARG BASE_TAG=latest +FROM browseruse/base-chromium:${BASE_TAG} + +ENV PYTHONUNBUFFERED=1 PATH="/app/.venv/bin:$PATH" PLAYWRIGHT_BROWSERS_PATH=/opt/playwright + +WORKDIR /app +COPY pyproject.toml uv.lock* ./ + +RUN --mount=type=cache,target=/root/.cache/uv,sharing=locked \ + uv venv && \ + uv sync --all-extras --no-dev --no-install-project --compile-bytecode diff --git a/docker/base-images/system/Dockerfile b/docker/base-images/system/Dockerfile new file mode 100644 index 000000000..2c8fb4931 --- /dev/null +++ b/docker/base-images/system/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.12-slim + +# Install minimal system dependencies +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + apt-get update && \ + apt-get install -y --no-install-recommends ca-certificates curl wget && \ + rm -rf /var/lib/apt/lists/* + +# Install uv package manager +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ diff --git a/docker/build-base-images.sh b/docker/build-base-images.sh new file mode 100755 index 000000000..1d9f76045 --- /dev/null +++ b/docker/build-base-images.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Build script for browser-use base images +set -euo pipefail + +# Configuration +REGISTRY="${DOCKER_REGISTRY:-browseruse}" +PLATFORMS="${PLATFORMS:-linux/amd64}" +PUSH="${PUSH:-false}" + +# Build function +build_image() { + local name=$1 + local dockerfile=$2 + local build_args="${3:-}" + + echo "[INFO] Building ${name}..." + + local build_cmd="docker build" + local tag_args="-t ${REGISTRY}/${name}:latest -t ${REGISTRY}/${name}:$(date +%Y%m%d)" + + # Use buildx for multi-platform or push + if [[ "$PLATFORMS" == *","* ]] || [ "$PUSH" = "true" ]; then + build_cmd="docker buildx build --platform=$PLATFORMS" + [ "$PUSH" = "true" ] && build_cmd="$build_cmd --push" || build_cmd="$build_cmd" + fi + + $build_cmd $tag_args $build_args -f $dockerfile ../../.. +} + +# Main +cd "$(dirname "$0")" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --push) PUSH=true; shift ;; + --registry) REGISTRY="$2"; shift 2 ;; + --platforms) PLATFORMS="$2"; shift 2 ;; + --help) + echo "Usage: $0 [--push] [--registry REG] [--platforms P]" + exit 0 ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +# Create buildx builder if needed +if [[ "$PLATFORMS" == *","* ]] || [ "$PUSH" = "true" ]; then + docker buildx inspect browseruse-builder >/dev/null 2>&1 || \ + docker buildx create --name browseruse-builder --use + docker buildx use browseruse-builder +fi + +# Build images in order +build_image "base-system" "base-images/system/Dockerfile" +build_image "base-chromium" "base-images/chromium/Dockerfile" "--build-arg BASE_TAG=latest" +build_image "base-python-deps" "base-images/python-deps/Dockerfile" "--build-arg BASE_TAG=latest" + +echo "[INFO] Build complete. Use: FROM ${REGISTRY}/base-python-deps:latest"