Building a Hardened, Containerized CI/CD Pipeline - 3

Phase 3: Creating and Automating the Renesas Cross-Compiler Build Image

Posted by yuanhang on June 02, 2026

To achieve truly repeatable firmware compilation, the entire compiler toolchain—including headers, specialized utility packages, and the ARM GNU Toolchain (GCC)—must be locked within an immutable, standardized Docker image.

We manage this build context in a dedicated infrastructure repository named devsecops/CI-Pipeline_CrossCompile.

The Dockerfile

This configuration optimizes layer caching, pins a stable Ubuntu baseline, installs core compilation building blocks, and strips unneeded testing suites out of the final layer to optimize size.

# Use Ubuntu 24.04 LTS minimal runtime
FROM ubuntu:24.04
# Avoid interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
# 1. Install ONLY the absolute essential tools required to run the toolchain and process Makefiles
RUN apt-get update && apt-get install -y --no-install-recommends \
    wget \
    ca-certificates \
    bzip2 \
    xz-utils \
    make \
    cmake \
    ninja-build \
    python3 \
    git \
    bc \
    gawk \
    libncurses6 \
    libncursesw6 \
    srecord \
    && rm -rf /var/lib/apt/lists/*
# 2. Download and extract the matching cross-toolchain: GCC ARM 10.3
# Using quiet mode (-q) to clean up the CI build log output
RUN wget -qO- "https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2" | tar -xj -C /opt/
# 3. Configure environment variables for the toolchain
ENV PATH="/opt/gcc-arm-none-eabi-10.3-2021.10/bin:${PATH}"
# Verify the installation structurally during the Docker build phase
RUN arm-none-eabi-gcc --version
# Standardize workspace directory for GitLab Runner execution
WORKDIR /build

Automating the Toolchain Build Lifecycle (.gitlab-ci.yml)

When changes are committed to this infrastructure repo, a pipeline builds the Docker image and seamlessly publishes it straight to our internal GitLab Container Registry.

stages:
  - build
variables:
  # Instruct Docker to communicate securely over TLS with its background service
  DOCKER_TLS_CERTDIR: "/certs"
  # Define the exact destination tag using GitLab's built-in environment variables
  IMAGE_TAG: "$CI_REGISTRY/devsecops/ci-pipeline-crosscompile/renesas-cross-compile-toolchain:v10.3"
build_toolchain:
  stage: build
  # Use the official Docker CLI image to run our commands
  image: docker:26.1
  # Spin up a background Docker service so the CLI image can talk to an engine
  services:
    - docker:26.1-dind
  before_script:
    # Safely log into your self-hosted registry using automated, built-in GitLab tokens
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    # 1. Compile the image forcing the classic layout compatibility flag we discussed
    #- docker build --provenance=false -t $IMAGE_TAG .
    - docker build -t $IMAGE_TAG .
    # 2. Upload the freshly baked image straight back to your GitLab registry
    - docker push $IMAGE_TAG