1 { config, lib, options, pkgs, ... }:
6 cfg = config.services.kubernetes;
7 opt = options.services.kubernetes;
9 defaultContainerdSettings = {
11 root = "/var/lib/containerd";
12 state = "/run/containerd";
16 address = "/run/containerd/containerd.sock";
19 plugins."io.containerd.grpc.v1.cri" = {
20 sandbox_image = "pause:latest";
23 bin_dir = "/opt/cni/bin";
27 containerd.runtimes.runc = {
28 runtime_type = "io.containerd.runc.v2";
29 options.SystemdCgroup = true;
34 mkKubeConfig = name: conf: pkgs.writeText "${name}-kubeconfig" (builtins.toJSON {
39 cluster.certificate-authority = conf.caFile or cfg.caFile;
40 cluster.server = conf.server;
45 client-certificate = conf.certFile;
46 client-key = conf.keyFile;
56 current-context = "local";
61 etcdEndpoints = ["https://${cfg.masterAddress}:2379"];
63 mkCert = { name, CN, hosts ? [], fields ? {}, action ? "",
64 privateKeyOwner ? "kubernetes" }: rec {
65 inherit name caCert CN hosts fields action;
67 key = secret "${name}-key";
69 owner = privateKeyOwner;
76 secret = name: "${cfg.secretsPath}/${name}.pem";
78 mkKubeConfigOptions = prefix: {
80 description = lib.mdDoc "${prefix} kube-apiserver server address.";
85 description = lib.mdDoc "${prefix} certificate authority file used to connect to kube-apiserver.";
86 type = types.nullOr types.path;
88 defaultText = literalExpression "config.${opt.caFile}";
92 description = lib.mdDoc "${prefix} client certificate file used to connect to kube-apiserver.";
93 type = types.nullOr types.path;
98 description = lib.mdDoc "${prefix} client key file used to connect to kube-apiserver.";
99 type = types.nullOr types.path;
106 (mkRemovedOptionModule [ "services" "kubernetes" "addons" "dashboard" ] "Removed due to it being an outdated version")
107 (mkRemovedOptionModule [ "services" "kubernetes" "verbose" ] "")
112 options.services.kubernetes = {
114 description = lib.mdDoc ''
115 Kubernetes role that this machine should take.
117 Master role will enable etcd, apiserver, scheduler, controller manager
118 addon manager, flannel and proxy services.
119 Node role will enable flannel, docker, kubelet and proxy services.
122 type = types.listOf (types.enum ["master" "node"]);
126 description = lib.mdDoc "Kubernetes package to use.";
127 type = types.package;
128 default = pkgs.kubernetes;
129 defaultText = literalExpression "pkgs.kubernetes";
132 kubeconfig = mkKubeConfigOptions "Default kubeconfig";
134 apiserverAddress = mkOption {
135 description = lib.mdDoc ''
136 Clusterwide accessible address for the kubernetes apiserver,
137 including protocol and optional port.
139 example = "https://kubernetes-apiserver.example.com:6443";
144 description = lib.mdDoc "Default kubernetes certificate authority";
145 type = types.nullOr types.path;
150 description = lib.mdDoc "Kubernetes root directory for managing kubelet files.";
151 default = "/var/lib/kubernetes";
155 easyCerts = mkOption {
156 description = lib.mdDoc "Automatically setup x509 certificates and keys for the entire cluster.";
161 featureGates = mkOption {
162 description = lib.mdDoc "List set of feature gates.";
164 type = types.listOf types.str;
167 masterAddress = mkOption {
168 description = lib.mdDoc "Clusterwide available network address or hostname for the kubernetes master server.";
169 example = "master.example.com";
174 description = lib.mdDoc "Packages added to the services' PATH environment variable. Both the bin and sbin subdirectories of each package are added.";
175 type = types.listOf types.package;
179 clusterCidr = mkOption {
180 description = lib.mdDoc "Kubernetes controller manager and proxy CIDR Range for Pods in cluster.";
181 default = "10.1.0.0/16";
182 type = types.nullOr types.str;
186 description = lib.mdDoc "Common functions for the kubernetes modules.";
189 inherit mkKubeConfig;
190 inherit mkKubeConfigOptions;
195 secretsPath = mkOption {
196 description = lib.mdDoc "Default location for kubernetes secrets. Not a store location.";
198 default = cfg.dataDir + "/secrets";
199 defaultText = literalExpression ''
200 config.${opt.dataDir} + "/secrets"
205 ###### implementation
209 (mkIf cfg.easyCerts {
210 services.kubernetes.pki.enable = mkDefault true;
211 services.kubernetes.caFile = caCert;
214 (mkIf (elem "master" cfg.roles) {
215 services.kubernetes.apiserver.enable = mkDefault true;
216 services.kubernetes.scheduler.enable = mkDefault true;
217 services.kubernetes.controllerManager.enable = mkDefault true;
218 services.kubernetes.addonManager.enable = mkDefault true;
219 services.kubernetes.proxy.enable = mkDefault true;
220 services.etcd.enable = true; # Cannot mkDefault because of flannel default options
221 services.kubernetes.kubelet = {
222 enable = mkDefault true;
223 taints = mkIf (!(elem "node" cfg.roles)) {
225 key = "node-role.kubernetes.io/master";
227 effect = "NoSchedule";
234 (mkIf (all (el: el == "master") cfg.roles) {
235 # if this node is only a master make it unschedulable by default
236 services.kubernetes.kubelet.unschedulable = mkDefault true;
239 (mkIf (elem "node" cfg.roles) {
240 services.kubernetes.kubelet.enable = mkDefault true;
241 services.kubernetes.proxy.enable = mkDefault true;
244 # Using "services.kubernetes.roles" will automatically enable easyCerts and flannel
245 (mkIf (cfg.roles != []) {
246 services.kubernetes.flannel.enable = mkDefault true;
247 services.flannel.etcd.endpoints = mkDefault etcdEndpoints;
248 services.kubernetes.easyCerts = mkDefault true;
251 (mkIf cfg.apiserver.enable {
252 services.kubernetes.pki.etcClusterAdminKubeconfig = mkDefault "kubernetes/cluster-admin.kubeconfig";
253 services.kubernetes.apiserver.etcd.servers = mkDefault etcdEndpoints;
256 (mkIf cfg.kubelet.enable {
257 virtualisation.containerd = {
258 enable = mkDefault true;
259 settings = mapAttrsRecursive (name: mkDefault) defaultContainerdSettings;
263 (mkIf (cfg.apiserver.enable || cfg.controllerManager.enable) {
264 services.kubernetes.pki.certs = {
265 serviceAccount = mkCert {
266 name = "service-account";
267 CN = "system:service-account-signer";
270 kube-apiserver.service \
271 kube-controller-manager.service
278 cfg.apiserver.enable ||
279 cfg.scheduler.enable ||
280 cfg.controllerManager.enable ||
281 cfg.kubelet.enable ||
283 cfg.addonManager.enable
285 systemd.targets.kubernetes = {
286 description = "Kubernetes";
287 wantedBy = [ "multi-user.target" ];
290 systemd.tmpfiles.rules = [
291 "d /opt/cni/bin 0755 root root -"
292 "d /run/kubernetes 0755 kubernetes kubernetes -"
293 "d /var/lib/kubernetes 0755 kubernetes kubernetes -"
296 users.users.kubernetes = {
297 uid = config.ids.uids.kubernetes;
298 description = "Kubernetes user";
299 group = "kubernetes";
303 users.groups.kubernetes.gid = config.ids.gids.kubernetes;
305 # dns addon is enabled by default
306 services.kubernetes.addons.dns.enable = mkDefault true;
308 services.kubernetes.apiserverAddress = mkDefault ("https://${if cfg.apiserver.advertiseAddress != null
309 then cfg.apiserver.advertiseAddress
310 else "${cfg.masterAddress}:${toString cfg.apiserver.securePort}"}");
314 meta.buildDocsInSandbox = false;