Add additional fun flake examples
This commit is contained in:
parent
c2cf1de816
commit
bbad847369
80
readme.md
80
readme.md
|
@ -1,8 +1,8 @@
|
||||||
This post is a Flake-based rewrite of [Learn Nix the Fun Way on fzakaria.com]
|
This post is a Flake-based rewrite of [Learn Nix the Fun Way on fzakaria.com][0].
|
||||||
[0]. I really enjoyed the content of the post and wanted to write it as a Nix
|
I really enjoyed the content of the post and wanted to write it as a Nix
|
||||||
user who is just using flakes. It does add a few extra steps and complexity,
|
user who is just using and prefers flakes. It does add a few extra steps and
|
||||||
but I think it's still valuable and perhaps reveals a bit more about Nix and why
|
complexity, but I think it's still valuable and perhaps reveals a bit more about
|
||||||
it's pretty fantastic.
|
Nix and why it's pretty fantastic.
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
|
|
||||||
|
@ -12,15 +12,15 @@ Let's walk through a single example of a shell script one may write: _what-is-my
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
curl -s http://httpbin.org/get \
|
curl -s http://httpbin.org/get | \
|
||||||
| jq --raw-output .origin
|
jq --raw-output .origin
|
||||||
```
|
```
|
||||||
|
|
||||||
Sure, it's _sort of portable_, if you tell the person running it to have _curl_ and _jq_. What if you relied on a specific version of either though?
|
Sure, it's _sort of portable_, if you tell the person running it to have _curl_ and _jq_. What if you relied on a specific version of either though?
|
||||||
|
|
||||||
Nix **guarantees** portability.
|
Nix **guarantees** portability.
|
||||||
|
|
||||||
We might leverage _[Nixpkgs' trivial builders](https://ryantm.github.io/nixpkgs/builders/trivial-builders/)_ (specifically, `writeShellScriptBin`) in a basic Nix flake to turn this into a Nix derivation (i.e. build recipe).
|
We might leverage _[Nixpkgs' trivial builders](https://ryantm.github.io/nixpkgs/builders/trivial-builders/)_ (specifically, `writeShellScriptBin`) in a basic Nix flake to turn this into a Nix derivation (i.e. build recipe):
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
# flake.nix
|
# flake.nix
|
||||||
|
@ -50,9 +50,13 @@ pkgs.writeShellScriptBin "what-is-my-ip" ''
|
||||||
|
|
||||||
Here we are pinning our package to dependencies which come from NixOS/Nixpkgs release branch 24.05.
|
Here we are pinning our package to dependencies which come from NixOS/Nixpkgs release branch 24.05.
|
||||||
|
|
||||||
If we `nix build` and `readlink result` we get:
|
We can build our package and find out the Nix store path (which contains the
|
||||||
|
hash) like so:
|
||||||
|
|
||||||
**/nix/store/lr6wlz2652r35rwzc79samg77l6iqmii-what-is-my-ip**
|
```console
|
||||||
|
$ nix build --print-out-paths
|
||||||
|
/nix/store/lr6wlz2652r35rwzc79samg77l6iqmii-what-is-my-ip
|
||||||
|
```
|
||||||
|
|
||||||
And, of course, we can run our built result:
|
And, of course, we can run our built result:
|
||||||
|
|
||||||
|
@ -68,7 +72,9 @@ $ nix run
|
||||||
24.5.113.148
|
24.5.113.148
|
||||||
```
|
```
|
||||||
|
|
||||||
Now that this is in Nix and we've modeled our dependencies, we can do _fun_ things like generate graph diagrams to view them (click the image to view larger).
|
Now that this is in our Nix store, we've naturally modeled our dependencies
|
||||||
|
and can do _fun_ things like generate graph diagrams (click the image to view
|
||||||
|
larger):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix-store --query --graph $(readlink result) | nix shell nixpkgs#graphviz -c dot -Tpng -o what-is-my-ip-deps.png
|
$ nix-store --query --graph $(readlink result) | nix shell nixpkgs#graphviz -c dot -Tpng -o what-is-my-ip-deps.png
|
||||||
|
@ -76,7 +82,7 @@ $ nix-store --query --graph $(readlink result) | nix shell nixpkgs#graphviz -c d
|
||||||
|
|
||||||
[![Image of what-is-my-ip dependencies as a graph](./what-is-my-ip-deps.png)](./what-is-my-ip-deps.png)
|
[![Image of what-is-my-ip dependencies as a graph](./what-is-my-ip-deps.png)](./what-is-my-ip-deps.png)
|
||||||
|
|
||||||
Let's create a _developer environment_ and bring in our new tool.
|
Let's add a _developer environment_ which contains our new tool.
|
||||||
This is a great way to create developer environments with reproducible tools.
|
This is a great way to create developer environments with reproducible tools.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
|
@ -89,7 +95,7 @@ index 2a99357..ab32421 100644
|
||||||
inputs.nixpkgs.url = "nixpkgs/nixos-24.05";
|
inputs.nixpkgs.url = "nixpkgs/nixos-24.05";
|
||||||
- outputs = {nixpkgs, ...}: let
|
- outputs = {nixpkgs, ...}: let
|
||||||
+ outputs = {
|
+ outputs = {
|
||||||
+ self,
|
+ self, # we will need to reference our own outputs to pull in the package we've declared
|
||||||
+ nixpkgs,
|
+ nixpkgs,
|
||||||
+ ...
|
+ ...
|
||||||
+ }: let
|
+ }: let
|
||||||
|
@ -97,12 +103,12 @@ index 2a99357..ab32421 100644
|
||||||
pkgsFor = func: (nixpkgs.lib.genAttrs systems (system: (func (import nixpkgs {inherit system;}))));
|
pkgsFor = func: (nixpkgs.lib.genAttrs systems (system: (func (import nixpkgs {inherit system;}))));
|
||||||
in {
|
in {
|
||||||
packages = pkgsFor (pkgs: {
|
packages = pkgsFor (pkgs: {
|
||||||
what-is-my-ip = pkgs.callPackage ./what-is-my-ip.nix {};
|
default = pkgs.callPackage ./what-is-my-ip.nix {};
|
||||||
});
|
});
|
||||||
+
|
+
|
||||||
+ devShells = pkgsFor (pkgs: {
|
+ devShells = pkgsFor (pkgs: {
|
||||||
+ default = pkgs.mkShell {
|
+ default = pkgs.mkShell {
|
||||||
+ packages = [self.outputs.packages.${pkgs.system}.what-is-my-ip];
|
+ packages = [self.outputs.packages.${pkgs.system}.default];
|
||||||
+ shellHook = ''
|
+ shellHook = ''
|
||||||
+ echo "Hello, Nix!"
|
+ echo "Hello, Nix!"
|
||||||
+ '';
|
+ '';
|
||||||
|
@ -122,7 +128,7 @@ $ which what-is-my-ip
|
||||||
|
|
||||||
🕵️ Notice that the hash **lr6wlz2652r35rwzc79samg77l6iqmii** is _exactly_ the same which we built earlier.
|
🕵️ Notice that the hash **lr6wlz2652r35rwzc79samg77l6iqmii** is _exactly_ the same which we built earlier.
|
||||||
|
|
||||||
We can now do binary or source deployments 🚀🛠️📦 since we know the full dependency closure of our tool. We simply copy the necessary _/nix/store_ paths to another machine with Nix installed.
|
We can now do binary or source deployments 🚀🛠️📦 since we know the full dependency closure of our tool. We simply copy the necessary `/nix/store` paths to another machine with Nix installed.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nix copy --to ssh://beefcake $(nix build --print-out-paths)
|
$ nix copy --to ssh://beefcake $(nix build --print-out-paths)
|
||||||
|
@ -130,7 +136,7 @@ $ ssh beefcake /nix/store/lr6wlz2652r35rwzc79samg77l6iqmii-what-is-my-ip/bin/wha
|
||||||
98.147.178.19
|
98.147.178.19
|
||||||
```
|
```
|
||||||
|
|
||||||
Maybe though you are stuck with Kubernetes or Docker. Let's use Nix to create an OCI-compatible image.
|
Maybe though you are stuck with Kubernetes or Docker. Let's use Nix to create an OCI-compatible image with our tool:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
diff --git a/flake.nix b/flake.nix
|
diff --git a/flake.nix b/flake.nix
|
||||||
|
@ -155,13 +161,13 @@ index 99d6d52..81e98c9 100644
|
||||||
```console
|
```console
|
||||||
$ docker load < $(nix build .#docker-image --print-out-paths)
|
$ docker load < $(nix build .#docker-image --print-out-paths)
|
||||||
Loaded image: what-is-my-ip-docker:c9g6x30invdq1bjfah3w1aw5w52vkdfn
|
Loaded image: what-is-my-ip-docker:c9g6x30invdq1bjfah3w1aw5w52vkdfn
|
||||||
$ docker run -it what-is-my-ip-docker:c9g6x30invdq1bjfah3w1aw5w52vkdfn
|
$ docker run -it what-is-my-ip-container:c9g6x30invdq1bjfah3w1aw5w52vkdfn
|
||||||
24.5.113.148
|
24.5.113.148
|
||||||
```
|
```
|
||||||
|
|
||||||
Cool! Nix + Docker integration perfectly. The image produced has only the files exactly necessary to run the tool provided, effectively **distroless**. You may also note that if you are following along, your image digest is exactly the same. **Reproducibility!**
|
Cool! Nix + Docker integration perfectly. The image produced has only the files exactly necessary to run the tool provided, effectively **distroless**. You may also note that if you are following along, your image digest is exactly the same. **Reproducibility!**
|
||||||
|
|
||||||
Finally, let's take the last step and create a reproducible operating system using NixOS to contain only the programs we want.
|
Finally, let's take the last step and create a reproducible operating system using NixOS to contain only the programs we want:
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
diff --git a/flake.nix b/flake.nix
|
diff --git a/flake.nix b/flake.nix
|
||||||
|
@ -198,6 +204,8 @@ index 99d6d52..81e98c9 100644
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now we can run this NixOS configuration as a reproducible virtual machine:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ nixos-rebuild build-vm --flake .#default
|
$ nixos-rebuild build-vm --flake .#default
|
||||||
$ ./result/bin/run-nixos-vm
|
$ ./result/bin/run-nixos-vm
|
||||||
|
@ -217,6 +225,40 @@ $ what-is-my-ip
|
||||||
|
|
||||||
We took a relatively simple script through a variety of applications in the Nix ecosystem: build recipe, shell, docker image, and finally NixOS VM.
|
We took a relatively simple script through a variety of applications in the Nix ecosystem: build recipe, shell, docker image, and finally NixOS VM.
|
||||||
|
|
||||||
|
One of the super neat part about flakes is that anywhere you find a flake, you
|
||||||
|
can make use of it. Try it out now!
|
||||||
|
|
||||||
|
> Note: The following obviously runs code from the internet. Be wary of doing this in general.
|
||||||
|
|
||||||
|
```console
|
||||||
|
# run a flake's package
|
||||||
|
$ nix run git+https://git.lyte.dev/lytedev/learn-flakes-the-fun-way
|
||||||
|
24.5.113.148
|
||||||
|
|
||||||
|
# enter a flake's development environment
|
||||||
|
$ nix develop git+https://git.lyte.dev/lytedev/learn-flakes-the-fun-way -c $SHELL
|
||||||
|
Hello, Nix!
|
||||||
|
$ what-is-my-ip
|
||||||
|
24.5.113.148
|
||||||
|
|
||||||
|
# load a flake's docker image and run it
|
||||||
|
$ docker load < $(nix build git+https://git.lyte.dev/lytedev/learn-flakes-the-fun-way#container --print-out-paths)
|
||||||
|
Loaded image: what-is-my-ip-container:wg0z43v4sc1qhq7rsqg02w80vsfk9dl0
|
||||||
|
$ docker run -it what-is-my-ip-container:c9g6x30invdq1bjfah3w1aw5w52vkdfn
|
||||||
|
|
||||||
|
# run a flake's NixOS configuration as a virtual machine
|
||||||
|
$ nixos-rebuild build-vm --flake git+https://git.lyte.dev/lytedev/learn-flakes-the-fun-way#default
|
||||||
|
Done. The virtual machine can be started by running /nix/store/xswwdly9m5bwhcz9ajd6km5hx9vdmfzw-nixos-vm/bin/run-nixos-vm
|
||||||
|
$ /nix/store/xswwdly9m5bwhcz9ajd6km5hx9vdmfzw-nixos-vm/bin/run-nixos-vm
|
||||||
|
|
||||||
|
# like running a pre-configured version of my workstation's NixOS configuration
|
||||||
|
# NOTE: this will probably take a good, long time to build and lots of bandwidth
|
||||||
|
$ nixos-rebuild build-vm --flake git+https://git.lyte.dev/lytedev/nix#dragon
|
||||||
|
Done. The virtual machine can be started by running /nix/store/abc-nixos-vm/bin/run-nixos-vm
|
||||||
|
$ /nix/store/abc-nixos-vm/bin/run-nixos-vm
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
Hopefully, seeing the _fun things_ you can do with Nix might inspire you to push through the hard parts.
|
Hopefully, seeing the _fun things_ you can do with Nix might inspire you to push through the hard parts.
|
||||||
|
|
||||||
There is a golden pot 💰 at the end of this rainbow 🌈 awaiting you.
|
There is a golden pot 💰 at the end of this rainbow 🌈 awaiting you.
|
||||||
|
|
Loading…
Reference in a new issue