Installing distribution packages during mender-convert

When converting images with mender-convert, you may need to pre-install packages from the distribution’s repositories. This tutorial demonstrates how to install packages during the conversion process using a configuration fragment.

The Challenge

The mender-convert tool operates in a chroot environment when modifying the rootfs. Direct package installation requires proper chroot setup, especially for cross-architecture builds where qemu-static emulation is needed.

Creating the Configuration Fragment

Create a configuration file that hooks into the platform modification phase:

cat > input/package_install_config << 'EOF'
# Configuration to install packages from distribution repositories during conversion

# Define packages to install (space-separated list)
MENDER_INSTALL_PACKAGES="vim htop tmux"

function install_distribution_packages_in_chroot() {
    local -r dest_dir="$1"
    
    # Update package lists
    run_in_chroot_and_log_cmd "$dest_dir" "apt-get update"
    
    # Install packages non-interactively
    run_in_chroot_and_log_cmd "$dest_dir" "DEBIAN_FRONTEND=noninteractive apt-get install -y $MENDER_INSTALL_PACKAGES"
    
    # Clean up package cache to reduce image size
    run_in_chroot_and_log_cmd "$dest_dir" "apt-get clean"
    run_in_chroot_and_log_cmd "$dest_dir" "rm -rf /var/lib/apt/lists/*"
}

function install_distribution_packages() {
    if [ -n "$MENDER_INSTALL_PACKAGES" ]; then
        log_warn "Installing packages from distribution repository: $MENDER_INSTALL_PACKAGES"
        
        # Run package installation with proper chroot setup
        run_with_chroot_setup work/rootfs install_distribution_packages_in_chroot work/rootfs
        
        log_info "Package installation completed"
    fi
}

# Add to platform modify hooks to run during the modify phase
PLATFORM_MODIFY_HOOKS+=(install_distribution_packages)
EOF

Understanding the Implementation

The configuration uses two functions:

  1. install_distribution_packages_in_chroot - Runs inside the chroot environment with:

    • Package list updates via apt-get update
    • Non-interactive installation with DEBIAN_FRONTEND=noninteractive
    • Cache cleanup to minimize final image size
  2. install_distribution_packages - Sets up the chroot environment using run_with_chroot_setup, which handles:

    • Cross-architecture qemu-static setup
    • DNS resolution via /etc/resolv.conf
    • Proper cleanup after execution

Running the Conversion

Include the configuration fragment during conversion. This is done through the --config flag, of which you can have as many as you want.

An example for the Raspberry Pi 4 might be:

MENDER_ARTIFACT_NAME=release-1 ./docker-mender-convert \
    --disk-image input/images/2025-05-13-raspios-bookworm-arm64-lite.img \
    --config configs/raspberrypi/uboot/debian/raspberrypi4_bookworm_64bit_config \
    --config input/package_install_config

Advanced Usage

Installing from Custom Repositories

Add repository configuration before package installation:

function install_distribution_packages_in_chroot() {
    local -r dest_dir="$1"
    
    # Add custom repository
    echo "deb http://custom.repo/debian bookworm main" >> "$dest_dir/etc/apt/sources.list"
    
    # Update and install
    run_in_chroot_and_log_cmd "$dest_dir" "apt-get update"
    run_in_chroot_and_log_cmd "$dest_dir" "DEBIAN_FRONTEND=noninteractive apt-get install -y $MENDER_INSTALL_PACKAGES"
    
    # Cleanup
    run_in_chroot_and_log_cmd "$dest_dir" "apt-get clean"
    run_in_chroot_and_log_cmd "$dest_dir" "rm -rf /var/lib/apt/lists/*"
}

Conditional Package Installation

Install packages based on device type or other conditions:

function install_distribution_packages() {
    case "$MENDER_DEVICE_TYPE" in
        raspberrypi4*)
            MENDER_INSTALL_PACKAGES="vim htop wiringpi"
            ;;
        raspberrypi3*)
            MENDER_INSTALL_PACKAGES="vim nano"
            ;;
    esac
    
    if [ -n "$MENDER_INSTALL_PACKAGES" ]; then
        log_warn "Installing packages for $MENDER_DEVICE_TYPE: $MENDER_INSTALL_PACKAGES"
        run_with_chroot_setup work/rootfs install_distribution_packages_in_chroot work/rootfs
    fi
}

Troubleshooting

Common issues and solutions:

  1. Package not found: Ensure the package name matches the distribution’s repository
  2. Network errors: Docker must have internet access for package downloads
  3. Architecture mismatches: The chroot setup handles qemu emulation automatically
  4. Dependency conflicts: Use apt-get install -f to fix broken dependencies

Performance Considerations

  • Package installation adds time to the conversion process
  • Each apt-get update downloads package lists (~50MB for Raspberry Pi OS)
  • Consider creating a custom rootfs overlay for frequently used package sets
  • The package cache cleanup saves ~100-200MB per conversion