deploy-rs

repository·master·Indexed 24 days ago

https://github.com/serokell/deploy-rs

A multi-profile Nix flake deployment tool (version 0.1.0) that enables independent updates of different profiles, such as NixOS system configs or home-manager configs, to various nodes. It features 'Magic Rollback' to prevent connectivity loss, activation helpers for NixOS, nix-darwin, and home-manager, and a CLI for managing deployments, activations, and profile revocations.

Tokens
6.5K
Snippets
16
Records
31
Agent score
81%

What's inside deploy-rs

  1. What is Magic Rollback?

    master

    Magic Rollback is a safety feature that prevents changes from rendering a machine unconnectable.

    How it works:

    1. deploy-rs activates the new profile.
    2. It then attempts to connect to the machine to confirm it is still available.
    3. If the connection cannot be established within the confirmTimeout, the target node is instructed to automatically roll back to the previous state.

    Warning: If you are changing settings that affect your ability to connect (e.g., changing the SSH port, changing the IP address, or changing firewall rules), you must either disable magicRollback in your configuration or use the CLI flag to override it.

  2. Define a Profile in deploy-rs

    master

    A profile is the core unit of deployment. You can define multiple profiles per node, allowing for independent updates (e.g., a system profile and a user profile).

    {
      # A derivation containing your required software, and a script to activate it in `${path}/deploy-rs-activate"
      path = deploy-rs.lib.x86_64-linux.activate.custom pkgs.hello "./bin/hello";
    
      # Optional: custom installation path
      profilePath = "/home/someuser/.local/state/nix/profiles/someprofile";
    
      # ...generic options...
    }
  3. Define a Node in deploy-rs

    master

    A node represents a single server and contains its associated profiles.

    {
      # The hostname of your server.
      hostname = "my.server.gov";
    
      # Optional: order in which profiles are deployed when running `deploy <flake>`
      profilesOrder = [ "something" "system" ];
    
      profiles = {
        system = {};
        something = {};
      };
    
      # ...generic options...
    }
  4. Deploy a NixOS system using deploy-rs

    master

    This example demonstrates the workflow for deploying a full NixOS system with a separate user unit to a bare machine. The process involves building a virtual machine for testing and then using deploy-rs for the actual deployment.

    Deployment Workflow

    1. Build and run the bare system in a VM for testing:

      • Build the VM configuration:
        nix build .#nixosConfigurations.bare.config.system.build.vm
      • Run the VM with port forwarding to access SSH (forwarding host port 2221 to guest port 22):
        QEMU_NET_OPTS=hostfwd=tcp::2221-:22 ./result/bin/run-bare-system-vm
    2. Execute deployment: Use deploy-rs to perform the deployment to the target machine:

      nix run github:serokell/deploy-rs
    nix build .#nixosConfigurations.bare.config.system.build.vm
    QEMU_NET_OPTS=hostfwd=tcp::2221-:22 ./result/bin/run-bare-system-vm
    nix run github:serokell/deploy-rs
  5. Deploy a nix-darwin system using deploy-rs

    master

    To deploy a nix-darwin configuration to a macOS machine, use deploy-rs via nix run. You must specify the target user via the --ssh-user flag.

    Prerequisites

    1. Target Machine Setup:
      • Install nix and nix-darwin on the target macOS machine. nix-darwin is required to ensure /run is created and /etc/nix/nix.conf is correctly symlinked.
      • Enable Remote Login in macOS settings to allow SSH access.
    2. Permissions:
      • The sshUser must have passwordless sudo access, as deploy-rs does not support password provisioning for sudo commands.
    nix run github:serokell/deploy-rs -- --ssh-user <user>
  6. Use the deploy CLI

    master

    The deploy command is used to deploy Nix flakes to your nodes.

    Basic Syntax

    deploy [options] <flake>

    • Deploy all profiles: deploy <flake> (respects profilesOrder).
    • Deploy a specific node: deploy <flake>#<node>.
    • Deploy a specific profile: deploy <flake>#<node>.<profile>.
    • Handle special characters: If your profile or node name contains a dot (.), wrap the target in quotes to avoid shell escaping, e.g., 'my-flake#"myserver.com".system'.
    • Pass arguments to Nix: Use -- to pass extra arguments to Nix calls (e.g., deploy . -- --impure).
    • Deploy multiple flakes: Use deploy --targets <flake> [<flake> ...] to deploy a subset of flakes in one invocation. If any deployment fails, all successful ones are rolled back by default.

    Environment Variables

    • LOCAL_KEY: Specify the path to a signing key if you need to push closures to your server.
    deploy . -- --impure
  7. Configure a Nix flake for deploy-rs

    master

    To use deploy-rs, your Nix flake should include deploy-rs as an input and define a deploy attribute. It is highly recommended to use deploy-rs.lib.<system>.deployChecks to validate your configuration using nix flake check.

    Basic Flake Structure

    {
      description = "Deployment for my server cluster";
    
      # For accessing `deploy-rs`'s utility Nix functions
      inputs.deploy-rs.url = "github:serokell/deploy-rs";
    
      outputs = { self, nixpkgs, deploy-rs }: {
        nixosConfigurations.some-random-system = nixpkgs.lib.nixosSystem {
          system = "x86_64-linux";
          modules = [ ./some-random-system/configuration.nix ];
        };
    
        deploy.nodes.some-random-system = {
            hostname = "some-random-system";
            profiles.system = {
              user = "root";
              path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.some-random-system;
            };
        };
    
        # This is highly advised, and will prevent many possible mistakes
        checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
      };
    }
  8. How deployment activation and rollbacks work

    master

    When deploying, deploy-rs follows a specific lifecycle:

    1. Evaluation: The Nix flake is evaluated to extract deployment data (nodes, profiles, settings).
    2. Build: Profiles are built (either locally or on the remote host if --remote-build is set).
    3. Push: Built profiles are pushed to the target nodes.
    4. Activation: The profiles are activated on the nodes.

    Rollback Logic

    If an activation fails, deploy-rs can automatically attempt to roll back to the previous successful generation. This behavior is controlled by:

    • The global --auto-rollback flag.
    • The specific profile's configuration.

    If --rollback-succeeded is enabled, deploy-rs will also revoke all previously successful deployments in the current session if a failure occurs during the activation of subsequent profiles. This ensures the cluster remains in a consistent state.

  9. Define nodes and profiles in deploy-rs configuration

    master

    The deploy-rs configuration structure is hierarchical. You define a top-level Data object containing nodes. Each node contains its own settings and a map of profiles.

    Data Hierarchy

    1. Data: The root object. Contains global GenericSettings and a map of nodes.
    2. Node: Represents a specific host. Contains hostname, a map of profiles, and an optional profilesOrder to specify the sequence in which profiles should be applied.
    3. Profile: A specific deployment configuration for a node. Contains a path (the deployment path) and its own GenericSettings which override node or global settings.
  10. Use the deploy-rs CLI to deploy Nix Flakes

    master

    The deploy-rs CLI is used to deploy Nix Flake configurations to remote or local nodes. You can specify a single target flake or multiple targets. The tool evaluates the flake to determine which nodes and profiles need deployment, builds the profiles (locally or remotely), pushes them to the target nodes, and finally activates them.

    To deploy a single flake (the default behavior if no target is provided is to use the current directory .):

    deploy-rs /path/to/your/flake

    To deploy multiple flakes alternatively:

    deploy-rs --targets /path/to/flake1 /path/to/flake2

    To use a specific file instead of treating targets as flakes (experimental):

    deploy-rs --file config.toml --targets target1 target2
    deploys
            .iter()
            .map(|f| deploy::parse_flake(f.as_str()))
            .collect::<Result<Vec<DeployFlake>, ParseFlakeError>>()?
  11. Use deploy-rs activation helpers

    master

    The deploy-rs.lib.<system>.activate set provides functions to generate the activation path for different profile types. These are used in the path field of a profile definition.

    • activate.nixos <nixosConfiguration>: Activates a NixOS system (runs switch-to-configuration).
    • activate.home-manager <hmConfiguration>: Activates a home-manager generation.
    • activate.darwin <darwinConfiguration>: Activates a nix-darwin system.
    • activate.custom <drv> "<activation command>": Wraps a derivation with a custom activation script. The script has access to ${path}/deploy-rs-activate, and the working directory and $PROFILE variable point to the profile path.
    • activate.profile <drv>: Installs a package or buildEnv into the target user's nix profile, replacing previous generations of the same name.
    • activate.noop <drv>: Deploys the closure without running any activation.