Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

TELEICU/Path B: NixOS: Difference between revisions

From OHC Network Wiki
Content deleted Content added
Create TELEICU Path B: NixOS guide (via create-page on MediaWiki MCP Server)
 
Replace ASCII art with Mermaid diagrams (via update-page on MediaWiki MCP Server)
Line 12: Line 12:
Every hospital PC runs NixOS with identical, pinned system configuration. A flake repository defines the full OS state — packages, services, users, firewall, K3s agent — and nodes converge to the declared state via <code>comin</code> (pull-based, primary) or <code>deploy-rs</code> (push-based, backup).
Every hospital PC runs NixOS with identical, pinned system configuration. A flake repository defines the full OS state — packages, services, users, firewall, K3s agent — and nodes converge to the declared state via <code>comin</code> (pull-based, primary) or <code>deploy-rs</code> (push-based, backup).


<pre>
syntaxhighlight lang="text"
{{#mermaid:flowchart TB
┌──────────────────────┐
subgraph Repo["Flake Repository"]
│ Flake repository │
FLAKE["flake.nix<br/>all node configs"]
│ (Nix flake, │
end
│ all node configs) │

└──────────┬───────────┘
subgraph Primary["Primary Path"]
├── comin (pull) ──── primary path
COMIN["comin (pull)<br/>each node polls<br/>for new generation"]
end
│ └─ each node polls for new generation

subgraph Backup["Backup Path"]
└── deploy-rs (push) ── backup path
└─ triggered from CI for urgent deploys
DEPLOY["deploy-rs (push)<br/>triggered from CI<br/>for urgent deploys"]
end
syntaxhighlight

FLAKE --> COMIN
FLAKE --> DEPLOY

COMIN --> N1["Spoke Node<br/>NixOS + K3s agent"]
COMIN --> N2["Hub Node<br/>NixOS + K3s agent"]
COMIN --> NM["... (200 more)"]

DEPLOY --> N1
DEPLOY --> N2
}}
</pre>


== Provisioning (zero-touch) ==
== Provisioning (zero-touch) ==
Line 85: Line 97:
== Repository structure ==
== Repository structure ==


<pre>
syntaxhighlight lang="text"
{{#mermaid:flowchart LR
teleicu-nixos/
subgraph Flake["teleicu-nixos/"]
├── flake.nix # inputs + outputs
├── flake.lock
FLAKE_NIX["flake.nix<br/>flake.lock"]
HOSTS["hosts/<br/>cp-1/<br/>cp-2/<br/>cp-3/<br/>spoke-template/<br/>hub-template/"]
├── hosts/
MODULES["modules/<br/>tailscale.nix<br/>k3s-agent.nix<br/>cloudflared.nix<br/>zfs.nix<br/>openebs.nix<br/>monitoring.nix<br/>downtime-classifier.nix"]
│ ├── cp-1/ # control plane VM 1
PROFILES["profiles/<br/>base.nix<br/>spoke.nix<br/>hub.nix"]
│ │ ├── configuration.nix
SECRETS["secrets/"]
│ │ └── hardware-configuration.nix
ISO["iso/<br/>bootstrap.nix"]
│ ├── cp-2/
COMIN_CFG["comin/<br/>configuration.nix"]
│ ├── cp-3/
end
│ ├── spoke-template/ # template for spoke nodes
}}
│ │ ├── configuration.nix
</pre>
│ │ └── hardware-configuration.nix
│ └── hub-template/ # template for hub nodes
├── modules/
│ ├── tailscale.nix
│ ├── k3s-agent.nix
│ ├── cloudflared.nix
│ ├── zfs.nix
│ ├── openebs.nix
│ ├── monitoring.nix
│ └── downtime-classifier.nix
├── profiles/
│ ├── base.nix # shared across all nodes
│ ├── spoke.nix # spoke-specific additions
│ └── hub.nix # hub-specific additions
├── secrets/ # encrypted via sops-nix
│ └── …
├── iso/
│ └── bootstrap.nix # nixos-generator config for install ISO
└── comin/
└── configuration.nix # comin poll config
syntaxhighlight


== Flake structure ==
== Flake structure ==

Revision as of 08:25, 6 July 2026

guideteleicuCARE 3.0+

Full architecture and workflow for the NixOS migration path.

Architecture

Every hospital PC runs NixOS with identical, pinned system configuration. A flake repository defines the full OS state — packages, services, users, firewall, K3s agent — and nodes converge to the declared state via comin (pull-based, primary) or deploy-rs (push-based, backup).

{{#mermaid:flowchart TB
    subgraph Repo["Flake Repository"]
        FLAKE["flake.nix<br/>all node configs"]
    end

    subgraph Primary["Primary Path"]
        COMIN["comin (pull)<br/>each node polls<br/>for new generation"]
    end

    subgraph Backup["Backup Path"]
        DEPLOY["deploy-rs (push)<br/>triggered from CI<br/>for urgent deploys"]
    end

    FLAKE --> COMIN
    FLAKE --> DEPLOY

    COMIN --> N1["Spoke Node<br/>NixOS + K3s agent"]
    COMIN --> N2["Hub Node<br/>NixOS + K3s agent"]
    COMIN --> NM["... (200 more)"]

    DEPLOY --> N1
    DEPLOY --> N2
}}

Provisioning (zero-touch)

New sites are provisioned using a custom ISO generated with nixos-generator:

  1. The ISO boots with a pre-configured Cloudflare Tunnel or Tailscale connection already active
  2. A bootstrap script on the ISO initiates nixos-anywhere over the tunnel
  3. nixos-anywhere partitions the disk (ZFS via disko) and installs NixOS
  4. The node reboots into its NixOS generation and registers as a K3s agent
  5. comin starts polling for configuration updates

What NixOS manages

  • Every system package, kernel parameter, and service
  • Tailscale configuration and bringup
  • K3s agent installation, config, and auto-join
  • Cloudflare tunnel service (cloudflared)
  • ZFS dataset layout and mount points
  • OpenEBS localPV provisioner for K3s
  • Monitoring agent, log shipper, downtime classifier
  • Firewall rules (strict — only Tailscale + K3s + tunnel outbound)
  • sops-nix secret decryption at build time

What K3s manages

  • Middleware container deployments
  • Service discovery, ingress, workload scaling
  • Identity as a Kubernetes node (identical to Path A at this layer)

Storage

ZFS + OpenEBS localPV:

  • Root pool: mirrored (if multiple disks) or single-disk with regular snapshots
  • LocalPV datasets for stateful middleware workloads
  • ZFS snapshots via sanoid/syncoid for fast backup
  • Off-site backup via restic or zfs send to S3

Rollback

  • Instant: nixos-rebuild switch --rollback reverts to the previous generation
  • At boot: hold Shift/space during systemd-boot to select a previous generation
  • Every NixOS generation is an atomic, bootable unit — rollback is always available even if the OS is partially broken

Update mechanism

comin is the primary path (pull-based, suited for unreliable connectivity):

- Each node polls the flake repository on a configurable interval - When a new generation is available, it builds and activates it atomically - If the build fails, the node stays on its current generation — no partial state

deploy-rs is the backup path:

- Push-based, triggered from CI for urgent/canary deploys - Requires the node to be reachable at deploy time - Used for staging and canary nodes where immediate rollout is needed

Repository structure

{{#mermaid:flowchart LR
    subgraph Flake["teleicu-nixos/"]
        FLAKE_NIX["flake.nix<br/>flake.lock"]
        HOSTS["hosts/<br/>cp-1/<br/>cp-2/<br/>cp-3/<br/>spoke-template/<br/>hub-template/"]
        MODULES["modules/<br/>tailscale.nix<br/>k3s-agent.nix<br/>cloudflared.nix<br/>zfs.nix<br/>openebs.nix<br/>monitoring.nix<br/>downtime-classifier.nix"]
        PROFILES["profiles/<br/>base.nix<br/>spoke.nix<br/>hub.nix"]
        SECRETS["secrets/"]
        ISO["iso/<br/>bootstrap.nix"]
        COMIN_CFG["comin/<br/>configuration.nix"]
    end
}}

Flake structure

flake.nix exposes:

- nixosConfigurations for each host (CP VMs + spoke/hub templates) - cominConfigurations for comin-based auto-updates - packages for the bootstrap ISO - devShells for development tooling