at 24.11-pre 6.0 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9let 10 cfg = config.services.k3s; 11 removeOption = 12 config: instruction: 13 lib.mkRemovedOptionModule ( 14 [ 15 "services" 16 "k3s" 17 ] 18 ++ config 19 ) instruction; 20in 21{ 22 imports = [ (removeOption [ "docker" ] "k3s docker option is no longer supported.") ]; 23 24 # interface 25 options.services.k3s = { 26 enable = mkEnableOption "k3s"; 27 28 package = mkPackageOption pkgs "k3s" { }; 29 30 role = mkOption { 31 description = '' 32 Whether k3s should run as a server or agent. 33 34 If it's a server: 35 36 - By default it also runs workloads as an agent. 37 - Starts by default as a standalone server using an embedded sqlite datastore. 38 - Configure `clusterInit = true` to switch over to embedded etcd datastore and enable HA mode. 39 - Configure `serverAddr` to join an already-initialized HA cluster. 40 41 If it's an agent: 42 43 - `serverAddr` is required. 44 ''; 45 default = "server"; 46 type = types.enum [ 47 "server" 48 "agent" 49 ]; 50 }; 51 52 serverAddr = mkOption { 53 type = types.str; 54 description = '' 55 The k3s server to connect to. 56 57 Servers and agents need to communicate each other. Read 58 [the networking docs](https://rancher.com/docs/k3s/latest/en/installation/installation-requirements/#networking) 59 to know how to configure the firewall. 60 ''; 61 example = "https://10.0.0.10:6443"; 62 default = ""; 63 }; 64 65 clusterInit = mkOption { 66 type = types.bool; 67 default = false; 68 description = '' 69 Initialize HA cluster using an embedded etcd datastore. 70 71 If this option is `false` and `role` is `server` 72 73 On a server that was using the default embedded sqlite backend, 74 enabling this option will migrate to an embedded etcd DB. 75 76 If an HA cluster using the embedded etcd datastore was already initialized, 77 this option has no effect. 78 79 This option only makes sense in a server that is not connecting to another server. 80 81 If you are configuring an HA cluster with an embedded etcd, 82 the 1st server must have `clusterInit = true` 83 and other servers must connect to it using `serverAddr`. 84 ''; 85 }; 86 87 token = mkOption { 88 type = types.str; 89 description = '' 90 The k3s token to use when connecting to a server. 91 92 WARNING: This option will expose store your token unencrypted world-readable in the nix store. 93 If this is undesired use the tokenFile option instead. 94 ''; 95 default = ""; 96 }; 97 98 tokenFile = mkOption { 99 type = types.nullOr types.path; 100 description = "File path containing k3s token to use when connecting to the server."; 101 default = null; 102 }; 103 104 extraFlags = mkOption { 105 description = "Extra flags to pass to the k3s command."; 106 type = types.str; 107 default = ""; 108 example = "--no-deploy traefik --cluster-cidr 10.24.0.0/16"; 109 }; 110 111 disableAgent = mkOption { 112 type = types.bool; 113 default = false; 114 description = "Only run the server. This option only makes sense for a server."; 115 }; 116 117 environmentFile = mkOption { 118 type = types.nullOr types.path; 119 description = '' 120 File path containing environment variables for configuring the k3s service in the format of an EnvironmentFile. See systemd.exec(5). 121 ''; 122 default = null; 123 }; 124 125 configPath = mkOption { 126 type = types.nullOr types.path; 127 default = null; 128 description = "File path containing the k3s YAML config. This is useful when the config is generated (for example on boot)."; 129 }; 130 }; 131 132 # implementation 133 134 config = mkIf cfg.enable { 135 assertions = [ 136 { 137 assertion = cfg.role == "agent" -> (cfg.configPath != null || cfg.serverAddr != ""); 138 message = "serverAddr or configPath (with 'server' key) should be set if role is 'agent'"; 139 } 140 { 141 assertion = 142 cfg.role == "agent" -> cfg.configPath != null || cfg.tokenFile != null || cfg.token != ""; 143 message = "token or tokenFile or configPath (with 'token' or 'token-file' keys) should be set if role is 'agent'"; 144 } 145 { 146 assertion = cfg.role == "agent" -> !cfg.disableAgent; 147 message = "disableAgent must be false if role is 'agent'"; 148 } 149 { 150 assertion = cfg.role == "agent" -> !cfg.clusterInit; 151 message = "clusterInit must be false if role is 'agent'"; 152 } 153 ]; 154 155 environment.systemPackages = [ config.services.k3s.package ]; 156 157 systemd.services.k3s = { 158 description = "k3s service"; 159 after = [ 160 "firewall.service" 161 "network-online.target" 162 ]; 163 wants = [ 164 "firewall.service" 165 "network-online.target" 166 ]; 167 wantedBy = [ "multi-user.target" ]; 168 path = optional config.boot.zfs.enabled config.boot.zfs.package; 169 serviceConfig = { 170 # See: https://github.com/rancher/k3s/blob/dddbd16305284ae4bd14c0aade892412310d7edc/install.sh#L197 171 Type = if cfg.role == "agent" then "exec" else "notify"; 172 KillMode = "process"; 173 Delegate = "yes"; 174 Restart = "always"; 175 RestartSec = "5s"; 176 LimitNOFILE = 1048576; 177 LimitNPROC = "infinity"; 178 LimitCORE = "infinity"; 179 TasksMax = "infinity"; 180 EnvironmentFile = cfg.environmentFile; 181 ExecStart = concatStringsSep " \\\n " ( 182 [ "${cfg.package}/bin/k3s ${cfg.role}" ] 183 ++ (optional cfg.clusterInit "--cluster-init") 184 ++ (optional cfg.disableAgent "--disable-agent") 185 ++ (optional (cfg.serverAddr != "") "--server ${cfg.serverAddr}") 186 ++ (optional (cfg.token != "") "--token ${cfg.token}") 187 ++ (optional (cfg.tokenFile != null) "--token-file ${cfg.tokenFile}") 188 ++ (optional (cfg.configPath != null) "--config ${cfg.configPath}") 189 ++ [ cfg.extraFlags ] 190 ); 191 }; 192 }; 193 }; 194}