NixOps4

  • Why
  • What
  • How

Robert Hensing
@roberth

fediversity.eu

@roberth


Robert Hensing

  • Hercules CI
  • Nix Steering Committee
  • Nix team
  • Module System / flake-parts / modular services / single package fixpoint
  • NixOps4

Fediversity.eu

  • NLNet
  • NORDUnet
  • Tweag
  • Open Internet Discourse Foundation

Fediversity.eu

Quotes, emphasis mine:

The Fediversity Project is a comprehensive effort to bring easy-to-use, hosted cloud services that have service portability and personal freedom at their core to everyone.

The Fediversity Project enables easy hosting for a wide variety of fediverse platforms, all based on NixOS.

helps with decentralisation of the internet, a core principle of the NGI, by making it easier for people to participate in the Open Social Web on their own terms.

NixOps4

  • Deployment tool
  • WIP
  • Successor to NixOps

Why

2013 - 2020

  • NixOps 1 is a tool to deploy NixOS systems
  • Provisioning, secrets
  • Also resources, e.g. AWS Route53

Why

  • Testing and CI
  • Python (*)
  • Call Nix evaluator in batch, twice (bad)

Why

NixOps 2

2020 - ...

  • Plugins
  • Polyrepo

Why

NixOps 2

2020 - ...

Why

2021

@roberth

  • Still the only tool that integrates provisioning

Step back

Nix





┌────────────┐                      ┌────────────────────┐
│ Nix        │---- instantiate ---->│ Derivations        │ ↺ store path
│ expression │                      └────────────────────┘
│ language   │                                ⇑ builds
│            │                      ┌────────────────────┐
│            │                      │ Nix sandbox, store │
└────────────┘                      └────────────────────┘

Architecture

NixOps4

┌────────────┐                      ┌────────────────────┐
│ Nix        │---- configure ------>│ Resources          │ ↺ nix value
│ expression │                      └────────────────────┘
│ language   │                                ⇑ run output
│            │                      ┌────────────────────┐
│            │---- instantiate ---->│ Derivations        │ ↺ store path
│            │                      └────────────────────┘
│            │                                ⇑ builds
│            │                      ┌────────────────────┐
│            │                      │ Nix sandbox, store │
└────────────┘                      └────────────────────┘

Resource

  • Declares the existence of a real world object
  • Operations
    • Create
    • Read
    • Update
    • Delete

Deployment

Collection of resources

  • wired together with Nix expressions
  • reflecting some area of the real world

Operations

  • CRUD

  • "nix run"

    • backup
    • key rotation

Resource Provider

  • Program built with Nix
  • Called by NixOps
  • JSON over stdio

Expressions

Simplified

{ # flake.nix
  outputs = inputs: {
    nixops4Deployments.default = { resources, ... }: {
      resources = {
        <resource name> = {
          ...
        };
      };
    };
  };
}

Expressions

{ resources, ... }: {
  resources = {
    "nixos" = {
      imports = [ inputs.nixos.modules.nixops4Resource.nixos ];
      inputs = {
        ssh.privateKey = resources.sshkeypair.privateKey;
        ssh.host = resources.host;
        module = ./configuration.nix;
      };
    };
  };
}

Expressions

{ resources, ... }: {
  resources = {
    "nixos" = ...;
    "sshkeypair" = {
      type = "ssh.keypair";
      inputs = {
        state = resources.state;
      };
    };
  };
}

Expressions

{ resources, ... }: {
  resources = {
    "nixos" = ...;
    "sshkeypair" = ...;
    "state" = {
      type = "s3.object";
      inputs = {
        endpoint = "https://garage.example.com";
        bucket = "nixops4-my-project";
      };
    };
  };
}

Expressions

{ config, resources, ... }: {
  options.customers = mkOption {
    type = attrsOf (submodule ./customer.nix);
  };
  config.resources = {
    "state" = ...;
    "sshkeypair" = ...;
    "nixos" = ... (foo config.customers) ...;
  };
}

Expressions

{ resources, ... }: {
  imports = [
    ./data-model.nix
    ./applications/pixelfed.nix
    ./applications/mastodon.nix
    ./applications/peertube.nix
  ];
}

Expressions

  • resources monoid in the category of endofunctors 😉
  • Structural composition like attrsOf or submodule
    • imports is mix-ins
top@{ resources, ... }: {
  resources = {
    "state" = ...;
    "my-host" = mkSequence ({ resources, ... }: {
      "sshkeypair" = ... top.resources.state.handle ...;
      "nixos" = ... resources.sshkeypair.privateKey ...;
    });
  };
}

Module author benefits

  • All-Nix development experience
  • No glue code
  • All declarative

Application benefits

"NixPanel"

  • Structured logging

  • Separate evaluator for stability

Operator benefits

CLI for the backend

Integrate arbitrary scripts, no glue code

Operator benefits

Progress

Built, but subject to fixes and improvements

  • nixops4/nixops4-eval process architecture
  • Nix C API, Rust bindings
  • Documentation tooling
  • Testing

Progress

TBD

  • mkSequence nesting / data dependencies
  • Read, Update, Delete
  • State management
  • More resources, OpenTofu

Questions

Not discussed

  • Resource naming within the state

    • read multiple => migrations
  • resourceProviderSystem

Process Architecture

  • nixops4
    • nixops4-eval -> libnixexpr etc (internal)
    • resource providers
      • nixops4-resources-local
      • nixops4-resources-opentofu (planned)
      • ...

What is the problem NixOps solves?

Also _has_ problems Testing and CI are underdeveloped Python is probably a fine language, but it did turn away contributors, and the way the code base was set up made it hard Calling the evaluator twice is both too often and too little, leading to bad workarounds.

I sincerely apologize to the authors and previous maintainers. They did a good job with the architecture they had. - Plugin system - Ossified the architecture

TODO: Explain firmly

Adds new layer on top, analogous to Nix Focus on `nix value` => precisely that; no tight coupling between NixOps and its resources NixOps4 just manages the data flows generically Another benefit - resource can be implemented in any language, with any library Not comparable to NixOps 2 architecture image. NixOps 2 is "just a script" that grew until it failed to scale and then ossified with plugins.

a. Arbitrary callable methods in resource provider b. Scripts depending on resource outputs

These are very abstract. Clarify why.

Next: zoom in on the function