-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Bring nix builds to buildkit #1650
Comments
You can build Dockerfile with |
Ah, sorry! I wasn't clear. What I'm interested in doing is have buildkit build something like using the nix builder {
redis = buildImage {
name = "redis";
tag = "latest";
# for example's sake, we can layer redis on top of bash or debian
# fromImage = bash;
# fromImage = debian;
contents = pkgs.redis;
runAsRoot = ''
mkdir -p /data
'';
config = {
Cmd = [ "/bin/redis-server" ];
WorkingDir = "/data";
Volumes = {
"/data" = {};
};
};
};
} The It leverages nix's ecosystem knowledge of how to build and run redis and puts that knowledge into a container. It eliminates the need for builder containers or apt-get cleanups or - even - for alpine itself: it efficiently produces single layered single binary containers without the need to know how to actually package them (thanks to the huge nix ecosystem fundus). I would imagine: something loosely like:
# syntax=nix/nixfile:master
{ pkgs, buildImage }: {
# `buildkit` - the magic attribute for buildkit to consume, since there can be various outputs, but buildkit presumes one `*file` - one artifact.
buildkit = buildImage {
name = "redis";
tag = "latest";
contents = pkgs.redis;
runAsRoot = ''
mkdir -p /data
'';
config = {
Cmd = [ "/bin/redis-server" ];
WorkingDir = "/data";
Volumes = {
"/data" = {};
};
};
};
} |
Yes you should be possible to do this as a frontend. The efficiency depends on how much work is put into it. The simplified version is similar to the Dockerfile approach @AkihiroSuda suggested, just the user does not need to write a Dockerfile. You might also want to take a look at https://github.com/talos-systems/bldr/ https://github.com/sipsma/bincastle for a take on natively defining build dependencies/rules in a similar fashion. |
Actually, we have |
I was having a closer look at the current nix dockerfile tooling: it uses a VM for the construction of the file system. I'd imagine this to cause trouble when running form |
@blaggacao it only uses a VM when you need to run commands as root user. But in practice, you rarely need this. This means we generally don't rely on a VM to build Docker images. |
A show stopper. @tazjin has build some interesting caching strategies into nixery (which also caches the completed image layers (noct obly the nix store results) based on the requested packages. Maybe in his codebase are clues how to map a nix derivation (after going through the layered image "popularity" algorithm to content adressable container layers. Code entrypoint for layer caching: https://github.com/google/nixery/blob/ba1d80323175b61c4f6348827daa8254e3aa13a5/config/pkgsource.go#L35-L41 |
You can probably used cache mounts if you want to keep things in nix store over multiple builds. A more complicated version likely doesn't even need that and could connect straight to instruction caching. Eg. examples I posted above don't use cache mounts afaik. |
Bincastle's current approach doesn't involve cache mounts and should hopefully be formalized upstream once buildkit has support for merge-op (right now it's sort of a hacked version of merge-op). It's been a long time since I've looked at how nix works underneath the hood so I don't have any concrete ideas. That being said, I quickly skimmed this blog post linked to in the nixery repo and, on the surface, it seems like a lot of the issues involved here might be positively impacted by the existence of an efficient merge-op. Just to give an example, in bincastle the equivalents of packages are all single layer images arranged in a DAG that get topologically sorted and efficiently merged together via merge-op make a final rootfs. I'd be curious to hear if anyone with more knowledge of nix internals thinks a similar approach would work with nix and allow the nix-store to be easily used. Not sure what the issues preventing use of the nix-store actually are. |
Or maybe it's enough/better to implement |
My experimental Nix frontend for BuildKit: https://github.com/AkihiroSuda/buildkit-nix
|
off topic, @tonistiigi iirc, you once implemented CA for docker. Looks like full CA is just about to land in nix as well (as opposed to "input addressability") |
I spent some time experimenting with MergeOp/DiffOp for this, and it's a really cool feature, but I don't think it's a silver bullet here; Nix also keeps a SQLite database under Before realizing that I tried using I also tried using My current approach is as follows (I'm using LLB directly so don't have Dockerfile syntax ready):
Using the digest as part of the cache mount ID is important because if you point to a different image (say So far this is working well, but it assumes the full lifecycle (including all building) is happening in Buildkit. If someone wanted to e.g. build in an external system (like Hydra) and propagate the results to Buildkit without a costly transfer they might need #1512. Hope this helps. |
@vito Thanks for the info! I am currently investigating adapting apk package DAGs to LLB using merge+diff, but doing the same investigation for nix is on my eventual TODO list, so I appreciate the data points you gathered so far. If you happen to have any code for your attempts that you can share, I'd appreciate it (no worries if not though, this is useful information on it's own). One thing I'm immediately curious about: when you saw all the memory on your machine being consumed, were you able to tell if that was Buildkit using the memory? Or was it Also, in terms of the |
@sipsma The memory usage was definitely Happy to share code, but it's deep in my esoteric Lisp so it might be hard to find the signal in the noise. It's living in the re: |
One approach might be to add packages on separate layers with a merge and then one layer on top of it with |
@vito I don't fully understand what you are trying to achieve and it would be nice if you could detail what you want to improve in the current buildkit-nix implementation. I would be glad to help you on the Nix side ;) For instance, if you want to cache Nix storepaths (stuffs in the @vito Note I'm pretty sure you should not have to use |
Regarding
I guess this Go library could be used by |
@nlewo PR is welcome 👍 |
Yeah that's exactly what I was thinking, though in the apk case it would only be necessary to do this if you want the exported result to actually have |
@nlewo Thanks for the info! I have some extra thoughts on how nix2container could integrate with buildkit, but please don't let this stop you from contributing to Here's what I'm imagining:
The nice part of that approach is that it lets us use all of Buildkit's caching to optimize the image creation step as much as possible in addition to offering lots of extra features (i.e. exporting the image in estargz format). Do you think that sounds feasible? I guess the main idea here is to re-use nix2container as much as possible but replace the skopeo image-building aspect with Buildkit. |
@nlewo My goal was to have a For some context, the project this is for is essentially a language that compiles commands to LLB and runs them, transparently setting up mounts for files/etc that are passed around. I was hoping to do all of this using the language's existing primitives without having to couple it to directly Nix or other projects. Given these limitations are self-imposed I hope not to distract y'all too much, but I'll be following this conversation closely to see if there's anything I could adjust if there ends up being a nice path forward.
|
@sipsma yep, this is also what i have in mind!
I think the Skopeo "nix" transport would still be valuable but it would be nice to be able to do it with buildkit-nix as well. However, maybe Buildkit could go one step further. Currently, for each layer in the generated JSON file, nix2container generates the digest of this layer (a layer consist on several storepaths). This digest is then used by Skopeo to skip already pushed layers. This however requires IOs (read) at build time, since Nix needs to tar the layer to generate this digest (thanks to the Nix cache mechanism, we only need to do it one time). @vito I would have some questions actually, but i think it would be better to talk about it somewhere else. For instance, it would be useful if you could show an example of your build expression, to see how you are planning to use Nix. Maybe you could open an issue in your project and ping me on it! |
There are also growing thoughts in my corner of the thought palast to modify the OCI standard to add a new image type / layer type that more directly provide handles to nix store paths. These could be assembled on the fly by a runtime into an image, but slightly differently than how it's done with the current layer mimetypes. The capabilities of the classic container overlay mechanism are only needed for the very last 'customization' layer since the nix store paths already never clash and are read-only for all intents and purposes. So amending the OCI standard makes a lot of sense to leverage these characteristics of nix, that don't require to spend on the max overlays budget for most of its contents. |
@blaggacao I like your thinking 👍 |
Maybe to clarify the role of the sqlite in nix, it has two roles:
Building something in buildkit without mounting the store path doesn't really make sense, imo, and from a nix point of view. Now cutting through all the elaborate words that have been said and of which I only understand half of it, in simple terms: what's conceptually holding us back to bind mount the store? I mean there is even a known implementation of a fuse store that queries on demand remotely from a central cache (eg ifps). Although that project is proprietary. |
I hinted at this idea earlier in this thread. Any help and "political" support is welcome to help that proposal gain momentum and succeed: opencontainers/image-spec#922 |
I'd like to propose to bring the capability of doing nix builds into buildkit.
nix builds propose a convincingly saner alternative of building container images, see this talk: https://www.youtube.com/watch?v=pfIDYQ36X0k
I'd be interested in preliminary feedback if / how that could be done.
The text was updated successfully, but these errors were encountered: