From 301f8e7397da26cdfd86e921f49e47e2a621b9eb Mon Sep 17 00:00:00 2001 From: Mathias Beaulieu-Duncan Date: Mon, 2 Feb 2026 01:14:31 -0500 Subject: [PATCH] Add plan for custom minimal Flutter SDK distribution using apko/melange Documents the multi-stage approach: build Flutter from source in Debian, package as APK with melange, compose minimal runtime image from Wolfi packages with apko. Phased rollout starting with web variant PoC. Co-Authored-By: Claude Opus 4.5 --- PLAN.md | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 PLAN.md diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..a90887e --- /dev/null +++ b/PLAN.md @@ -0,0 +1,259 @@ +# Custom Minimal Flutter SDK Distribution + +## Goal + +Build Flutter SDK from source in a multi-stage Docker build, then copy only the compiled SDK and its runtime dependencies into a custom minimal Linux base image. The result is a secure, minimal container with zero build toolchain bloat. + +## Architecture + +``` +┌─────────────────────────────────────┐ +│ Stage 1: BUILD (debian:bookworm) │ +│ │ +│ - Full build toolchain │ +│ - Compile Flutter engine + Dart │ +│ - All build-time deps │ +│ - Discarded after build │ +└──────────────┬──────────────────────┘ + │ COPY artifacts + ▼ +┌─────────────────────────────────────┐ +│ Stage 2: RUNTIME (custom base) │ +│ │ +│ - Minimal glibc + runtime libs │ +│ - Flutter SDK (pre-compiled) │ +│ - Only what's needed to run │ +│ `flutter build` commands │ +└─────────────────────────────────────┘ +``` + +## Approach: apko + melange on Wolfi + +Use Chainguard's open-source tooling to build the runtime base image from Wolfi packages. This avoids maintaining a full Linux distribution while achieving the same result. + +### Why Wolfi (not Alpine, not from scratch) + +- **glibc-based**: Flutter/Dart require glibc (musl/Alpine won't work) +- **apk package format**: Minimal, fast, composable +- **15,000+ packages**: glibc, libstdc++, git, curl, ca-certificates all available +- **Nightly CVE patching**: Chainguard patches 80%+ of vulnerabilities within 24 hours +- **No distro maintenance burden**: We consume their packages, not maintain them + +### Tools + +| Tool | Purpose | +|---|---| +| **melange** | Build custom APK packages (Flutter SDK, Android SDK) from source | +| **apko** | Compose final OCI image from APK packages (Wolfi base + custom) | + +## Stage 1: Build Flutter from Source + +Flutter SDK source build requirements: +- git (clone flutter/flutter and flutter/engine repos) +- Python 3 (engine build scripts) +- curl, unzip, xz-utils +- clang/llvm (engine compilation) +- ninja-build, gn (engine build system) +- libstdc++-dev +- Dart SDK (bootstrapped from prebuilt, then rebuilt) + +Flutter engine build steps: +1. Clone `flutter/engine` at the pinned revision from `flutter/flutter/bin/internal/engine.version` +2. Run `gclient sync` to fetch dependencies +3. Build with `gn` + `ninja` for target platform +4. Dart SDK is built as part of the engine + +### Per-Variant Build Targets + +| Variant | Engine build target | Extra build deps | Extra runtime deps | +|---|---|---|---| +| **web** | `host_release` (dart2js/dart2wasm) | None | None | +| **android** | `android_release` + `android_release_arm64` | Android NDK | JDK 17, Android SDK cmdline-tools | +| **linux** | `linux_release_x64` | GTK3-dev, CMake | GTK3 runtime libs | + +## Stage 2: Custom Runtime Base via apko + +### Web variant (minimal) + +```yaml +# apko.web.yaml +contents: + keyring: + - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub + repositories: + - https://packages.wolfi.dev/os + - @local /packages # our melange-built Flutter SDK package + packages: + - wolfi-baselayout + - glibc + - libstdc++ + - git + - ca-certificates-bundle + - flutter-sdk-web@local +entrypoint: + command: /bin/sh +environment: + FLUTTER_HOME: /opt/flutter + PATH: /opt/flutter/bin:/opt/flutter/bin/cache/dart-sdk/bin:/usr/bin:/bin +archs: + - x86_64 +``` + +### Android variant + +Same as web plus: +- `openjdk-17-jre` (from Wolfi) +- `flutter-sdk-android@local` (custom package including Android SDK components) + +### Linux desktop variant + +Same as web plus: +- `gtk+3.0` runtime libs (from Wolfi, or custom melange package if not available) +- `flutter-sdk-linux@local` + +## melange Package Definitions + +### flutter-sdk-web.melange.yaml (example structure) + +```yaml +package: + name: flutter-sdk-web + version: 3.38.9 + epoch: 0 + description: Flutter SDK for Web/WASM builds (compiled from source) + +environment: + contents: + packages: + - build-base + - git + - python3 + - curl + - unzip + - xz + - clang + - ninja + - gn + +pipeline: + - uses: git-checkout + with: + repository: https://github.com/flutter/flutter.git + tag: ${{package.version}} + destination: flutter + + - runs: | + # Bootstrap Dart SDK + flutter/bin/flutter --version + + # Configure for web-only + flutter/bin/flutter config --enable-web \ + --no-enable-android --no-enable-ios \ + --no-enable-linux-desktop --no-enable-macos-desktop \ + --no-enable-windows-desktop + + # Precache web artifacts + flutter/bin/flutter precache --web \ + --no-android --no-ios --no-linux \ + --no-macos --no-windows --no-fuchsia --no-universal + + # Install to package destination + mkdir -p ${{targets.destdir}}/opt + mv flutter ${{targets.destdir}}/opt/flutter + + # Mark git safe directory + git config --global --add safe.directory /opt/flutter +``` + +## Implementation Phases + +### Phase 1: Proof of Concept (web variant only) + +1. Install melange and apko locally +2. Write `flutter-sdk-web.melange.yaml` to package Flutter SDK +3. Build the APK: `melange build flutter-sdk-web.melange.yaml` +4. Write `apko.web.yaml` to compose the final image +5. Build the image: `apko build apko.web.yaml flutter-sdk-web:test flutter-sdk-web.tar` +6. Load and test: `docker load < flutter-sdk-web.tar` +7. Verify: `docker run --rm flutter-sdk-web:test flutter doctor -v` +8. Compare image size vs current debian:bookworm-slim approach + +### Phase 2: CI Pipeline + +1. Add melange + apko build steps to publish.yaml +2. Multi-stage: melange builds APK → apko composes image → push to registry +3. Scout CVE scan on the final image +4. SBOM generation (apko generates SBOMs natively) + +### Phase 3: Android + Linux Desktop Variants + +1. Write melange packages for Android SDK components +2. Write apko YAML for Android variant (add JDK from Wolfi) +3. Write apko YAML for Linux variant (add GTK3 from Wolfi) +4. Test each variant with real Flutter project builds + +### Phase 4: Automated Updates + +1. Daily update-check detects new Flutter stable release +2. Triggers melange rebuild of Flutter SDK package +3. apko recomposes image with latest Wolfi packages (picks up CVE fixes) +4. Push new images to registry + +## Expected Image Sizes + +| Variant | Current (debian:bookworm-slim) | Target (Wolfi/apko) | +|---|---|---| +| Web | ~1.8 GB | ~1.2-1.4 GB | +| Android | ~3.5 GB | ~2.5-3.0 GB | +| Linux | ~2.2 GB | ~1.5-1.8 GB | + +Note: Flutter SDK itself is ~1+ GB regardless of base. The savings come from the base OS layer (74 MB debian-slim → ~14 MB Wolfi base) and elimination of build-time packages. + +## File Structure (Target) + +``` +docker-flutter-sdk/ +├── melange/ +│ ├── flutter-sdk-web.melange.yaml +│ ├── flutter-sdk-android.melange.yaml +│ └── flutter-sdk-linux.melange.yaml +├── apko/ +│ ├── web.apko.yaml +│ ├── android.apko.yaml +│ └── linux.apko.yaml +├── Dockerfile # Fallback: current debian approach (web) +├── Dockerfile.android # Fallback: current debian approach (android) +├── Dockerfile.linux # Fallback: current debian approach (linux) +├── .gitea/ +│ └── workflows/ +│ ├── publish.yaml # Build with melange+apko, push to registry +│ ├── publish-dockerfile.yaml # Fallback Dockerfile builds +│ ├── scout.yaml +│ └── update-check.yaml +└── PLAN.md +``` + +## Risks and Mitigations + +| Risk | Mitigation | +|---|---| +| GTK3 dev libs not in Wolfi | Fall back to Dockerfile.linux with debian-slim for that variant | +| Flutter engine source build is complex | Start with packaging prebuilt SDK, graduate to source build | +| melange/apko learning curve | Well-documented by Chainguard, active community | +| Wolfi package availability changes | Pin package versions, maintain fallback Dockerfiles | +| Build times for source compilation | Cache melange build artifacts, only rebuild on new Flutter release | + +## Dependencies + +- melange CLI: `go install chainguard.dev/melange@latest` +- apko CLI: `go install chainguard.dev/apko@latest` +- Docker (for testing) +- Signing key pair (for APK package signing) + +## References + +- [Wolfi Overview](https://edu.chainguard.dev/open-source/wolfi/overview/) +- [Getting Started with apko](https://edu.chainguard.dev/open-source/build-tools/apko/getting-started-with-apko/) +- [Getting Started with melange](https://edu.chainguard.dev/open-source/build-tools/melange/getting-started-with-melange/) +- [Flutter Engine Build Instructions](https://github.com/flutter/flutter/wiki/Compiling-the-engine) +- [wolfi-dev/os packages](https://github.com/wolfi-dev/os)