Skip to content

Wrapperless kas: land Apple container as a kas-container engine upstream, drop bin/docker #48

Description

@koenkooi

The idea

mackas currently keeps two layers of indirection between the user and upstream kas so that kas itself never needs a patch:

  1. bin/docker — a docker-CLI shim that masquerades as docker on $PATH and translates the calls kas-container issues into Apple container calls. It exists because kas-container detects its engine with command -v docker && docker -v | grep -q '^Docker'.
  2. $MACKAS_BIN/kas-container — a generated protection wrapper (write_kas_wrapper(), mackas:4091) that recomputes --runtime-args live (the three ext4 volumes, -c/-m limits), blanks KAS_BUILD_DIR/DL_DIR/SSTATE_DIR, refuses to launch if the resulting string is missing a volume, and then execs the real upstream script.

The idea is to flip which side adapts: mackas keeps doing the real setup work (creating and sizing the ext4 volumes, deriving the project), and then execs genuinely unmodified upstream kas-container — no translation shim, no protection wrapper — because kas has learned to accept the environment mackas prepared. That means patching kas, which reverses the "zero patches to kas" design goal — but upstream patches, not a local fork, so mackas would still never carry a modified kas of its own.

Researched against real kas source (master dcbd85c, kas-container 5.4-14; line numbers below are the v5.4 tag mackas pins unless stated). Conclusion: this is two separate upstream asks, one small and structurally unblocked, one a genuine gap that needs careful framing. They should not be proposed as one thing.

Ask 1: Apple container as a third engine in kas-container — small

The XPC-vs-Docker-Engine-API concern is a non-issue. kas-container never opens a socket or speaks the Engine API; engine support is entirely "shell out to a CLI". The only engine invocation in the whole 820-line script is its last line:

trace ${KAS_CONTAINER_COMMAND} run "$@"

and KAS_CONTAINER_COMMAND is set by a small case on KAS_CONTAINER_ENGINE (master lines 552–584): auto-detect (podman when build_system: isar-rootless, else docker if docker -v | grep -q '^Docker', else podman), then a per-engine branch where podman's whole contribution is KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} --security-opt label=disable". The docker-only helper calls (docker -v, docker context show, docker context inspect) all sit inside the docker branch or the Isar/rootless paths, so a container) branch never reaches them.

Size precedent: podman was added in one commit, a5dc5f8 "kas-docker: Add support for podman", 38 insertions, structured exactly as above (auto-detect chain + case + one usage line).

What a container) branch actually has to do:

  • KAS_CONTAINER_COMMAND="container".
  • Remove --log-driver=none from KAS_RUNTIME_ARGS="--log-driver=none --user=root" (v5.4:449, master:456). Note this line runs before engine selection, and the engine detection was moved deliberately late (5435c6c, a440b89) so it can see the build system — so the fix belongs in the engine case, not in an earlier reordering.
  • Auto-detection that doesn't match any random binary named container: the analogue of the existing docker -v | grep -q '^Docker' probe, against container --version.
  • Optionally, sane -c/-m defaults, since Apple container defaults to cpus=4 / memory=1gb where docker on Linux inherits the host. Every OE build on the Apple engine needs these; supplying them is arguably part of what an engine branch is for.
  • Docs: docs/userguide/kas-container-description.inc ("As container backends, Docker and Podman are supported…") and the KAS_CONTAINER_ENGINE row in docs/userguide/environment-variables.inc.

--log-driver=none is the only incompatibility on the real path — smaller than bin/docker's drop list implies. The recorded argv fixture in this repo (tests/fixtures/kas-container-5.4.argv, captured from real runs) shows a plain-OE invocation emits only -v, -e, --workdir=, --rm, --init, --user=root plus mackas's -c/-m/volume args, all of which Apple container takes verbatim. The other flags bin/docker drops (--security-opt, --userns, --group-add, --privileged) only appear on the Isar/rootless paths that are already out of scope. So bin/docker is defensive breadth around a one-flag problem, and Ask 1 alone deletes it.

Ask 2: handing kas an already-prepared storage environment — real gap, harder sell

There is no near-miss flag here. forward_dir() (v5.4:286) has exactly two behaviours:

KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -v ${FW_DIR_REL}:$2:$3 -e $1=$2"   # dir outside KAS_WORK_DIR
KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e $1=/work/${FW_DIR_REL}"          # dir inside KAS_WORK_DIR

A host path either gets bind-mounted or gets rewritten to a /work subpath. The script has no concept of a named volume anywhere, and setup_kas_dirs()/check_and_expand() (v5.4:219/239) mkdir and realpath -e these values on the host before forward_dir() ever runs, so any non-path spelling has to be handled ahead of that. Hence mackas's current blanking: an unprotected KAS_BUILD_DIR would bind-mount an APFS path over the ext4 volume, and there is no way to say "this one is already provided".

--runtime-args/--docker-args is the only injection point, and it is CLI-only on purpose: KAS_EXTRA_RUNTIME_ARGS is initialised to "" at v5.4:331 by commit 567950b, whose entire rationale is "Just to avoid it is perceived as API or even used as such." So an ask framed as "let the environment supply runtime args" is dead on arrival.

Two framings that could survive:

  • Volume-form values for the three dirs, e.g. KAS_BUILD_DIR=volume:oe-build-tmp expanding to -v oe-build-tmp:/build -e KAS_BUILD_DIR=/build. These env vars already are the documented API for exactly this decision, and the feature generalises past macOS (anyone wanting TMPDIR on a filesystem the host can't supply directly). The container entrypoint needs nothing: chown_managed_dirs() already chowns /build /work /sstate /downloads /repo-ref to the invoking uid however they were mounted.
  • Validation only: kas-container notices that --runtime-args already mounts something at /build and refuses to also bind-mount KAS_BUILD_DIR over it. Cheaper, narrower, closes the actual footgun — but leaves mackas still injecting the flag, so it doesn't remove the wrapper.

What survives even if both land

bin/docker disappears outright with Ask 1 — that's the clean win. The generated kas-container wrapper does not fully disappear even with Ask 2: -c/-m limits, the monitor's -p and bind mounts, and the NFS mirror mounts still have no expression outside --runtime-args, and runtime auto-start (#33) plus the macos-local.yml fragment append are mackas's own business, not kas's. Realistically the wrapper shrinks to those, and its "refuse to launch without the three volumes" check becomes unnecessary once the volume-form env vars are inherited rather than injected. Worth having; "wrapperless" overstates the end state.

Process and prior art

Upstream contributions go to the kas-devel mailing list with Signed-off-by: per CONTRIBUTING.md; GitHub PRs get routinely redirected there by the maintainer (recent: PR #188, PR #152).

  • siemens/kas#123 — the maintainer explicitly recommends --runtime-args '-v <host>:<container>' for exactly this class of problem. mackas's current mechanism is the sanctioned one, not a hack.
  • siemens/kas#116 — "that would not work across kas-container. It needs to know this value but has no parser for configs". kas-container is deliberately a dumb bash script; that bounds how clever Ask 2 may be.
  • siemens/kas#188 (open) — makes --runtime-args honour shell quoting instead of blind word-splitting. If it lands, mackas's "no value in the runtime-args string may contain a space" constraint (kas_runtime_args(), mackas:1416) can be retired.
  • No prior art at all for non-docker/non-podman runtimes: searches across all kas issues and PRs for macOS/darwin/apple/nerdctl/lima/colima turn up only #38 (2020, a Mac user on docker-machine hitting a bitbake-server socket error). Apple container has never been raised upstream.

siemens/kas#179 is a red herring

#179 "Support for external plugins/commands" is about the Python side: kas/plugins/__init__.py hard-codes its nine plugin modules in load() (register_plugins(build), register_plugins(checkout), …) with no entry-point mechanism, and the thread is a stalled design discussion about a stable core-kas/plugin API, referencing older kas-devel RFCs. Its one kas-container sentence ("the unsolved problem is how to add plugins to kas-container") is about surfacing a Python plugin through the container image — not about extending the bash script. Neither ask above needs a plugin system; both are ordinary patches to a shell script. Starting the conversation there would be starting it in the wrong place.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions