Build Android 15 AOSP with Jenkins and Docker on an SSH Connected Agent

This guide walks you through setting up a Jenkins pipeline to build AOSP 15 using Docker on a remote SSH-connected agent.

It builds on the base Docker setup from:
Build Android 15 AOSP with Docker on Ubuntu 24.04


Why Jenkins + Docker for AOSP?

Using Jenkins to drive your AOSP builds in Docker gives you:

  • Fully reproducible, isolated build environments
  • Clean separation between infrastructure and build logic
  • Automation-friendly setup for CI/CD integration

However, making this work in Jenkins requires a few critical adjustments. This guide explains them step-by-step.


Problems Encountered and Fixes Applied

    When using the same Docker image inside Jenkins, we hit several common issues:

    ProblemFix
    ssh-keyscan not foundInstall openssh-client in the Dockerfile
    Missing repo toolDownload in the Dockerfile
    curl SSL error when downloading repoInstall ca-certificates first
    repo requires python3Install python3 in Dockerfile
    source fails in shRun sh with #!/bin/bash in the first line

    1. Prepare the Docker Image

    Create Dockerfile, save this as aosp-builder/Dockerfile:

    FROM ubuntu:24.04
    
    ENV DEBIAN_FRONTEND=noninteractive
    ENV LANG=C.UTF-8
    ENV USE_CCACHE=1
    ENV CCACHE_DIR=/ccache
    ENV CCACHE_EXEC=/usr/local/bin/ccache
    
    RUN apt-get update && apt-get install -y --no-install-recommends \
        git-core \
        gnupg \
        flex \
        bison \
        build-essential \
        zip \
        curl \
        zlib1g-dev \
        libc6-dev-i386 \
        x11proto-core-dev \
        libx11-dev \
        lib32z1-dev \
        libgl1-mesa-dev \
        libxml2-utils \
        xsltproc \
        unzip \
        fontconfig \
        rsync \
        openssl \
        openssh-client \
        python3 \
        ca-certificates \
        && apt-get clean
    
    RUN curl -Lo /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo && chmod +x /usr/local/bin/repo
    
    COPY ccache /usr/local/bin/ccache
    
    WORKDIR /workspace
    

    Build the Image

    docker build -t aosp-builder ./aosp-builder
    

    1. Set Up Jenkins Environment

    Connect a Remote Agent

    • A Linux host with Docker installed
    • Add the user to the docker group
    • Connect it as a Jenkins SSH agent
    • Label it as: ssh-agent-with-docker

    Add Gerrit Credentials, In Manage Jenkins → Credentials:

    • Kind: SSH Username with private key
    • ID: gerrit-ssh-maksonlee
    • Username: maksonlee
    • Private key: Gerrit access key

    1. Write the Jenkinsfile

    Save this as Jenkinsfile in your repo:

    pipeline {
      agent { label 'ssh-agent-with-docker' }
    
      environment {
        CCACHE_PATH = "/home/administrator/.cache/ccache"
      }
    
      stages {
        stage('Build AOSP') {
          steps {
            script {
              docker.image('aosp-builder').inside("-v ${CCACHE_PATH}:/ccache ") {
                sshagent(['gerrit-ssh-maksonlee']) {
                  sh '''#!/bin/bash
                    mkdir -p ~/.ssh
                    chmod 700 ~/.ssh
                    ssh-keyscan -p 29418 -H gerrit.maksonlee.com >> ~/.ssh/known_hosts
    
                    repo init -u ssh://maksonlee@gerrit.maksonlee.com:29418/platform/manifest -b android-15.0.0_r30
                    repo sync -c
                    
                    source build/envsetup.sh
                    lunch aosp_arm64-trunk_staging-userdebug
                    m
                  '''
                }
              }
            }
          }
        }
      }
    }
    

    How Jenkins Uses -u When Running Docker in Pipelines

    When you run code inside a Docker container in Jenkins with:

    docker.image('aosp-builder').inside {
        sh 'id'
    }
    

    Jenkins executes the container using:

    docker run -u $(id -u):$(id -g) ...
    

    This ensures that files created inside the container are owned by the Jenkins agent user, not by root. This behavior prevents common permission issues when Jenkins accesses workspace files after the container step.


    Behavior When UID:GID Doesn’t Exist in the Container

    When Jenkins executes:

    docker run -u 1001:1001 ...
    

    but the container image (e.g. aosp-builder) doesn’t define user ID 1001 or group ID 1001 in /etc/passwd or /etc/group, Docker still runs the process, but:

    Inside the Container:

    • No username is shown because there’s no entry for UID 1001.
    • The process runs with raw numeric UID:GID, which may lack:
      • A valid $HOME directory
      • Shell configuration (like .bashrc)
      • Access to files owned by standard users inside the container

    Consequences:

    • Any shell prompt or utilities that rely on a username may fail or behave oddly.
    • Your build tools (like AOSP makefiles) may fail if they assume a real user exists.
    • If a tool looks for $HOME or tries to write to ~/.cache, it may fail if $HOME is unset or points to a non-existent directory.

    Leave a Comment

    Your email address will not be published. Required fields are marked *

    Scroll to Top