Repository navigation
UX: Running chisel cut with slices as single arg? (or sourced from a file arg) #220
Description
TL;DR: Instead of providing slices via a list of args, there are some scenarios where a single arg is more convenient, be that a string of slices or a file config.
When experimenting with chisel, I noticed that I could technically set:
# NOTE: `SHELL` is not an OCI spec compatible instruction,
# thus won't work by default with Podman or other alternatives to Docker.
SHELL ["/chisel", "cut", "--release", "ubuntu-24.04", "--root", "/"]And then a RUN instruction would only be the slices. However that is presently only compatible in the JSON RUN syntax since each slice is expected as a separate arg:
# JSON syntax (separate args):
RUN ["base-files_base", "bash_bins"]
# SHELL syntax (string):
RUN base-files_base bash_bins
# Equivalent to JSON syntax:
RUN ["base-files_base bash_bins"]This fails as chisel will see that as a single slice (although I don't think spaces would be valid in a slice name?). Perhaps with a single arg for the slices it could split that into the actual slices? Or a delimiter like , could be supported?
Another option would be to source the slices via a separate config file instead of as CLI args?
- This file could contain other CLI args such as the release channel, install root, and opt-in/out of Ubuntu Pro, etc.
- It could also technically group slices by their suffix, such as a list of slices under
base:likebase-files, andbins:likebash, which might be nicer/practical than the repetitive slice suffixes?
I thought this concern was worth seeking some feedback on, as it might be nice to support running chisel without requiring a shell as demonstrated below in the reference section.
When I initially opened this report I had a misunderstanding that I couldn't use a shell for --root / on FROM scratch, requiring instead --root /root-fs (and the creation of that location, plus another stage in the build to copy from /root-fs to /). That was a user error on my part as I had mounted Nushell to /bin/nu instead of /usr/bin/local/nu.
Reference
Base image to use chisel from
Ideally in future there would be an official chisel image instead of extra steps to acquire the binary to run chisel:
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"
# NOTE: `--no-same-owner` used as `chisel` release has ownership of `1001:128`
RUN wget -qO - "${CHISEL_RELEASE}" | tar -xz --no-same-owner -C /usr/local/bin chiselFROM scratch + Shell
Here's one way to then run with chisel on a scratch base (this is ok, the issue was originally created before I realized this approach also worked with --root /):
FROM scratch
ENV XDG_CACHE_HOME=/cache
SHELL ["/usr/local/bin/nu", "-c"]
RUN --mount=type=cache,target=${XDG_CACHE_HOME}/chisel,id="chisel-cache" \
--mount=type=bind,from=chisel,source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt \
--mount=type=bind,from=chisel,source=/usr/local/bin/chisel,target=/chisel \
--mount=type=bind,from=ghcr.io/nushell/nushell,source=/usr/bin/nu,target=/usr/local/bin/nu \
/chisel cut --release ubuntu-24.04 --root / \
base-files_base bash_bins procps_bins grep_bins gawk_bins sed_bins coreutils_bins busybox_bins openssl_bins curl_binsNOTES:
/etc/ssl/certs/ca-certificates.crt(or similar) is required.- This location is not configurable like some other tools (eg:
curl) offer, perhaps it should be? (or better,chiselcould embed a fallback? This file is about 220KB on Alpine) - If this
ca-certificates.crtfile would be modified bychiseldue to slices installed, a bind mount here is probably not appropriate, you'd need an earlierCOPYinstead and lose some image weight efficiency (fallback or alternative path would avoid this concern).
- This location is not configurable like some other tools (eg:
- Nushell has been used as the shell instead of
bash, only because this easily allows for a shell that works onscratchas it's a single self-contained binary likechisel.- While Nushell could use additional commands, note that
\cannot be used for multi-line splitting (valid for bash) if providingRUNa HereDoc string (multi-line input, akin to an actual script, which then encodes the\as part of that string, not as part of theRUNinstruction itself that is parsed). Hence additional commands in the sameRUNrequire familiarity with Nushell's syntax differences from Bash (&&=>;,\=>(...)).
- While Nushell could use additional commands, note that
- If not using
--root /withscratch,WORKDIR /root-fs+--root /root-fsor similar would be required aschiseldoes not yet create the--rootlocation when it doesn't exist. A separate stage to then copy/root-fsto/would be required aschiselmay fail when existing base image conflicts (such as an existing/binthat would otherwise be symlinked to/usr/bin).
FROM scratch without a shell
Alternatively, a shell can be avoided by using the RUN JSON syntax (tad awkward, but avoids running via defined SHELL):
FROM scratch
ENV XDG_CACHE_HOME=/cache
RUN --mount=type=cache,target=${XDG_CACHE_HOME}/chisel,id="chisel-cache" \
--mount=type=bind,from=chisel,source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt \
--mount=type=bind,from=chisel,source=/usr/local/bin/chisel,target=/chisel \
[ \
"/chisel", "cut", "--release", "ubuntu-24.04", "--root", "/", \
"base-files_base", "bash_bins", "procps_bins", "grep_bins", "gawk_bins", "sed_bins", "coreutils_bins", "busybox_bins", "openssl_bins", "curl_bins" \
]FROM scratch with shell provided by earlier chisel RUN
You could also use a mix of the two to first get a shell provisioned, then install the rest of the slices:
FROM scratch
ENV XDG_CACHE_HOME=/cache
# Required for default `SHELL ["/bin/sh", "-c"]`
# Provision `/bin/sh` (`base-files_base` creates `/bin` -> `/usr/bin` symlink, `dash_bins` creates `/usr/bin/sh` -> `/usr/bin/dash` symlink)
# Alternatively use `bash_bins` and then set `SHELL ["/usr/bin/bash", "-c"]` or create a `/bin/sh` -> `/usr/bin/bash` symlink (requires `coreutils_bins` for `ln`)
RUN --mount=type=cache,target=${XDG_CACHE_HOME}/chisel,id="chisel-cache" \
--mount=type=bind,from=chisel,source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt \
--mount=type=bind,from=chisel,source=/usr/local/bin/chisel,target=/chisel \
[ "/chisel", "cut", "--release", "ubuntu-24.04", "--root", "/", "base-files_base", "dash_bins"]
# Now you can use `SHELL` syntax `RUN`:
RUN --mount=type=cache,target=${XDG_CACHE_HOME}/chisel,id="chisel-cache" \
--mount=type=bind,from=chisel,source=/etc/ssl/certs/ca-certificates.crt,target=/etc/ssl/certs/ca-certificates.crt \
--mount=type=bind,from=chisel,source=/usr/local/bin/chisel,target=/chisel \
/chisel cut --release ubuntu-24.04 --root / base-files_base bash_bins procps_bins grep_bins gawk_bins sed_bins coreutils_bins busybox_bins openssl_bins curl_binsNOTE: The 2nd RUN presently incurs layer inefficiency with chisel installing existing slices, about 5MB wasted in this example (48MB image instead of 43MB). This should be resolved in a future release.
Activity
cjdcordeiro commentedon Apr 28, 2025
This is an interesting case @polarathene . As for #222 , we'll keep this one open here for gathering community interest and for later evaluation.