diff --git a/docs/creation.md b/docs/creation.md new file mode 100644 index 0000000..fdd570f --- /dev/null +++ b/docs/creation.md @@ -0,0 +1,116 @@ +# Creating Nixlets + +Nixlets need a `default.nix` and a `values.nix` (a `nixlet.nix` containing the metadata is also recommended). + +Check out the existing [nixlets](https://gitlab.com/technofab/nixlets/-/tree/main/nixlets) to understand how they work. +There is also a bare-bones [template](https://gitlab.com/technofab/nixlets/-/tree/main/template/). + +## `nixlet.nix` + +```nix title="Example" +{ + name = "attic"; + version = "0.0.1"; + description = "Multi-tenant Nix Binary Cache"; + defaultProject = "attic"; +} +``` + + + +It's best to create a file `nixlet.nix` for your Nixlet. It's possible to create +Nixlets without this file, by passing the metadata directly to `mkNixlet`, but +when you intend to package the Nixlet this won't work, because when fetching +Nixlets it expects the metadata. + +```nix title="Usage without nixlet.nix" +mkNixlet { + name = ""; + version = ""; + # etc. +} +``` + +```nix title="Usage with nixlet.nix" +mkNixlet ./path; +``` + +Metadata: + +- `name`: Name of the Nixlet +- `version`: Version of the Nixlet itself (like Helm Chart version) +- `description`: Short description of the Nixlet +- `defaultProject`: Kubenix has the concept of projects. + This makes it possible to use the same Nixlet multiple times by specifying + different projects. This is typically included in the resources' names. + (see also `uniqueName` below) + +## `values.nix` + +```nix title="Template" +{ + lib, + utils, + nixlet, + ... +}: +with lib; +with utils; +with nixlet; { + # for some basic values see https://github.com/helm/examples/blob/4888ba8fb8180dd0c36d1e84c1fcafc6efd81532/charts/hello-world/values.yaml + options = { + # define values here + }; +} +``` + +In `values.nix` you declare options the end-user can set. +This uses the NixOS/nixpkgs module system. + +To create a simple string input you can add this in the `options = {}` above: + +```nix title="Simple string value" +hello = mkOption { + type = types.str; + default = "World"; + description = "Hello world!"; +} +``` + +The end-user using your Nixlet can then do this: + +```nix title="Usage" +nixlet.render { + # ... + values = { + hello = "Nixlets"; + }; +} +``` + +It is recommended to use an option like seen below to create a unique name for the Nixlet's resources. + +```nix +# internal +uniqueName = mkOption { + internal = true; + type = types.str; + default = "${project}-atticd"; # example for atticd +}; +``` + +Then use that in your resource names like seen below. + +## `default.nix` + +This file is the entrypoint to your Nixlet. You can define all the resources +in this file directly or import other files. + +```nix +{nixlet, ...}: +with nixlet; { + imports = [./some-resource.nix]; + # or directly + kubernetes.resources.configMaps."${values.uniqueName}-config".data.hello = values.hello; +} +``` diff --git a/docs/index.md b/docs/index.md index 980a0d5..52e39a9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1 +1,12 @@ -Hello World! +# Nixlets + +Nixlets are like Helm Charts, but instead created using [Nix](https://nixos.org). +They are based on [KubeNix](https://kubenix.org) +(this [fork](https://github.com/TECHNOFAB11/kubenix) specifically). + +## Features + +- supports importing Helm Charts, Kustomizations and YAML files if needed +- reproducible thanks to Nix +- versionable (eg. by uploading to GitLab Package Registry) +- utilities for secret management diff --git a/docs/packaging.md b/docs/packaging.md new file mode 100644 index 0000000..c9408e0 --- /dev/null +++ b/docs/packaging.md @@ -0,0 +1,44 @@ +# Packaging Nixlets + +## GitLab Package Registry + +To package and upload Nixlets to the GitLab Package Registry there is a helper script available. +Use it like so: + +```nix title="flake.nix" +apps.upload = { + type = "app"; + program = pkgs.callPackage nixlet-lib.uploadNixletsToGitlab { + projectId = ""; + nixlets = [ + # list of Nixlets + ]; + }; +}; +``` + +You can then run this: + +```sh +nix run .#upload --impure +``` + +`--impure` is needed because the Script needs to access the env variable `AUTH_HEADER`. + +`AUTH_HEADER` needs to contain the Header GitLab expects for auth. +In GitLab CI this should for example be `JOB-TOKEN: $CI_JOB_TOKEN`. +A personal access token requires this format instead: `PRIVATE-TOKEN: `. + +!!! note + The script only uploads a version once. If the version already exists it will skip that Nixlet. + +## General + +Nixlets are self contained and receive all their dependencies etc. from the +caller rendering it. + +This means that you can just compress any Nixlet directory to a tarball, upload +it somewhere and then fetch it later where you intend to use/render it +(the upload script for GitLab CI does basically that). + +See [Usage](./usage.md) for information on how to fetch and render it later. diff --git a/docs/secrets.md b/docs/secrets.md new file mode 100644 index 0000000..51b87bb --- /dev/null +++ b/docs/secrets.md @@ -0,0 +1,27 @@ +# Secrets + +When using Nixlets together with tools like [FluxCD](https://fluxcd.io) and +[SOPS](https://github.com/getsops/sops) it makes sense to apply the secrets on +their own (eg. with their own FluxCD's `Kustomization`). + +To make secret management easier, Nixlets allow you to specify encrypted secret +files in your configuration like this: + +```nix title="some_resource.nix" + # ... + kubernetes.secrets."name" = ./secret.sops.yaml; + kubernetes.resources.configMaps. # ... + # ... +``` + +In CI for example you can then retrieve all of these files at once and put them +in an OCI image for FluxCD to deploy: + +```nix title="flake.nix" +packages.secrets = ().secretsCombined; # (derivation) +``` + +```sh +nix build .#secrets +# result/ contains all yaml secret files +``` diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..d861bef --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,62 @@ +# Using Nixlets + +## Fetching + +You can fetch Nixlets you uploaded somewhere [earlier](./packaging.md) using an URL to the tarball and the sha256 hash: + +```nix +nixlet-lib.fetchNixlet "" "" +``` + +For the GitLab Package Registry there is a helper function: + +```nix +nixlet-lib.fetchNixletFromGitlab { + project = "/"; # eg "TECHNOFAB/nixlets" + name = ""; + version = ""; + sha256 = ""; +} +``` + +## Metadata + +A Nixlet's metadata can easily be accessed: + +```nix +().description # version, name, etc. +``` + +## Rendering + +Rendering a Nixlet will produce a YAML file which contains all the resources. + +```nix +().render { + inherit system; + # values = {}; + # project = ""; + # overrides = ({...}: {}); +} +``` + +Parameters: + +- `system`: needed for Kubenix to work. +- `values`: values to pass to the Nixlet, gets validated by the Nixlets options +- `project`: project to use, makes it possible to use the same Nixlet multiple + times without conflicts +- `overrides`: custom module which can override configuration + +## Just evaluating + +Instead of directly rendering a Nixlet it's also possible to just evaluate it +and access all kinds of data inside it. + +```nix +().eval { + # see above +} +``` + +It accepts the same parameters as `render`. diff --git a/flake.nix b/flake.nix index 492237d..d52d0cc 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,13 @@ alejandra.enable = true; mdformat.enable = true; }; + settings.formatter.mdformat.command = let + pkg = pkgs.python3.withPackages (p: [ + p.mdformat + p.mdformat-mkdocs + ]); + in + lib.mkForce "${pkg}/bin/mdformat"; }; devenv.shells.default = { containers = lib.mkForce {}; @@ -90,9 +97,11 @@ }; plugins = ["search" "material-umami"]; nav = [ - { - "Introduction" = "index.md"; - } + {"Introduction" = "index.md";} + {"Creating Nixlets" = "creation.md";} + {"Packaging" = "packaging.md";} + {"Usage" = "usage.md";} + {"Secrets" = "secrets.md";} ]; markdown_extensions = [ { @@ -102,6 +111,7 @@ "pymdownx.snippets" "pymdownx.superfences" "fenced_code" + "admonition" ]; extra.analytics = { provider = "umami";