Colmena
Colmena
Goal: Express a small hive with Colmena, deploy at least two nodes (one may be local), use tags, and know when Colmena wins over deploy-rs for fleet shape. Hosts pin NixOS 26.05.
deploy-rs is excellent node/profile oriented glue. Colmena shines when you think in hives: many hosts, tags (@web, @db), parallel apply, and a flake hive attribute. Real orgs often evaluate both; leave ops with a deliberate choice, not two half-wired tools forever.
Why it matters
One remote deploy proves the pipe. Fleets need selection, defaults, and blast-radius control. Colmena’s mental model maps cleanly onto roles you will build in the shared modules chapter.
Theory 1 — Hive mental model
meta (nixpkgs, specialArgs)
nodes
host-a → NixOS module stack
host-b → …
defaults → shared modules
| Concept | Role |
|---|---|
meta.nixpkgs |
Package set for evaluation |
defaults |
Applied to every node |
nodes.<name> |
Per-host config + deployment keys |
| tags | Selection subsets for apply |
specialArgs |
Inject libs/secrets helpers carefully |
Theory 2 — Flake-based Colmena (modern)
{
description = "colmena hive lab";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
outputs = { self, nixpkgs, ... }: {
colmena = {
meta = {
nixpkgs = import nixpkgs { system = "x86_64-linux"; };
# specialArgs = { inherit inputs; };
};
defaults = { pkgs, ... }: {
# shared baseline modules
imports = [ ../modules/profiles/baseline.nix ];
system.stateVersion = "26.05";
deployment.tags = [ "all" ];
};
edge = { name, nodes, ... }: {
deployment = {
targetHost = "edge.lab.internal";
targetUser = "root";
tags = [ "web" "edge" ];
};
imports = [ ../hosts/edge/configuration.nix ];
};
db = {
deployment = {
targetHost = "db.lab.internal";
targetUser = "root";
tags = [ "db" ];
};
imports = [ ../hosts/db/configuration.nix ];
};
};
};
}CLI shapes evolve—typical patterns:
nix shell nixpkgs#colmena -c colmena --help
colmena build
colmena apply --on @web
colmena apply-local --sudo # local node storiesConfirm current Colmena flake attribute and CLI against upstream docs for your pin.
Theory 4 — Evaluation vs activation
colmena build → realize all selected system closures
colmena apply → build + copy + switch on targets
| Command family | Risk |
|---|---|
| build/eval only | Low—catches module errors |
| apply one tag | Medium |
| apply all | High |
Wire flake checks that eval the hive even when you do not apply.
Theory 5 — Relationship to nixosConfigurations
Many flakes expose both:
nixosConfigurations.edge = nixpkgs.lib.nixosSystem { … };
# colmena.nodes.edge imports same modules| Approach | Pros |
|---|---|
| Single module entry per host | DRY |
| Generate Colmena from nixosConfigurations | Less drift |
| Separate trees | Fast way to diverge—avoid |
Shared modules chapter makes this maintainable.
Theory 6 — When Colmena vs deploy-rs
| Situation | Lean |
|---|---|
| 1–3 nodes, profile/rollback focus | deploy-rs |
| Many nodes, tags, parallel ops | Colmena |
| Already invested in one | Don’t dual-run forever |
| Need both temporarily | Document primary |
Write a decision paragraph in notes after you deploy with both once (or one deeply).
Theory 7 — Secrets and specialArgs
meta = {
nixpkgs = import nixpkgs { system = "x86_64-linux"; };
specialArgs = { inherit inputs; };
};| Inject | Careful of |
|---|---|
inputs |
Large eval; fine when needed |
| Secret paths | OK |
| Secret strings | Never—store contamination |
sops-nix still decrypts on the host; Colmena only delivers config that references paths.
Worked example — two-node hive (one local)
colmena = {
meta.nixpkgs = import nixpkgs { system = "x86_64-linux"; };
defaults = {
deployment.tags = [ "all" ];
services.openssh.enable = true;
system.stateVersion = "26.05";
};
laptop = {
deployment = {
allowLocalDeployment = true;
targetHost = null; # local patterns per docs
tags = [ "local" ];
};
environment.etc."hive-proof".text = "laptop\n";
};
vm = {
deployment = {
targetHost = "192.0.2.50";
targetUser = "root";
tags = [ "vm" "web" ];
};
environment.etc."hive-proof".text = "vm\n";
imports = [ ./hosts/vm.nix ];
};
};colmena apply --on @vm
ssh root@192.0.2.50 cat /etc/hive-proofLab — multi-step
Suggested notes: ~/lab/nixos/ops/colmena
Step 1 — Install Colmena in a shell
nix shell nixpkgs#colmena -c colmena --versionStep 2 — Define hive with defaults
Baseline SSH + stateVersion + one shared import.
Step 3 — Two nodes
One may be local; one remote VM. Distinct hive-proof texts.
Step 4 — Build only
colmena build
# or build --on @vmFix eval errors before apply.
Step 5 — Apply tagged subset
Apply only @vm (or equivalent). Prove file on remote.
Step 6 — Tag experiment
Add @web; apply by tag; document selection syntax you used.
Step 7 — Blast-radius note
Write: “scary change procedure” = canary host → tag → all.
Step 8 — Decision card
Colmena vs deploy-rs for your lab size.
Step 9 — Optional parallel apply
Apply two nodes; note ordering/logs; decide if parallel is for you.
Step 10 — DRY modules
Point both nodes at a shared profile module (preview of shared modules chapter).
Exercises
- Design tags for web/db/obs/canary.
- Eval-only CI job sketch for the hive.
- Failure mode: wrong
targetHost—what do logs show?
- Convert a deploy-rs node list into a Colmena hive sketch.
- Security: who can run
colmena apply --on @all?
Common gotchas
| Symptom / mistake | What to do |
|---|---|
| Applied all nodes by accident | Tags; confirm prompts; canary |
| Hive eval huge/slow | Reduce specialArgs; modularize |
| Drift vs nixosConfigurations | Share modules |
| Local deploy confusion | Read allowLocalDeployment docs |
| SSH user wrong | targetUser + keys |
| Mixed nixpkgs | Single meta.nixpkgs |
| Parallel firewall change | Serial + console |
| Secrets in hive attrset | Paths only |
Checkpoint
- Hive evaluates
- At least one remote (or local) apply succeeded
- Tags used for selection
- Build-only vs apply distinction clear
- Decision note vs deploy-rs
- Blast-radius procedure written
Commit
git add .
git commit -m "ops: colmena hive and tags"Write three personal gotchas before shared modules.