Skip to content

Commit 06d05c6

Browse files
committed
build: kernel: force target arch on cross-built kernel docker image manifest
- our kernel builds are done in arch-independent Dockerfiles - but those get the build-host's architecture, despite the contents being correct - when locally developing on a kernel that is != host-arch - those get the host-arch in the image - but LinuxKit refuses to use it due to arch mismatch - (when pushed to a registry, the arch info is discarded, and LK is ok with that) - thus - introduce `ensure_docker_image_architecture(imagetag, arch)` - which just hacks at manifests via a docker save/docker load - call it from both default and armbian kernel builds Signed-off-by: Ricardo Pardini <[email protected]>
1 parent e4c9762 commit 06d05c6

File tree

4 files changed

+75
-8
lines changed

4 files changed

+75
-8
lines changed

bash/docker.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,70 @@ function produce_dockerfile_helper_apt_oras() {
123123
DOWNLOAD_HELPER_SCRIPT
124124
log debug "Created apt-oras helper script '${fn}'"
125125
}
126+
127+
# A huge hack to force the architecture of a Docker image to a specific value.
128+
# This is required for the LinuxKit kernel images: LK expects them to have the correct arch, despite the
129+
# actual contents always being the same. Docker's buildkit tags a locally built image with the host arch.
130+
# Thus change the host arch to the expected arch in the image's manifests via a dump/reimport.
131+
function ensure_docker_image_architecture() {
132+
declare kernel_oci_image="$1"
133+
declare expected_arch="$2"
134+
135+
# If the host arch is the same as the expected arch, no need to do anything
136+
if [[ "$(uname -m)" == "${expected_arch}" ]]; then
137+
log info "Host architecture is already ${expected_arch}, no need to rewrite Docker image ${kernel_oci_image}"
138+
return 0
139+
fi
140+
141+
log info "Rewriting Docker image ${kernel_oci_image} to architecture ${expected_arch}, wait..."
142+
143+
# Create a temporary directory, use mktemp
144+
declare -g tmpdir
145+
tmpdir="$(mktemp -d)"
146+
log debug "Created temporary directory: ${tmpdir}"
147+
148+
# Export the image to a tarball
149+
docker save -o "${tmpdir}/original.tar" "${kernel_oci_image}"
150+
151+
# Untag the hostarch image
152+
docker rmi "${kernel_oci_image}"
153+
154+
# Create a working dir under the tmpdir
155+
mkdir -p "${tmpdir}/working"
156+
157+
# Extract the tarball into the working dir
158+
tar -xf "${tmpdir}/original.tar" -C "${tmpdir}/working"
159+
log debug "Extracted tarball to ${tmpdir}/working"
160+
161+
# Remove the original tarball
162+
rm -f "${tmpdir}/original.tar"
163+
164+
declare working_blobs_dir="${tmpdir}/working/blobs/sha256"
165+
166+
# Find all files under working_blobs_dir which are smaller than 2048 bytes
167+
# Use mapfile to create an array of files
168+
declare -a small_files
169+
mapfile -t small_files < <(find "${working_blobs_dir}" -type f -size -2048c)
170+
log debug "Found small blob files: ${small_files[*]}"
171+
172+
# Replace the architecture in each of the small files
173+
for file in "${small_files[@]}"; do
174+
log debug "Replacing architecture in ${file}"
175+
sed -i "s|\"architecture\":\".....\"|\"architecture\":\"${expected_arch}\"|g" "${file}" # 🤮
176+
done
177+
178+
# Create a new tarball with the modified files
179+
tar -cf "${tmpdir}/modified.tar" -C "${tmpdir}/working" .
180+
log debug "Created modified tarball: ${tmpdir}/modified.tar"
181+
182+
# Remove the working directory
183+
rm -rf "${tmpdir}/working"
184+
185+
# Import the modified tarball back into the local cache
186+
docker load -i "${tmpdir}/modified.tar"
187+
188+
# Remove the temporary directory, completely
189+
rm -rf "${tmpdir}"
190+
191+
log info "Rewrote Docker image ${kernel_oci_image} to architecture ${expected_arch}."
192+
}

bash/kernel.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function kernel_build() {
3333
log debug "Kernel build method: ${kernel_info[BUILD_FUNC]}"
3434
"${kernel_info[BUILD_FUNC]}"
3535

36-
# Push it to the OCI registry
36+
# Push it to the OCI registry; this discards the os/arch information that BuildKit generates
3737
if [[ "${DO_PUSH:-"no"}" == "yes" ]]; then
3838
log info "Kernel built; pushing to ${kernel_oci_image}"
3939
docker push "${kernel_oci_image}"

bash/kernel/kernel_armbian.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ function calculate_kernel_version_armbian() {
2525
ARMBIAN_KERNEL_MAJOR_MINOR_POINT="$(echo -n "${ARMBIAN_KERNEL_VERSION}" | cut -d "-" -f 1)"
2626
log info "ARMBIAN_KERNEL_MAJOR_MINOR_POINT: ${ARMBIAN_KERNEL_MAJOR_MINOR_POINT}"
2727

28-
2928
# A helper script, as escaping bash into a RUN command in Dockerfile is a pain; included in input_hash later
3029
declare dockerfile_helper_filename="undefined.sh"
3130
produce_dockerfile_helper_apt_oras "kernel/" # will create the helper script in kernel/ directory; sets helper_name
@@ -99,8 +98,10 @@ function build_kernel_armbian() {
9998
log info "Building armbian kernel from deb-tar at ${ARMBIAN_KERNEL_FULL_ORAS_REF_DEB_TAR}"
10099
log info "Will build Dockerfile ${ARMBIAN_KERNEL_DOCKERFILE}"
101100

102-
# Build the Dockerfile; don't specify platform, our Dockerfile is multiarch, thus you can get build x86 kernels in arm64 hosts and vice-versa
101+
# Don't specify platform, our Dockerfile is multiarch, thus you can build x86 kernels in arm64 hosts and vice-versa ...
103102
docker buildx build --load "--progress=${DOCKER_BUILDX_PROGRESS_TYPE}" -t "${kernel_oci_image}" -f "${ARMBIAN_KERNEL_DOCKERFILE}" kernel
103+
# .. but enforce the target arch for LK in the final image via dump/edit-manifests/reimport trick
104+
ensure_docker_image_architecture "${kernel_oci_image}" "${kernel_info['DOCKER_ARCH']}"
104105
}
105106

106107
function configure_kernel_armbian() {

bash/kernel/kernel_default.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,8 @@ function build_kernel_default() {
131131
common_build_args_kernel_default
132132
log info "Will build with: ${build_args[*]}"
133133

134-
(
135-
cd kernel
136-
docker buildx build --load "--progress=${DOCKER_BUILDX_PROGRESS_TYPE}" "${build_args[@]}" -t "${kernel_oci_image}" .
137-
)
138-
134+
# Don't specify platform, our Dockerfile is multiarch, thus you can build x86 kernels in arm64 hosts and vice-versa ...
135+
docker buildx build --load "--progress=${DOCKER_BUILDX_PROGRESS_TYPE}" "${build_args[@]}" -t "${kernel_oci_image}" -f kernel/Dockerfile kernel
136+
# .. but enforce the target arch for LK in the final image via dump/edit-manifests/reimport trick
137+
ensure_docker_image_architecture "${kernel_oci_image}" "${kernel_info['DOCKER_ARCH']}"
139138
}

0 commit comments

Comments
 (0)