docker: split host deps into per-group apt layers in generated Dockerfile

Instead of a single huge 'apt-get install' RUN (one giant image layer),
group host_dependencies by their 'group::' prefix and emit one RUN per
group, ordered heaviest/most-stable first. Produces multiple layers that
Docker can pull and cache in parallel. apt update is its own layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ricardo Pardini
2026-06-21 23:04:42 +02:00
co-authored by Claude Opus 4.8
parent 22aedbc49d
commit 5288f2d64e
+50 -3
View File
@@ -245,6 +245,50 @@ function docker_cli_prepare() {
display_alert "Docker info" "Docker ${DOCKER_SERVER_VERSION} Kernel:${DOCKER_SERVER_KERNEL_VERSION} RAM:${DOCKER_SERVER_TOTAL_RAM} CPUs:${DOCKER_SERVER_CPUS} OS:'${DOCKER_SERVER_OS}' hostname '${DOCKER_SERVER_NAME_HOST}' under '${DOCKER_ARMBIAN_HOST_OS_UNAME}' - buildx:${DOCKER_HAS_BUILDX} - loop-hacks:${DOCKER_SERVER_REQUIRES_LOOP_HACKS} static-loops:${DOCKER_SERVER_USE_STATIC_LOOPS}" "sysinfo"
}
# Build the per-group "apt-get install" RUN lines for the Dockerfile, so the image
# is split into multiple, parallel-pullable layers instead of one giant layer.
# Reads globals: host_dependencies[] (entries possibly "group::package") and BASIC_DEPS[].
# Arg $1 is the "${c}" comment-gate prefix used to disable the lines (SIMULATE_CLEAN/SKIP_UPDATE).
# Sets global: DOCKERFILE_APT_INSTALL_RUNS (one RUN instruction per line, no trailing newline).
function docker_create_dockerfile_apt_install_runs() {
declare comment_gate="${1}"
declare -A group_pkgs=()
declare -a groups_seen=()
declare entry group pkg
for entry in "${host_dependencies[@]}"; do
if [[ "${entry}" == *"${HOSTDEP_GROUP_DELIMITER}"* ]]; then
group="${entry%%"${HOSTDEP_GROUP_DELIMITER}"*}"
pkg="${entry#*"${HOSTDEP_GROUP_DELIMITER}"}"
else
group="${HOSTDEP_DEFAULT_GROUP}"
pkg="${entry}"
fi
[[ -z "${group_pkgs[${group}]:-}" ]] && groups_seen+=("${group}")
group_pkgs[${group}]+="${pkg} "
done
# Preferred layer order: heaviest/most-stable first, so they stay cached longest.
# Any unknown (e.g. extension-defined) group is appended after, in first-seen order.
declare -a preferred_order=(clang cross-arm cross-other emulation imaging native-toolchain build-tools python fs-tools compression core)
declare -a final_order=()
for group in "${preferred_order[@]}"; do
[[ -n "${group_pkgs[${group}]:-}" ]] && final_order+=("${group}")
done
for group in "${groups_seen[@]}"; do
[[ " ${final_order[*]} " == *" ${group} "* ]] || final_order+=("${group}")
done
declare runs=""
# BASIC_DEPS first, as their own small layer.
runs+="${comment_gate}RUN echo \"--> apt group: basic\" && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ${BASIC_DEPS[*]}"$'\n'
for group in "${final_order[@]}"; do
runs+="${comment_gate}RUN echo \"--> apt group: ${group}\" && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ${group_pkgs[${group}]}"$'\n'
done
declare -g DOCKERFILE_APT_INSTALL_RUNS="${runs%$'\n'}" # strip trailing newline
}
function docker_cli_prepare_dockerfile() {
# @TODO: grab git info, add as labels et al to Docker... (already done in GHA workflow)
@@ -308,13 +352,16 @@ function docker_cli_prepare_dockerfile() {
c_req=""
fi
# Group the host dependencies by their "group::" prefix into separate apt-get install
# RUN instructions, so the resulting image has multiple parallel-pullable layers.
docker_create_dockerfile_apt_install_runs "${c}" # sets DOCKERFILE_APT_INSTALL_RUNS
cat <<- INITIAL_DOCKERFILE > "${SRC}"/Dockerfile
${c}# PLEASE DO NOT MODIFY THIS FILE. IT IS AUTOGENERATED AND WILL BE OVERWRITTEN. Please don't build this Dockerfile yourself either. Use Armbian ./compile.sh instead.
FROM ${DOCKER_ARMBIAN_BASE_IMAGE}
${c}# PLEASE DO NOT MODIFY THIS FILE. IT IS AUTOGENERATED AND WILL BE OVERWRITTEN. Please don't build this Dockerfile yourself either. Use Armbian ./compile.sh instead.
${c}RUN echo "--> CACHE MISS IN DOCKERFILE: apt packages." && \\
${c} DEBIAN_FRONTEND=noninteractive apt-get -y update && \\
${c} DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ${BASIC_DEPS[@]} ${host_dependencies[@]}
${c}RUN echo "--> CACHE MISS IN DOCKERFILE: apt update." && DEBIAN_FRONTEND=noninteractive apt-get -y update
${DOCKERFILE_APT_INSTALL_RUNS}
${c}# Use C.UTF-8 locale which is available in rootfs from the very first command
WORKDIR ${DOCKER_ARMBIAN_TARGET_PATH}
ENV ARMBIAN_RUNNING_IN_CONTAINER=yes LANG=C.UTF-8