1{ config, lib, pkgs, ... }:
2
3with lib;
4let
5 cfg = config.services.k3s;
6in
7{
8 # interface
9 options.services.k3s = {
10 enable = mkEnableOption "k3s";
11
12 package = mkOption {
13 type = types.package;
14 default = pkgs.k3s;
15 defaultText = "pkgs.k3s";
16 example = literalExample "pkgs.k3s";
17 description = "Package that should be used for k3s";
18 };
19
20 role = mkOption {
21 description = ''
22 Whether k3s should run as a server or agent.
23 Note that the server, by default, also runs as an agent.
24 '';
25 default = "server";
26 type = types.enum [ "server" "agent" ];
27 };
28
29 serverAddr = mkOption {
30 type = types.str;
31 description = "The k3s server to connect to. This option only makes sense for an agent.";
32 example = "https://10.0.0.10:6443";
33 default = "";
34 };
35
36 token = mkOption {
37 type = types.str;
38 description = "The k3s token to use when connecting to the server. This option only makes sense for an agent.";
39 default = "";
40 };
41
42 docker = mkOption {
43 type = types.bool;
44 default = false;
45 description = "Use docker to run containers rather than the built-in containerd.";
46 };
47
48 extraFlags = mkOption {
49 description = "Extra flags to pass to the k3s command.";
50 type = types.str;
51 default = "";
52 example = "--no-deploy traefik --cluster-cidr 10.24.0.0/16";
53 };
54
55 disableAgent = mkOption {
56 type = types.bool;
57 default = false;
58 description = "Only run the server. This option only makes sense for a server.";
59 };
60 };
61
62 # implementation
63
64 config = mkIf cfg.enable {
65 assertions = [
66 {
67 assertion = cfg.role == "agent" -> cfg.serverAddr != "";
68 message = "serverAddr should be set if role is 'agent'";
69 }
70 {
71 assertion = cfg.role == "agent" -> cfg.token != "";
72 message = "token should be set if role is 'agent'";
73 }
74 ];
75
76 virtualisation.docker = mkIf cfg.docker {
77 enable = mkDefault true;
78 };
79
80 # TODO: disable this once k3s supports cgroupsv2, either by docker
81 # supporting it, or their bundled containerd
82 systemd.enableUnifiedCgroupHierarchy = false;
83
84 systemd.services.k3s = {
85 description = "k3s service";
86 after = [ "network.service" "firewall.service" ] ++ (optional cfg.docker "docker.service");
87 wants = [ "network.service" "firewall.service" ];
88 wantedBy = [ "multi-user.target" ];
89 serviceConfig = {
90 # See: https://github.com/rancher/k3s/blob/dddbd16305284ae4bd14c0aade892412310d7edc/install.sh#L197
91 Type = if cfg.role == "agent" then "exec" else "notify";
92 KillMode = "process";
93 Delegate = "yes";
94 Restart = "always";
95 RestartSec = "5s";
96 LimitNOFILE = 1048576;
97 LimitNPROC = "infinity";
98 LimitCORE = "infinity";
99 TasksMax = "infinity";
100 ExecStart = concatStringsSep " \\\n " (
101 [
102 "${cfg.package}/bin/k3s ${cfg.role}"
103 ] ++ (optional cfg.docker "--docker")
104 ++ (optional cfg.disableAgent "--disable-agent")
105 ++ (optional (cfg.role == "agent") "--server ${cfg.serverAddr} --token ${cfg.token}")
106 ++ [ cfg.extraFlags ]
107 );
108 };
109 };
110 };
111}