From a052d499dfff684ddec2f0735702b23a46cd93de Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 4 Dec 2023 21:32:12 -0800 Subject: [PATCH] Continue writing README; add template --- README.rst | 190 +++++++++++------- flake.nix | 4 + templates/default/flake.nix | 45 +++++ .../services/default/breezewiki/default.nix | 38 ++++ .../gateway-system/gateway-api/default.nix | 10 + 5 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 templates/default/flake.nix create mode 100644 templates/default/services/default/breezewiki/default.nix create mode 100644 templates/default/services/gateway-system/gateway-api/default.nix diff --git a/README.rst b/README.rst index 026b2de..2850653 100644 --- a/README.rst +++ b/README.rst @@ -22,22 +22,22 @@ Turboprop templates your Helm charts for you, making an individual Nix derivatio Acknowledgments *************** -Without `Vladimir Pouzanov`_'s "`Nix and Kubernetes\: Deployments Done Right`_" (and `its notes`_), this project would not exist. - -I also used `heywoodlh's Kubernetes flake`_ as a starting point early on. +- `Vladimir Pouzanov`_'s "`Nix and Kubernetes\: Deployments Done Right`_" (and `its notes`_) is the reason this project exists. +- Early on, I used `heywoodlh's Kubernetes flake`_ as a starting point. +- Once I discovered `Haumea`_, Turboprop *really* started coming together. .. _Vladimir Pouzanov: https://github.com/farcaller .. _Nix and Kubernetes\: Deployments Done Right: https://media.ccc.de/v/nixcon-2023-35290-nix-and-kubernetes-deployments-done-right .. _its notes: https://gist.github.com/farcaller/c87c03fbb55eaeaeb840b938455f37ff .. _heywoodlh's Kubernetes flake: https://github.com/heywoodlh/flakes/blob/aa5a52a/kube/flake.nix +.. _Haumea: https://github.com/nix-community/haumea +******** +Tutorial +******** -********************** -Usage and architecture -********************** - -Getting started -=============== +Installation +============ To start, add this flake to your flake's inputs, along with ``nixpkgs`` and ``flake-utils``: @@ -64,17 +64,30 @@ Next, put it to use in your flake's output: <...> outputs = {self, nixpkgs, flake-utils, turboprop}: flake-utils.lib.eachDefaultSystem (system: let - pkgs = import nixpkgs { - inherit system; - overlays = [devshell.overlays.default]; + pkgs = import nixpkgs {inherit system;}; + + turbo = turboprop.lib.${system}; + + mkDerivation = turbo.mkDerivation { + user = { + # We'll get to this + app-template = turbo.app-template; + }; }; - - t = turboprop.lib.${system}; - - mkDerivation = t.mkDerivation {}; in { - packages.default = turbo.mkDerivation { - # This too + packages.default = let + pname = "my-k8s-flake"; + in + mkDerivation { + inherit pname; + version = "rolling"; + src = builtins.path { + path = ./.; + name = pname; + }; + + serviceRoot = ./services; + nsMetadata = {}; }; } ); @@ -115,14 +128,15 @@ This is a module that defines a *service derivation*: spec.ca.secretName = user.vars.k8sCert.name; } ]; - } + } 1. The module takes as input: #. A tree of *chart derivations*; #. the Turboprop library; and - #. user data specific to your flake. You may `omit any of these input variables`_ if they're not used. + #. the Nixpkgs for the current system (``pkgs``); and + #. user data specific to your flake. You may `omit any of these input variables`_. 2. The module has the output signature ``{builder, args, extraObjects}``. @@ -135,75 +149,89 @@ This is a module that defines a *service derivation*: .. _single remote YAML file: https://git.sr.ht/~goorzhel/kubernetes/tree/f3cba6831621288228581b7ad7b6762d6d58a966/item/system/gateway-system/gateway-api/default.nix#L2 .. _define your own builder: https://git.sr.ht/~goorzhel/kubernetes/tree/f3cba6831621288228581b7ad7b6762d6d58a966/item/services/svc/breezewiki/default.nix#L6 -Trees of Nix modules -==================== +Creating a service tree +======================= -Turboprop's operates on *trees* of Nix modules, both in the filesystem sense (nested directories) and the Nix sense (nested attrsets). A service tree, then, consists of +Turboprop operates on *trees* of Nix modules, both in the filesystem sense (nested directories) and the Nix sense (nested attrsets), and uses `Haumea`_ to do so. A service tree consists of #. an arbitrarily-named root, such as ``./services``, which contains #. zero or more intermediate directories (we'll get to this), which each contain #. directories representing Kubernetes namespaces, which each contain #. Nix modules representing a templated deployment. -This metaphor extends to charts. Both Turboprop and nixhelm, from which Turboprop borrows heavily, contain a chart tree: +We'll start with building a flake containing two applications: -#. an arbitrarily-named root, ``./charts``, which contains -#. directories representing Helm repositories, which each contain -#. Nix modules representing a(n untemplated) chart. +- the `Gateway API`_, and +- `Breezewiki`_ (through `app-template`_). -In practice:: +.. _Gateway API: https://gateway-api.sigs.k8s.io/ +.. _Breezewiki: https://gateway-api.sigs.k8s.io/ +.. _app-template: https://bjw-s.github.io/helm-charts/docs/app-template/ - $ nix run nixpkgs#tree -- ~/src/kubernetes/{chart,service}s --noreport - /home/ag/src/kubernetes/charts - ├── kubernetes-dashboard - │   └── kubernetes-dashboard - │   └── default.nix - <...> - /home/ag/src/kubernetes/services - <...> - ├── istio-system - │   ├── 1-18-1 - │   │   └── default.nix - │   └── kiali - │   └── default.nix - └── svc - ├── breezewiki - │   └── default.nix - <...> - └── vaultwarden -    └── default.nix +Normally, one would also deploy a Gateway controller, but this suffices for the example. -You may have noticed that, if neither Nixhelm nor Turboprop provide a chart you need, you may define it within your flake. (PRs welcome, though.) +.. code-block:: nix -Builders -=========================== + # services/gateway-system/gateway-api/default.nix + {lib, ...}: { + builder = lib.builders.derivation; + args = { + src = lib.fetchers.remoteYAMLFile rec { + version = "1.0.0"; + url = "https://github.com/kubernetes-sigs/gateway-api/releases/download/v${version}/experimental-install.yaml"; + hash = "sha256-bGAdzteHKpQNdvpmeuEmunGMtMbblw0Lq0kSjswRkqM="; + }; + }; + } -*Builders* are Nix functions that build a derivation, be it of a chart, a service, or a service's extra objects. +.. code-block:: nix + # services/default/breezewiki/default.nix + {charts, lib, user, ...}: { + builder = user.app-template.build; + args = { + mainImage = "quay.io/pussthecatorg/breezewiki:latest"; + values = { + service.main.ports.http.port = 10416; + route.main = { + enabled = true; + hostnames = ["breezewiki.example.com"]; + parentRefs = [ + { + name = "gateway"; + namespace = "default"; + sectionName = "https"; + } + ]; + rules = [ + { + backendRefs = [ + { + name = "breezewiki"; + namespace = "default"; + port = 10416; + } + ]; + } + ]; + }; + }; + }; + } +Ordering services by provided APIs +================================== -Services and system services -============================ - - - -.. TODO -- Helm cannot see your cluster from inside the sandbox. -- Custom APIs must be gathered and passed explicitly. -- This can't be done in one step due to infinite recursion. - -Finally: your flake's output -============================ ********* Reference ********* -Utilities -========= +Library +======= -Charts -====== +mkDerivation +------------ Turboprop overlays `its own charts`_ atop `Nixhelm's`_. @@ -211,6 +239,15 @@ Turboprop overlays `its own charts`_ atop `Nixhelm's`_. .. _Nixhelm's: https://github.com/farcaller/nixhelm/tree/master/charts +app-template +------------ + +mkCharts +-------- + +mkChartsWithNixhelm +------------------- + Fetchers ======== @@ -277,7 +314,7 @@ helmChart Wrapped re-export of `kubelib.fromHelm`_ that sets ``metadata.namespace`` on all templated objects lacking it. As such, its signature is identical to `kubelib.buildHelmChart`_. - **chart** (derivation): The chart from which to build. -- **values** (attrset, default: ``{}``): Values to pass into the chart. +- **values** (attrs, default: ``{}``): Values to pass into the chart. - **includeCRDs** (bool, default: ``true``): Whether to include CustomResourceDefinitions in the template output. - **kubeVersion** (str, default: ``pkgs.kubernetes.version``): The Kubernetes version to target. - **apiVersions** ([str], default: ``[]``): Sets `Capabilities.APIVersions`_. @@ -286,6 +323,9 @@ Wrapped re-export of `kubelib.fromHelm`_ that sets ``metadata.namespace`` on all .. _kubelib.buildHelmChart: https://github.com/farcaller/nix-kube-generators/blob/cdb5810a8d5d553cdd0d04fa53378d5105b529b2/lib/default.nix#L82-L90 .. _Capabilities.APIVersions: https://helm.sh/docs/chart_template_guide/builtin_objects/#helm +app-template.build +------------------ + .. _SRI-style hash: https://nixos.wiki/wiki/Nix_Hash @@ -295,3 +335,17 @@ Assign extra metadata in ``namespaces.nix``. For example, ``svc = {labels."istio.io/rev" = "1-18-1"}`` is the equivalent of ``k label ns/svc istio.io/rev=1-18-1`` + +Modules +======= + +Service (unbuilt) +----------------- + +``{charts, lib, pkg, user} -> {builder, args, extraObjects}`` + + +Service (loaded) +----------------- + +``{kubeVersion, apiVersion} -> {out, extra}`` diff --git a/flake.nix b/flake.nix index 432d794..7dab35f 100644 --- a/flake.nix +++ b/flake.nix @@ -61,5 +61,9 @@ }; # TODO: make a template formatter = pkgs.alejandra; + templates.default = { + path = ./templates/default; + description = "Example Turboprop flake"; + }; }); } diff --git a/templates/default/flake.nix b/templates/default/flake.nix new file mode 100644 index 0000000..2537d09 --- /dev/null +++ b/templates/default/flake.nix @@ -0,0 +1,45 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + turboprop = { + url = "sourcehut:~goorzhel/turboprop"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + turboprop, + }: + flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs {inherit system;}; + + turbo = turboprop.lib.${system}; + + mkDerivation = turbo.mkDerivation { + user = { + app-template = turbo.app-template; + }; + }; + in { + packages.default = let + pname = "my-k8s-flake"; + in + mkDerivation { + inherit pname; + version = "rolling"; + src = builtins.path { + path = ./.; + name = pname; + }; + + serviceRoot = ./services; + nsMetadata = {}; + }; + } + ); +} diff --git a/templates/default/services/default/breezewiki/default.nix b/templates/default/services/default/breezewiki/default.nix new file mode 100644 index 0000000..05cad4f --- /dev/null +++ b/templates/default/services/default/breezewiki/default.nix @@ -0,0 +1,38 @@ +{ + charts, + lib, + user, + ... +}: { + builder = user.app-template.build; + args = { + mainImage = "quay.io/pussthecatorg/breezewiki:latest"; + values = let + port = 10416; + in { + service.main.ports.http.port = port; + route.main = { + enabled = true; + hostnames = ["breezewiki.example.com"]; + parentRefs = [ + { + name = "gateway"; + namespace = "default"; + sectionName = "https"; + } + ]; + rules = [ + { + backendRefs = [ + { + name = "breezewiki"; + namespace = "default"; + inherit port; + } + ]; + } + ]; + }; + }; + }; +} diff --git a/templates/default/services/gateway-system/gateway-api/default.nix b/templates/default/services/gateway-system/gateway-api/default.nix new file mode 100644 index 0000000..e6d3d42 --- /dev/null +++ b/templates/default/services/gateway-system/gateway-api/default.nix @@ -0,0 +1,10 @@ +{lib, ...}: { + builder = lib.builders.derivation; + args = { + src = lib.fetchers.remoteYAMLFile rec { + version = "1.0.0"; + url = "https://github.com/kubernetes-sigs/gateway-api/releases/download/v${version}/experimental-install.yaml"; + hash = "sha256-bGAdzteHKpQNdvpmeuEmunGMtMbblw0Lq0kSjswRkqM="; + }; + }; +}