Repository navigation
Description
TL;DR: Have chisel cut --arch map/normalize BuildKit supplied platform ARGs to the appropriate --arch value, making cross-platform builds much simpler with docker build --platform (which is commonly used on GH CI with docker/build-push-action):
# Creating a container driver for Buildx to build with:
docker buildx create --name=container --driver=docker-container --bootstrap --use
# Now we can build multiple platforms concurrently:
docker buildx build \
--builder=container \
--platform=linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le \
--tag localhost/testssl \
.Problem and workarounds
Using chisel to get packages for a different arch is fairly simple with chisel cut --arch (provided you know what the supported architecture values look like, otherwise for the unfamiliar there's ab it more legwork to search that up).
However, I recently looked into building a multi-arch image with Chisel beyond the common amd64/arm64 archs, and encountered a few points of friction.
While chisel cut --arch maps to the same archs that Ubuntu repos use:
-
The GH Releases omit several of those archs, so you cannot pull from there for a convenient executable when building non-native arch images by using
TARGETARCHwith the defaultdocker buildbehaviour emulating that target arch.# NOTE: This will be redundant once an official chisel image is released: FROM alpine AS chisel ARG CHISEL_VERSION=1.1.0 ARG TARGETARCH ARG CHISEL_RELEASE="https://github.com/canonical/chisel/releases/download/v${CHISEL_VERSION}/chisel_v${CHISEL_VERSION}_linux_${TARGETARCH}.tar.gz" RUN wget -qO - "${CHISEL_RELEASE}" | tar -xz --no-same-owner -C /usr/local/bin chisel
While this is typically slower, it does infer the platform arch emulated for
chisel cut, removing any need for an explicit--arch. That's useful because of the next point.. -
chisel cut --archdoes not mapTARGETARCH(or relatedARGfrom BuildKit) to the repo architectures expected / supported.TARGETARCHcan bearm, which matches the GH release arch. But that is presumablyarmhf(arm/v7), since unlike Debian, Ubuntu only has support for that arch. The legacyarmel(arm/v6) would still bearmforTARGETARCH, you need to pair it withTARGETVARIANTto get thev7vsv6distinction. Regardless, theseARGvalues do not match theaptrepo arch, so some logic is now required to map between the two.Similar story for
ppc64le=>ppc64eland386=>i386.So we end up with something like this:
-
Use
--platform=${BUILDPLATFORM}to only use a base image native to your build host for all targets, and likewise only pull a compatible binary for that (BASEARCHinstead ofTARGETARCH) which won't be required once there is an official chisel image.# NOTE: This will be redundant once an official chisel image is released: FROM --platform=${BUILDPLATFORM} alpine AS chisel ARG CHISEL_VERSION=1.1.0 ARG BUILDARCH ARG CHISEL_RELEASE="https://github.com/canonical/chisel/releases/download/v${CHISEL_VERSION}/chisel_v${CHISEL_VERSION}_linux_${BUILDARCH}.tar.gz" RUN wget -qO - "${CHISEL_RELEASE}" | tar -xz --no-same-owner -C /usr/local/bin chisel
-
Map platforms to package arch:
# Workaround - Performance improvement (avoid emulation for non-native image builds) # Map TARGETPLATFORM from BuildKit to equivalent input for `chisel cut --arch`: FROM --platform=${BUILDPLATFORM} alpine AS chisel-arch-target ARG TARGETPLATFORM RUN <<HEREDOC case "${TARGETPLATFORM}" in ( 'linux/amd64' ) echo 'amd64' > /target-arch.txt ;; ( 'linux/arm64' ) echo 'arm64' > /target-arch.txt ;; ( 'linux/arm/v7' ) echo 'armhf' > /target-arch.txt ;; ( 'linux/arm/v6' ) # NOTE: This presumably isn't reliable and should be `armel` (if Ubuntu supported it): echo 'armhf' > /target-arch.txt ;; ( 'linux/386' ) echo 'i386' > /target-arch.txt ;; ( 'linux/ppc64le' ) echo 'ppc64el' > /target-arch.txt ;; ( * ) echo "ERROR: Unsupported target platform: '${TARGETPLATFORM}'" return 1 ;; esac HEREDOC
or alternatively:
# The suffix matches TARGETARCH + TARGETVARIANT # TARGETPLATFORM is not valid in the stage name due to presence of `/` FROM chisel AS chisel-amd64 ENV CHISEL_ARCH=amd64 FROM chisel AS chisel-arm64 ENV CHISEL_ARCH=arm64 FROM chisel AS chisel-armv7 ENV CHISEL_ARCH=armhf FROM chisel AS chisel-armv6 ENV CHISEL_ARCH=armel FROM chisel AS chisel-386 ENV CHISEL_ARCH=i386 FROM chisel AS chisel-ppc64le ENV CHISEL_ARCH=ppc64el
-
Have
chisel cut --archaccess that arch value from/target-arch.txt:# Prepare root-fs with required packages: FROM chisel AS root-fs COPY --link --from=chisel-arch-target /target-arch.txt /target-arch.txt WORKDIR /root-fs RUN --mount=type=cache,target=/.cache/chisel,id="chisel-cache" \ chisel cut --arch "$(cat /target-arch.txt)" --release ubuntu-24.04 --root /root-fs \ base-files_base bash_bins
or with alternative pulling in the appropriate stage for the correct
CHISEL_ARCHENV:# Prepare root-fs with required packages: FROM chisel-${TARGETARCH}${TARGETVARIANT} AS root-fs WORKDIR /root-fs RUN --mount=type=cache,target=/.cache/chisel,id="chisel-cache" \ chisel cut --arch "${CHISEL_ARCH?arch-required}" --release ubuntu-24.04 --root /root-fs \ base-files_base bash_bins
-
You can now build for i386 (and for armhf & ppc64el more performantly), but it's awkward (I don't personally need this, but the referenced project was reluctant to drop supporting it).
This is something that could be improved on, so that examples like I showed here would work as intended without that mapping workaround demonstrated above.
chisel cut --arch should ideally recognize TARGETPLATFORM and TARGETARCH to normalize/map to the equivalent --arch value supported, or fail early when that is not a valid/supported arch (if possible). Should chisel support alternative distros/repos like Debian or Fedora, this may be less straight-forward and need some config support at that point to support specifying the appropriate mappings?
Raspbian apparently considers armhf as arm/v6, I've also seen on DockerHub where Debian and openSUSE Leap images archs differ a bit, linux/arm seems to resolve to the lowest supported variant, so if both armv6 and armv7 are published you'd get armv6 (openSUSE Leap is known for this with 15.5 at least), Debian I've seen only publishes linux/arm/v5 and linux/arm/v7, where pulling a linux/arm/v6 gets you the linux/arm/v5 platform image (which Raspbian also considers as armel).
Activity
cjdcordeiro commentedon May 6, 2025
Hi @polarathene
thanks for the detailed description.
Currently: Chisel's
--archexpects deb archs, while the Chisel GH releases are names after Go archsI don't think this would change. We want the UX to be deb-derived, and the TARGETARCH is based on Go archs. So, you can actually use TARGETARCH to download the Chisel releases from GitHub.
I think I'm missing context on the user story that you're aiming for here. Let me try to depict a few different flows, and their implications
1.
chisel cutfor arch xyz, from a xyz Deb build environment, without buildkit (i.e TARGETARCH)Since it's a Deb build environment, we can rely on
arch="$(dpkg --print-architecture | sed -e 's/armhf/arm/g' -e 's/ppc64el/ppc64le/g')"to get the Go arch string that we'll use to download the GH release.2.
chisel cutfor arch xyz, from a xyz NON-Deb build environment, without buildkit (i.e TARGETARCH)This will be very distro-specific, but one might indeed need a custom mapping. Another option is to rely on Golang, if installed in the system, e.g. use
go env GOARCHto determine the arch string to use when downloading the Chisel GH release.3.
chisel cutfor arch xyz, from a xyz multi-arch build environment, WITH buildkit (i.e TARGETARCH)Just rely on TARGETARCH. E.g.
"https://github.com/canonical/chisel/releases/download/v${CHISEL_VERSION}/chisel_v${CHISEL_VERSION}_linux_${TARGETARCH}.tar.gz"4.
chisel cutfor a foreign arch (i.e. an architecture that is different from the build env's)4.1 without buildkit (i.e TARGETARCH)
This is the trickiest case, cause you'll need to know the deb arch you're aiming for, as well as its Go counterpart for downloading the Chisel GH release. So some sort of custom mapping is indeed necessary.
4.2 WITH buildkit (i.e TARGETARCH)
In this case, you still need some sort of Go-2-deb mapping, but we know that these arch strings only change in a few cases. This is the snippet you provided above, but simplified to cover only the diffs we know and support:
I hope I captured the most common use cases. Is your use case different from these? If not, apart from 4.1, all the others seem quite low effort.
And yes, in a container context, all of this becomes easier with a Chisel container (fyi, an unofficial image in WIP: https://github.com/rockcrafters/chisel-rock by @rebornplusplus)
polarathene commentedon Jun 17, 2025
Apologies for the delayed response. I somehow missed the notification.
I am aware of this now, but I do recall losing time trying to lookup the deb arch values and get that working properly for the more niche archs.
I don't think it's called "Go arch" specifically? (I know it's the arch convention Go uses, but it's not the only one to use that convention)
The deb archs was a bit more effort to grok and acquire a list / mapping of. If Chisel will not add support mapping/normalizing archs for
--arch(or via some other flag/option/ENV), it would be helpful to document the supported archs that--archexpects.uname -mbeing the two most common arch conventions.I mean yeah that kinda works? But I'd also assume Chisel being container oriented will see more use in other build environments.
Is this debian build environment specific workaround officially documented, or do users need to find it through search? (or like in my case, think of more potable alternatives)
You'll still have very slow builds in comparison to native arch cutting foreign archs (when using CI to build for multiple archs), but when
sedis available it could be leveraged for that too with buildkit.I don't know why this needs to be complicated? Platforms aren't likely to vary much here. If that's a concern, a file mapping could be used and one could be embedded by default (or similar internal code as fallback).
The point is it should not need to be distro specific. Even if chisel were to support other distros in the far future (beyond Ubuntu slices), that
--archoption may take different values for equivalent archs, but common mapping/normalization logic for the intended arch would effectively be the same.It'd be much better (and portable) for UX for chisel to have the functionality to do such a mapping internally (even if that invokes a separate flag like
--from-go-arch).One of the first points I mentioned in my issue description was that GH releases does not cover all supported
--arch:You are missing
386and AFAIK thearmvariant isarmhf, there is noarmel.At the end of my issue description I note how
armhf/armeldiffers for different debian distros. I also note with respect to DockerHub base images published that this is inconsistent and thus care needs to be taken when bringing inarmimage variants that aren'tarm64.All of those concerns can be avoided however by only using the image for your native build host (likely AMD64/ARM64) and providing chisel with
--archwith correct mapping normalization in place. Not only is the much nicer and simpler to work with, but it is considerably faster than running emulated builds for non-native archs through QEMU.It doesn't matter that only a subset changes, you still need to be consistent in the usage? (reading the arch in from a text file or ENV)
polarathene commentedon Jun 17, 2025
Is that published anywhere? It has had no activity since Oct 2024 and remains a draft PR: rockcrafters/chisel-rock#1
The author has commented in Feb 2025 in the related chisel discussion for an official image: #203 (comment)
Another user shared their own attempt at a chisel image and I provided feedback there, and earlier my own feedback on the topic with example
Dockerfiles. I'll likely get around to just building and publishing my own Chisel image once some of my concerns are better addressed with improving Chisel.As Chisel is not the only tool I run into issues with regarding mapping arch conventions from one to another, I'll probably just build a static binary that can do this on-demand.
This issue was mainly to raise awareness of the UX problems related to Chisel with a real-world example (
testssl.sh) where this added a fair amount of friction when looking into using Chisel.cjdcordeiro commentedon Jun 20, 2025
Hi, no worries. Some quick remarks:
please keep in mind that Chisel isn't a container tool. Yes, is has been extremely useful for container builds, but at its core, it creates Ubuntu filesystems, that you can then package in any format you'd like, not just OCI.
That's precisely what I mean - a mapping. Nothing complicated.
In this case you'd just be shifting the architecture mapping into Chisel's codebase, which although possible, it would become a can of worms, as a single architecture can have a growing number of different notations if considering different environments/distros. The risk/benefit ratio isn't justified IMO, as the cost of doing said mapping outside Chisel is a very low. The bottom line is that Chisel works with Ubuntu packages, and for those, we rely on the debian architecture notation.
Indeed we don't build for 386 (intentionally). That also applied to our container images in Docker Hub.
In GitHub releases, we name the artifacts after the GOARCH, so
armhf(the arm 32bit arch that we support) becomesarm(we don't take into account theGOARMvalue for naming the GH release assets).It hasn't. Atm Chisel is delivered through GH releases and Snap Store.
Thanks for the detailed discussion.
Given it's length, let me try to create an oversimplified summary for future reference:
Summary
Today, Chisel offers a UX that is designed to rely on the host to infer the target Ubuntu Release and Architecture to install slices from.
For those running on a non-Debian distro, Chisel offers 2 CLI options:
--releaseand--archto allow users enough flexibility to compensate for the lack of system data such as/etc/lsb-release(which Chisel relies on to infer the chisel-release).At the same time, Chisel is not a container specific tool, so it hasn't been designed to dynamically work with things like
TARGETARCH.The above also applies to the naming convention we use in the GitHub releases (based on GOARCH). In this case, users who consume Chisel from a GitHub release may need to manually map their working architecture into GOARCH in order to download the right binary from GitHub. We may be able to improve this experience though:
For cases where the GH release is being used, we don't have any short term plans to embed any sort of custom cross-distro architecture mapping into Chisel.
fyi @letFunny
polarathene commentedon Jun 21, 2025
Cheers for the clarification. My mistake regarding Chisel as container image oriented, I must be recalling some Canonical blog posts I came across when first hearing about it that were focused on building OCI images and comparing to alternative images 😅
I think it'd be nice to make progress towards an official Chisel image, is there an outline for any blockers regarding that or just a lower priority to allocate time towards over existing tasks for Chisel? (I understand that there are still some UX improvements that could be done to make using Chisel less verbose, beyond what this issue discusses)
I'll close this issue as there isn't that much actionable for Chisel beyond acquiring a release.
I've only come across one project (
testssl.sh) that wanted to retain support for what are now niche archs, and in their case several packages are lacking slices (which I have opened issues for and implemented myself), yet the final image for that project was effectively the same size as their existing openSUSE Leap image at 54MB (while the Alpine variant is 27MB).. so they have little incentive to switch given all that added friction without any benefits.Thanks for the detailed responses ❤