Nixpacks takes a source directory and produces an OCI compliant image
nixpacks.com
nixpacks.com
Personally I've been making OCI images using Nix, just by running tar, sha256sum and jq:
- We can get a Nix derivation's dependencies using `writeDependenciesToFile`
- We can put these dependencies (alongside anything else we like) into an OCI "layer" using GNU tar: the `--hard-dereference` and `--mode=755` options work well, and we can include directories using `-C /foo --filesFrom=foo.txt` where foo.txt comes from `cd /foo && find . -maxdepth 1`, with the leading `./` removed.
- A "digest" is just a JSON file like `{size: 123, digest: "abc"}`, e.g. generated using `stat` and `sha256sum`
- Those sha256sums can be referenced in a config.json, like `{"rootfs": {"type": "layers", "diff_ids": [...]}}`; along with the application-specific config (EntryPoint, WorkingDir, etc.)
- Finally, a "manifest" is just another JSON file; with `{"mediaType": "application/vnd.oci.image.config.v1+json"}` for the config digest, and `{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip"}` for each layer digest.
Unlike Docker, these commands can all be run directly (from the "host", although it's not really hosting anything, since we don't need any containers or VMs to run the above); their contents are completely declarative (since we're just zipping up pre-existing files, e.g. built/fetched by Nix; rather than mutating a filesystem in-place); we can do it on any OS (e.g. no need for a Linux VM on macOS); etc.
We could jam back and forth on this but generally we're not dogmatic about the "middle" of the process, and we suspect the implementation will change over time for a variety of reasons (even faster builds, smaller images, less dependencies, etc).
The only thing we're dogmatic about is the experience and the fact that it emits an OCI compliant image (that can indeed be run on any orchestrator).
If you're interested in contributing or jamming on this wanna shoot me a DM on twitter (JustJake) or email at jake at railway dot app?
"Tags", "registries", "base images", "extraCommands"... no thanks
> ociTools
IIRC, this generates a runnable container (i.e. a directory, with accompanying config); not a container image, e.g. suitable for uploading to AWS ECS.
All of which are optional. It's just doing the same thing as your tar commands.
True, but they're dangerous enough that I'd still at least want a wrapper function which doesn't accept them at all.
> It's just doing the same thing as your tar commands.
Not quite: I came up with those commands by reading the OCI specifications.
In contrast, the output of the dockerTools functions does not quite follow those specifications, and appears to be more Docker-specific.
It uses dockerTools: https://github.com/NixOS/bundlers/blob/master/flake.nix
maybe a bundler can be added that uses OCI tools, thus providing such a wrapper and giving a nice CLI for it
Usually you wouldn't use any of that, unless you have some external organizational reason to depend on a base image. A typical image would just be:
dockerTools.streamLayeredImage {
name = "mything";
config.Cmd = "${mything}/bin/mything";
}I'll see if Nixpkgs is receptive to having such functionality, as a unification of what I've done with what exists in dockerTools (although I need to check that my employer's happy for it to be upstreamed first!)
https://nixos.org/manual/nixpkgs/stable/#trivial-builder-wri...
Can you share more? I thought a Fly.io person said _the opposite_ some time ago so I would love to know what the pain points are.
We're the people behind nixpacks; happy to answer any questions just holler
[0]: https://github.com/railwayapp/nixpacks/blob/60ab563fdc9bf4fb...
Guix has put quite a bit of work into this, AFAIU, and it's getting close to being bootstrappable all the way from stage0 [0]. Curious if some group is also working on similar things for Nix.
Guix has pretty radical goals in comparison to Nix, which is itself relatively radical. Bootstrapping Nix is... maybe less useful to optimize? I'm not saying it's not worth solving, but as an end user I really don't care if my packages are built from source or not, as long as I can, for example, use Spotify.
--
this is neat though, and in political terms, the elevator pitch mentions nix itself as an implementation detail in passing. hopefully, if this catches on, it'll function as a non-threatening gateway drug to nix itself, when users inevitably go digging into the weeds
for anyone interested, prior art on the nix container front: https://nixery.dev
Our goal is to make reproducibility more approachable/less cumbersome, and for people to be able to define additional nix/apt/etc packages added to the container .
You can add package you'd like via the environment variables NIXPACKS_PKGS (or NIXPACKS_APT_PKGS for apt)
See: https://github.com/railwayapp/nixpacks/blob/f88718efe1156671...
For me `nixpacks plan .` seems to generate a plain old pip (or poetry) install. The problem with the python packaging ecosystem is that since the start, in order to figure out which dependencies a package has, we needed to run arbitrary python code (setup.py). I can write a package in 5 minutes that declares its deps with `random.choice`. If you're installing from pypi.org, then there's no reproducibility guarantee. Though, I know nothing about Nix or how it works, so maybe you're changing pip's index-url somewhere else..
[0]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/...
However, any Nix package can be installed, including from python-packages.nix, and we are planning on allowing more Nix config and customization in the future.
There are a couple of sneaky ways this could possibly be done, but wondered if you explored any of them.
Would love to drop image sizes
I guess a "third way" might involve using e.g. pypi2nix, bundix, node2nix and the like.
Nixpacks can also spit out a plan (https://nixpacks.com/docs/how-it-works#plan) which, when run again, will assure that the build artifacts the exact same every time it's run against that plan.
The result is that any code that's built with nixpacks has all it's dependencies snapshotted so it won't break over time.
For us, that means anytime someone comes to our platform (http://railway.app/) and deploys an Template, it won't be broken
> We want to make it more trivial to build OCI compliant images without all the knowledge required to understand how Dockerfiles/Container Filesystem/BuildLayers/etc work
As someone who understands how the above mentioned stuff works - I feel like I'm being forcefully excluded from the tool's target audience as I need explanations and the docs are written with such an idea in mind that it is something I shouldn't know.
https://nixpacks.com/docs/how-it-works
> Nixpacks works in two steps
> Plan
> Analyze the app source directory and generates a reproducible build plan. This plan can be saved (in JSON format) and re-used at a later date to build the image in the exact same way every time.
How about an example of how a simple plan for a few projects would look like?
Plus, the tool seems to assume too much:
> To create the plan, language providers are matched against the app source directory and suggest Nix packages
I don't need no Nix in my images, no thanks.
I like it.
BuildKit makes this possible and we've got lots of stuff planned. Would love to hear anything you can think of that would make this more friendly!
TLDR; it's promising