canonical / canonical/chisel

UX: Running `chisel cut` with slices as single arg? (or sourced from a file arg)

Open
#220 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
424
Forks
65
Avg merge
12d 19h
Merged PRs (30d)
1

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:

```Dockerfile
# 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:

```Dockerfile
# 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:` like `base-files`, and `bins:` like `bash`, 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`:

```Dockerfile
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 chisel
```

### `FROM 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 /`_):

```Dockerfile
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_bins
```

**NOTES:**
- `/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, `chisel` could embed a fallback? This file is about 220KB on Alpine_)
- If this `ca-certificates.crt` file would be modified by `chisel` due to slices installed, a bind mount here is probably not appropriate, you'd need an earlier `COPY` instead and lose some image weight efficiency (_fallback or alternative path would avoid this concern_).
- Nushell has been used as the shell instead of `bash`, only because this easily allows for a shell that works on `scratch` as it's a single self-contained binary like `chisel`.
- While Nushell could use additional commands, note that `\` cannot be used for multi-line splitting (valid for bash) if providing `RUN` a HereDoc string (_multi-line input, akin to an actual script, which then encodes the `\` as part of that string, not as part of the `RUN` instruction itself that is parsed_). Hence additional commands in the same `RUN` require familiarity with Nushell's syntax differences from Bash (_`&&` => `;`, `\` => `(` ... `)`_).
- If not using `--root /` with `scratch`, `WORKDIR /root-fs` + `--root /root-fs` or similar would be required as `chisel` does not yet create the `--root` location when it doesn't exist. A separate stage to then copy `/root-fs` to `/` would be required as `chisel` may fail when existing base image conflicts (_such as an existing `/bin` that 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`_):

```Dockerfile
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:

```Dockerfile
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_bins
```

**NOTE:** 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](https://github.com/canonical/chisel/issues/208).

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing the `chisel cut` CLI entry point and the Dockerfile `SHELL` and `RUN` examples described here. Compare the proposed single-argument slice parsing, delimiters, and config-file alternatives, then establish a scoped behavior and tests before implementation; done should include a documented, tested way to provide slices without separate CLI arguments.

Written by the indexing model from the issue text.

Assessment

Tech stack
dockerfile, shell
Domain
cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.