GETTING STARTED
Building and Deploying Android Apps from an LXD Container: A Full Toolchain Setup on Ubuntu
By John Simiyu • jonysimiyu75@gmail.com
One of the more underrated benefits of LXD containers is how well they suit mobile app build environments. Android tooling is notoriously heavy and version-sensitive, needing a specific JDK version, a specific Android SDK build-tools revision, and a specific Gradle version pinned per project. Running this inside an isolated LXD container means your host stays clean, and you can spin up a fresh, reproducible build environment for each project without version conflicts bleeding between them.
This article walks through setting up a working Android build toolchain inside an LXD container on Ubuntu 24.04, based on a real deployment.
Why LXD for Android builds?
- Isolation: each project can have its own JDK/SDK/Gradle versions without polluting the host or other projects.
- Reproducibility: the exact same container image can be reused or cloned for a new project.
- Cleanliness: if something goes wrong, you can destroy and rebuild the container without touching your main system.
Step 1: Create or prepare the container
Start with a clean Ubuntu 24.04 LXD container:
lxc launch ubuntu:24.04 android-build
lxc exec android-build -- bash
Step 2: Install the JDK via apt
It is tempting to copy a working JDK installation from another container to save time, but this is a mistake. Apt-managed JDK installs register properly with update-alternatives, which many Android tools rely on to resolve the correct Java binary. Copying raw binaries from elsewhere tends to break that registration silently.
apt update
apt install -y openjdk-17-jdk
java -version
Step 3: Install the Android SDK
Download the command-line tools and set up the SDK directory structure:
mkdir -p /opt/android-sdk/cmdline-tools
cd /opt/android-sdk/cmdline-tools
wget https://dl.google.com/android/repository/commandlinetools-linux-XXXX_latest.zip
unzip commandlinetools-linux-XXXX_latest.zip
mv cmdline-tools latest
Set environment variables (add to ~/.bashrc or a profile script):
export ANDROID_HOME=/opt/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
Install the specific SDK components your project needs:
sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"
sdkmanager --list_installed
Step 4: Generate the Gradle wrapper (without a permanent system install)
You do not need a permanently installed Gradle binary on the container. Install a temporary copy just long enough to generate a project-specific wrapper, after which the project can drive its own Gradle version via ./gradlew:
# Download and extract Gradle temporarily
wget https://services.gradle.org/distributions/gradle-8.7-bin.zip
unzip gradle-8.7-bin.zip -d /opt/gradle-temp
# From inside your project directory:
/opt/gradle-temp/gradle-8.7/bin/gradle wrapper --gradle-version 8.7
# From now on, use:
./gradlew assembleDebug
This keeps the container lean and ties the Gradle version explicitly to the project rather than the environment, which is useful if you maintain multiple Android projects across different containers or revisit this one months later.
Step 5: Verify the full build
./gradlew assembleDebug
A successful first build should end with BUILD SUCCESSFUL. If you hit dependency resolution errors at this stage, check your settings.gradle and top-level build.gradle for conflicting repository declarations.
Cloning the environment for future projects
Once a container has a working JDK + SDK setup, you can package the SDK directory as a tarball and reuse it in a fresh container rather than repeating the download step:
# On the source container
tar -czf android-sdk.tar.gz -C /opt android-sdk
# Pull to host, then push into the new container
lxc file pull android-build/root/android-sdk.tar.gz .
lxc file push android-sdk.tar.gz new-container/root/
# On the new container
tar -xzf android-sdk.tar.gz -C /opt
Still install the JDK fresh via apt on each new container rather than copying it. The update-alternatives issue mentioned earlier applies here too.
Summary
An LXD container gives you a disposable, reproducible Android build environment that will not interfere with your host system or other projects. The core steps are: apt-install the JDK, download and configure the Android SDK command-line tools, and use a project-local Gradle wrapper rather than a system-wide Gradle install. Once set up, the SDK portion can be reused across future containers to save setup time.