nixcon-2024-presentation-pu.../presentation.md
2024-11-02 16:30:24 +01:00

7.9 KiB

marp theme paginate footer
true gaia true October 26th, 2024

Kubenix: Leveraging NixOS modules to generate Kubernetes manifests

bg right:35% 100% Kubenix logo

Pim Kunis


Agenda

bg right:60% 80%

  1. My background
  2. Kubernetes
  3. Kubenix

$ whoami

bg right 60% drop-shadow:0,5px,10px,rgba(0,0,0,.7)

  • Pim Kunis
    • Matrix: @pim:envs.net
    • GitHub: @pizzapim
  • Consultant @ Sue
    • Currently doing Linux + Ansible stuff
  • Relatively new to Nix
  • Avid self-hoster

Self-hosting

bg Logos of services I self-host


Self-hosting

3 mini PCs (Gigabyte Brix with Intel Celeron J4105)

w:900 My servers in their closet


NixOS for a cluster?

w:900 My servers in their closet


NixOS for a cluster?

bg right assets/cat-chewing-cable.jpg

  • Balance services
  • Maintenance
  • Services are tied to a particular host
    • Pets vs cattle

Agenda

  1. My background
  2. Kubernetes
  3. Kubenix

Enter: Kubernetes

bg left:40% 100% assets/cat-chewing-cable.jpg

  • Abstracts infrastructure
  • Container orchestration
    • Workloads are containers (pods)
  • Distributed state (etcd)
    • Actual state
    • Desired state
    • Reconciliation

Kubernetes

w:900 My servers in their closet


Kubernetes

w:900 My servers in their closet


Kubernetes

w:900 My servers in their closet


Mutating state in Kubernetes

bg 80% hi


Mutating state in Kubernetes

bg 80% hi


Mutating state in Kubernetes

bg 80% hi


Mutating state in Kubernetes

bg 80% hi


Helm

bg right:50% 60%

  • Package manager
  • Templating YAML
  • Cursed

Helm

bg 80% hi


Helm

bg 80% hi


Helm

bg 80% hi


Agenda

  1. My background
  2. Kubernetes
  3. Kubenix

Kubenix

  • Generate manifests using NixOS modules!
  • Benefits:
    • No ugly YAML templates
    • Functional language
    • Type and structure checking
    • Modularity

How Kubenix works

  1. My background
  2. Kubernetes
  3. Kubenix
    • OpenAPI specification
    • Generate NixOS module
    • Use generated module
    • Generate manifest

The OpenAPI spec

  • Standard for describing APIs
  • YAML or JSON
  • Specifies how to interact with Kubernetes API

The OpenAPI spec

bg 75% hi


The OpenAPI spec

bg 75% hi


The OpenAPI spec

bg 75% hi


How Kubenix works

  1. My background
  2. Kubernetes
  3. Kubenix
    • OpenAPI specification
    • Generate NixOS module
    • Use generated module
    • Generate manifest

Generating the NixOS module

  • Generate Nix code
    • Templating?

Generating the NixOS module

''
definitions = {
  # Here we loop over each "definition"
  ${concatStrings (mapAttrsToList (name: value: ''
  "${name}" = {
    ${optionalString (hasAttr "options" value) "
      options = {${concatStrings (mapAttrsToList (name: value: ''                                                            
      "${name}" = ${value};
    '')
    value.options)}};
      "}

    ${optionalString (hasAttr "config" value) ''
    config = {${concatStrings (mapAttrsToList (name: value: ''
        "${name}" = ${value};
      '')
      value.config)}};
  ''}
  };
'')
definitions)}
};
''

The generated NixOS module

    "io.k8s.api.core.v1.Pod" = {
      options = {
        "apiVersion" = mkOption {
          description = "...";
          type = (types.nullOr types.str);
        };
        "kind" = mkOption {
          description = "...";
          type = (types.nullOr types.str);
        };
        "metadata" = mkOption {
          description = "...";
          type = (types.nullOr (submoduleOf "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"));                                  
        };
        "spec" = mkOption {
          description = "...";
          type = (types.nullOr (submoduleOf "io.k8s.api.core.v1.PodSpec"));
        };
        "status" = mkOption {
          description = "...";
          type = (types.nullOr (submoduleOf "io.k8s.api.core.v1.PodStatus"));
        };
      };
    };

How Kubenix works

  1. My background
  2. Kubernetes
  3. Kubenix
    • OpenAPI specification
    • Generate NixOS module
    • Use generated module
    • Generate manifest

Using the module

bg 70% hi


Using the module

bg 70% hi


Using the module

bg 70% hi


Using the module

bg 70% hi


Using the module

bg 70% hi


Example of type checking

{
    kubernetes.resources.pods.example-pod = {
        spec.containers.jellyfin-container = {
            image = "jellyfin/jellyfin:latest";
            ports = [{ containerPort = "foo"; }];
        };
    };
};
 error: A definition for option `kubernetes.(...).containerPort' is not of type `signed integer'.

An undefined option

{
    kubernetes.resources = {
        foo.bar = "baz";
    }
}
error: The option `kubernetes.api.resources.foo' does not exist.

How Kubenix works

  1. My background
  2. Kubernetes
  3. Kubenix
    • OpenAPI specification
    • Generate NixOS module
    • Use generated module
    • Generate manifest

kubenix.evalModules

{
  inputs.kubenix.url = "github:hall/kubenix";
  outputs = {self, kubenix, ... }@inputs: let
    system = "x86_64-linux";
  in {
    packages.${system}.default = (kubenix.evalModules.${system} {
      module = { kubenix, ... }: {
        imports = [ kubenix.modules.k8s ];
        kubernetes.resources.pods.example.spec.containers.jellyfin.image = "jellyfin/jellyfin:latest";
      };
    }).config.kubernetes.result;
  };
}

kubenix.evalModules

{
  "apiVersion": "v1",
  "items": [
    {
      "apiVersion": "v1",
      "kind": "Pod",
      "metadata": {
        "annotations": {
          "kubenix/k8s-version": "1.30",
          "kubenix/project-name": "kubenix"
        },
        "labels": {
          "kubenix/hash": "84130bb6a26b9066eb2bdcaf2e68148a6e0648b0"                                                                                                                  
        },
        "name": "example"
      },
      "spec": {
        "containers": [
          {
            "image": "jellyfin/jellyfin:latest",
            "name": "jellyfin"
          }
        ]
      }
    }
  ],
  "kind": "List",
  "labels": {
    "kubenix/hash": "84130bb6a26b9066eb2bdcaf2e68148a6e0648b0",
    "kubenix/k8s-version": "1.30",
    "kubenix/project-name": "kubenix"
  }
}

Summary

  • Kubenix generates Kubernetes manifests
  • Converts OpenAPI spec to a NixOS module
  • Build Kubernetes deployments with:
    • No ugly YAML templates
    • Modularity
    • In a functional language
    • Type and structure checking

Terraform: OpenAPI Provider Spec Generator

hoi


Bonus: nix-snapshotter

bg right:50% 100%

  • Images are in Nix store
  • Fully declarative

Bonus: NixNG

bg right:50% 100%

  • NixOS in a container
  • init-system independent