@@ -1,117 +1,85 @@
1−# nix-container
1+# container-nix
3A Nix flake that builds an **OCI image** (via
3A Nix flake that builds an **OCI image** (via
4[`nix2container`](https://github.com/nlewo/nix2container)) for running with
4[`nix2container`](https://github.com/nlewo/nix2container)) for running with
5Apple's [`container`](https://github.com/apple/container) CLI on macOS.
5Apple's [`container`](https://github.com/apple/container) CLI on macOS.
7It's a plain, single-process image — no NixOS, no systemd — defined in
7It's a plain, single-process image — no NixOS, no systemd — defined in
8−[`flake.nix`](./flake.nix). `c start` drops you into a
8+[`flake.nix`](./flake.nix). The default command is `fish` (with a configured
9−[`herdr`](https://herdr.dev) session whose panes use your host login shell
9+prompt), and the image ships a handful of dev/LLM tools: `git`, `jujutsu`,
10−(detected and bundled by `c init`). You choose what else it ships via a
10+`ripgrep`, `fd`, `jq`, `nodejs`, `python3`, a Rust + C toolchain,
11−per-project `container.nix`.
11+`charmbracelet.crush`, `openssh`, and more.
13## Prerequisites
13## Prerequisites
15−- [Nix](https://nixos.org/download/) with flakes enabled.
16−- Apple's [`container`](https://github.com/apple/container) CLI installed, with
15+- Apple's `container` CLI installed, with services started:
17− services started: `container system start` (first run downloads a Linux
16+ `container system start` (first run downloads a Linux kernel).
18− kernel).
17+- A **Linux builder** — the image *contents* are Linux binaries and can't be
19−- A **Linux builder** *only if you use packages that aren't in the binary
18+ built on macOS. `internal.iko.soy` (aarch64-linux) is already configured, so
20− cache*. The image is assembled entirely on macOS — the root filesystem is just
19+ `nix` dispatches to it automatically.
21− a host-built symlink tree over the **substituted** Linux store paths — so a
20+
22− fully-cached package set needs no builder. Compiling a Linux package that
21+## Steps
23− `cache.nixos.org` doesn't have does, though: use a [remote builder][builders]
24− or, on Apple Silicon, the `nix-darwin` `linux-builder`.
26−[builders]: https://nix.dev/manual/nix/latest/advanced-topics/distributed-builds
30−`init` builds the image from a **`container.nix`** in the current directory — an
31−attrset with a `packages` function (`{ pkgs, nur }` returning the package list;
32−`nur` is [NUR](https://github.com/nix-community/NUR), for packages outside
33−nixpkgs) and an optional `mounts` list. It is **required**; there is no default.
38− packages = { pkgs, nur }: with pkgs; [
41− nur.repos.charmbracelet.crush
43− # Extra "host:container" bind mounts, on top of $PWD → /workspace. A leading
44− # ~/ in the host path expands to $HOME. Optional.
51−Your **host login shell** (detected by `c init`, bash fallback), **coreutils**,
23+### 1. Build the image archive
52−[**herdr**](https://herdr.dev) (the session `c start` launches), **Nix** itself
53−(with CA certs and `nix-command`/`flakes` enabled, single-user), and the ncurses
54−**terminfo** database are always included — no need to list them.
56−Point at a different file with `-c`/`--config`:
25+`nix run` builds the Linux contents (on the remote builder) and writes a tagged
26+OCI archive locally via `skopeo`. Pass the output path; the image is tagged
27+`nixos-container:latest`.
59−nix run github:ilyakooo0/nix-container -- init --config envs/ci.nix
30+nix run . -- image.tar.gz
62−## Quick start
33+### 2. Load it into `container`
64−No clone needed — `nix run` drives everything. Run it from a project directory
65−that holds a `container.nix`; the container is named after that directory.
68−# build the image, load it, and create the container (named after $PWD):
36+container image load --input image.tar.gz
69−nix run github:ilyakooo0/nix-container -- init
37+```
71−# start it and attach — drops you into a herdr session:
39+### 3. Create and start the container
72−nix run github:ilyakooo0/nix-container -- start
40+
42+container create --name nixos --ssh -it nixos-container:latest
43+container start -ai nixos
75−- `init` builds the OCI archive in a temp dir, loads it into `container`,
76− deletes the temp file, then (re)creates the container. It mounts the current
77− directory at `/workspace` (the container's working directory).
78- `--ssh` forwards your host SSH agent socket into the container (so `git` over
46- `--ssh` forwards your host SSH agent socket into the container (so `git` over
79− SSH works with your keys).
47+ SSH etc. works with your keys).
80−- Add more mounts persistently via `mounts` in `container.nix` (above), or
48+- `-it` / `-ai` give an interactive TTY; `start -ai` attaches to it.
81− ad-hoc by passing them through to `create` (mounts can only be set at creation):
84− nix run github:ilyakooo0/nix-container -- init -v $HOME/data:/data
87−Working from a checkout, [`./c init`](./c) / `./c start` are equivalent — and
50+You land in `fish`. Exit the shell to stop the container.
88−`c` can be symlinked onto your `$PATH` and run from any project.
90## Re-running after a rebuild
52## Re-running after a rebuild
92−Just run `init` again — it reloads the image and replaces the existing container
54+`container` keeps the loaded image and the created container, so to pick up a
93−(removing the old one first), so there's nothing to clean up:
55+new build, remove the old ones first:
96−nix run github:ilyakooo0/nix-container -- init
58+nix run . -- image.tar.gz # rebuild the archive
59+container rm nixos # remove the old container (stop it first if running)
60+container image rm nixos-container:latest
61+container image load --input image.tar.gz
62+container create --name nixos --ssh -it nixos-container:latest
63+container start -ai nixos
99−## Customize further
66+## Other image destinations
101−Fork or clone to change what isn't per-project — `config.cmd`/`env` or the image
68+`nix run .#copyTo` is nix2container's generic skopeo wrapper
102−name — in [`flake.nix`](./flake.nix). The flake also exposes build helpers:
69+(`skopeo copy nix:<image> "$@"`) — the argument is any skopeo destination:
104−- `lib.<system>.copyWith` → a skopeo copy app for a `{ pkgs, nur }: [ ... ]`
71+```sh
105− function, for building/pushing the image anywhere skopeo can write (e.g. a
72+nix run .#copyTo -- docker://ghcr.io/me/nixos:latest # push to a registry
106− registry):
73+nix run .#copyTo -- docker-daemon:nixos-container:latest # local Docker daemon
108− ```sh
78+Edit the `buildImage` call in [`flake.nix`](./flake.nix):
109− drv=$(nix build --no-link --print-out-paths --impure --expr \
79+
110− '(builtins.getFlake "github:ilyakooo0/nix-container").lib.${builtins.currentSystem}.copyWith (import ./container.nix).packages')
80+- Add packages to `copyToRoot.paths`.
111− $drv/bin/copy-to docker://ghcr.io/me/img:latest
81+- Change the default process via `config.cmd`.
112− ```
82+- Add env vars via `config.env`.
113−- `lib.<system>.mkImage <name> <shell>` → the underlying OCI image (`copyWith`
114− defaults these to `nix-container` / `bash`).
116The flake uses `flake-utils` over `{aarch64,x86_64}-{darwin,linux}`; the host
84The flake uses `flake-utils` over `{aarch64,x86_64}-{darwin,linux}`; the host
117system maps to the matching Linux target automatically (an Intel Mac builds an
85system maps to the matching Linux target automatically (an Intel Mac builds an
@@ -119,15 +87,8 @@ system maps to the matching Linux target automatically (an Intel Mac builds an
120## How it works
88## How it works
122−- **Contents** are Linux store paths — downloaded prebuilt from the binary cache
90+- **Contents** (`copyToRoot`) are built from `pkgsLinux` → the Linux builder.
123− (only built on a Linux builder if not cached).
91+- **Assembly** (`nix2container` + the `skopeo` copy) runs on your Mac, so a
124−- **Assembly** runs entirely on your Mac: `copyToRoot` is a *host-arch* `buildEnv`
92+ single `nix run` produces a loadable archive.
125− symlink tree over those Linux paths (symlinks are arch-neutral), and
126− `nix2container` + `skopeo` package it — so for a cached set, `init` produces a
127− loadable Linux image with no Linux build at all.
128- Apple's `container` runs each container in its own lightweight Linux VM and
93- Apple's `container` runs each container in its own lightweight Linux VM and
129 consumes standard OCI images — no `--privileged` or systemd needed.
94 consumes standard OCI images — no `--privileged` or systemd needed.