Minimalist, high-performance Docker images for Android CI/CD pipelines. Based on Alpaquita Linux1 (glibc) and BellSoft Liberica JDK2. Optimized with mimalloc3 for maximum build speed and reduced memory footprint. Self-updating via Renovate automerge.
Images are published to both Docker Hub and GHCR:
docker pull g00fy2/alpaquita-android:latestdocker pull ghcr.io/g00fy2/alpaquita-android:latestTip
Available images and their content are listed in the latest GitHub Release.
- Faster builds -
glibc(via Alpaquita Linux) avoids the performance overhead of Alpine'smusl, and Microsoft'smimallocallocator speeds up the Kotlin Daemon and parallel Gradle workers. - Always current - Renovate tracks Google's official Android SDK repositories directly and auto-merges updates (including minor platform revisions) as soon as they're released - no manual lag.
- Minimal & secure - Only the OS packages and SDK components needed for the respective image are included, keeping the image small and the attack surface low. The build image stays around ~400 MB compressed.
- Reproducible - All core components and base images are strictly pinned for deterministic CI/CD builds.
- K8s/OpenShift-ready - Follows the OpenShift GID 0 pattern for
/opt/android/sdkand/opt/android/user, so the container runs under any non-root UID as long as it stays in group 0.
Important
NDK & CMake: - Not pre-installed, to keep the image lean, but automatically downloaded by the Android Gradle Plugin the first time your project needs them.
Android Emulator: - Headless emulator image for instrumented tests and Baseline Profile generation. Runs as a sidecar next to the build container and needs KVM (/dev/kvm) on the host for usable performance. Minimal runtime: Alpaquita glibc plus only the libraries the emulator and adb need, no JDK, bash, curl or git.
The matrix always covers the three most recent stable major Android API levels, each paired with JDK 26, 25, and 21. When Google ships a new major API level, it's added at the top and the oldest one drops off; minor SDK and platform revisions roll forward automatically, no separate action needed.
| Android API | Platform version | Java versions | Example tags |
|---|---|---|---|
| 37 (latest) | 37.1 / 37.0 |
JDK 26 / 25 / 21 | android-37.1-jdk26 β¦ android-37.0-jdk21 |
| 36 | 36.1 / 36 |
JDK 26 / 25 / 21 | android-36.1-jdk26 β¦ android-36-jdk21 |
| 35 | 35 |
JDK 26 / 25 / 21 | android-35-jdk26 β¦ android-35-jdk21 |
- Rolling tags -
android-<api>-jdk<java>- always point to the latest build for that API/JDK combo. - Immutable tags -
android-<api>-jdk<java>-v<year>.<release>.<patch>- pinned forever, for production use. latest- newest stable API level combined with the highest supported Java version.
The image includes android-tools to configure SDK behavior at runtime. To opt out of Android CLI metrics collection, execute the command once in your pipeline after $HOME is set:
android-tools disable-metricsThis makes sure --no-metrics exists inside ~/.androidrc.
Only the bare minimum of OS packages and SDK components needed for each image is pre-installed, keeping download size, disk usage and attack surface small. Missing a package your pipeline needs? Open an issue.
The emulator image only runs the emulator and adb. Build tooling belongs in the build image.
Custom datasources track Google's official Android SDK repo structure directly, including minor revision bumps, and automerge any update that passes the automated smoke tests.
Every image runs a smoke test (assembling a real Android test project inside the container for the build image, booting the emulator for the emulator image), gets scanned for vulnerabilities with Trivy, and audited layer-by-layer with Dive. Compressed size of the build image lands around 400 MB (zstd level 9).
Letting AGP pick buildToolsVersion (Google's default) can cause issues in CI: it's hardcoded into AGP and often lags behind, so you miss recent fixes in bundled tools like the aidl compiler or aapt2, and AGP falls back to scanning the runner environment, which can behave unpredictably. Pinning the latest version avoids that.
ANDROID_HOME (/opt/android/sdk) holds the fixed SDK installation; GRADLE_USER_HOME and the Android user config live under the separate /opt/android/user path, which works the same no matter which user runs the container. That split makes it simple to mount just the user/cache directory as a persistent volume (Kubernetes, GitLab CI) without touching the SDK itself.
Many enterprise platforms don't allow containers to run as root or with a static non-root UID. This image follows the OpenShift GID 0 pattern for its toolchain paths (/opt/android/sdk and /opt/android/user): those directories are readable/writable/executable by the root group (GID 0), so the container works under any UID that stays in group 0 (OpenShift's default).
The contents of this repository (Dockerfiles, scripts, workflows and documentation) are licensed under the MIT License.
The published Docker images additionally contain third-party software that is not covered by the MIT License and remains subject to its own license terms:
| Component | License |
|---|---|
| Android SDK (platforms, build-tools, platform-tools, cmdline-tools) | Android Software Development Kit License Agreement |
| Android Emulator and system images (emulator variant) | Android Software Development Kit License Agreement |
| Liberica JDK | GPL-2.0 with Classpath Exception, see BellSoft |
| Alpaquita Linux and OS packages | Various, see Alpaquita Linux and the package metadata inside the image |
| mimalloc | MIT |