1{
2 config,
3 lib,
4 options,
5 pkgs,
6 ...
7}:
8let
9 top = config.services.kubernetes;
10 otop = options.services.kubernetes;
11 cfg = top.controllerManager;
12in
13{
14 imports = [
15 (lib.mkRenamedOptionModule
16 [ "services" "kubernetes" "controllerManager" "address" ]
17 [ "services" "kubernetes" "controllerManager" "bindAddress" ]
18 )
19 (lib.mkRemovedOptionModule [ "services" "kubernetes" "controllerManager" "insecurePort" ] "")
20 ];
21
22 ###### interface
23 options.services.kubernetes.controllerManager = with lib.types; {
24
25 allocateNodeCIDRs = lib.mkOption {
26 description = "Whether to automatically allocate CIDR ranges for cluster nodes.";
27 default = true;
28 type = bool;
29 };
30
31 bindAddress = lib.mkOption {
32 description = "Kubernetes controller manager listening address.";
33 default = "127.0.0.1";
34 type = str;
35 };
36
37 clusterCidr = lib.mkOption {
38 description = "Kubernetes CIDR Range for Pods in cluster.";
39 default = top.clusterCidr;
40 defaultText = lib.literalExpression "config.${otop.clusterCidr}";
41 type = str;
42 };
43
44 enable = lib.mkEnableOption "Kubernetes controller manager";
45
46 extraOpts = lib.mkOption {
47 description = "Kubernetes controller manager extra command line options.";
48 default = "";
49 type = separatedString " ";
50 };
51
52 featureGates = lib.mkOption {
53 description = "Attribute set of feature gates.";
54 default = top.featureGates;
55 defaultText = lib.literalExpression "config.${otop.featureGates}";
56 type = attrsOf bool;
57 };
58
59 kubeconfig = top.lib.mkKubeConfigOptions "Kubernetes controller manager";
60
61 leaderElect = lib.mkOption {
62 description = "Whether to start leader election before executing main loop.";
63 type = bool;
64 default = true;
65 };
66
67 rootCaFile = lib.mkOption {
68 description = ''
69 Kubernetes controller manager certificate authority file included in
70 service account's token secret.
71 '';
72 default = top.caFile;
73 defaultText = lib.literalExpression "config.${otop.caFile}";
74 type = nullOr path;
75 };
76
77 securePort = lib.mkOption {
78 description = "Kubernetes controller manager secure listening port.";
79 default = 10252;
80 type = int;
81 };
82
83 serviceAccountKeyFile = lib.mkOption {
84 description = ''
85 Kubernetes controller manager PEM-encoded private RSA key file used to
86 sign service account tokens
87 '';
88 default = null;
89 type = nullOr path;
90 };
91
92 tlsCertFile = lib.mkOption {
93 description = "Kubernetes controller-manager certificate file.";
94 default = null;
95 type = nullOr path;
96 };
97
98 tlsKeyFile = lib.mkOption {
99 description = "Kubernetes controller-manager private key file.";
100 default = null;
101 type = nullOr path;
102 };
103
104 verbosity = lib.mkOption {
105 description = ''
106 Optional glog verbosity level for logging statements. See
107 <https://github.com/kubernetes/community/blob/master/contributors/devel/logging.md>
108 '';
109 default = null;
110 type = nullOr int;
111 };
112
113 };
114
115 ###### implementation
116 config = lib.mkIf cfg.enable {
117 systemd.services.kube-controller-manager = {
118 description = "Kubernetes Controller Manager Service";
119 wantedBy = [ "kubernetes.target" ];
120 after = [ "kube-apiserver.service" ];
121 serviceConfig = {
122 RestartSec = "30s";
123 Restart = "on-failure";
124 Slice = "kubernetes.slice";
125 ExecStart = ''
126 ${top.package}/bin/kube-controller-manager \
127 --allocate-node-cidrs=${lib.boolToString cfg.allocateNodeCIDRs} \
128 --bind-address=${cfg.bindAddress} \
129 ${lib.optionalString (cfg.clusterCidr != null) "--cluster-cidr=${cfg.clusterCidr}"} \
130 ${
131 lib.optionalString (cfg.featureGates != { })
132 "--feature-gates=${
133 lib.concatStringsSep "," (
134 builtins.attrValues (lib.mapAttrs (n: v: "${n}=${lib.trivial.boolToString v}") cfg.featureGates)
135 )
136 }"
137 } \
138 --kubeconfig=${top.lib.mkKubeConfig "kube-controller-manager" cfg.kubeconfig} \
139 --leader-elect=${lib.boolToString cfg.leaderElect} \
140 ${lib.optionalString (cfg.rootCaFile != null) "--root-ca-file=${cfg.rootCaFile}"} \
141 --secure-port=${toString cfg.securePort} \
142 ${
143 lib.optionalString (
144 cfg.serviceAccountKeyFile != null
145 ) "--service-account-private-key-file=${cfg.serviceAccountKeyFile}"
146 } \
147 ${lib.optionalString (cfg.tlsCertFile != null) "--tls-cert-file=${cfg.tlsCertFile}"} \
148 ${
149 lib.optionalString (cfg.tlsKeyFile != null) "--tls-private-key-file=${cfg.tlsKeyFile}"
150 } \
151 ${lib.optionalString (lib.elem "RBAC" top.apiserver.authorizationMode) "--use-service-account-credentials"} \
152 ${lib.optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \
153 ${cfg.extraOpts}
154 '';
155 WorkingDirectory = top.dataDir;
156 User = "kubernetes";
157 Group = "kubernetes";
158 };
159 unitConfig = {
160 StartLimitIntervalSec = 0;
161 };
162 path = top.path;
163 };
164
165 services.kubernetes.pki.certs = with top.lib; {
166 controllerManager = mkCert {
167 name = "kube-controller-manager";
168 CN = "kube-controller-manager";
169 action = "systemctl restart kube-controller-manager.service";
170 };
171 controllerManagerClient = mkCert {
172 name = "kube-controller-manager-client";
173 CN = "system:kube-controller-manager";
174 action = "systemctl restart kube-controller-manager.service";
175 };
176 };
177
178 services.kubernetes.controllerManager.kubeconfig.server = lib.mkDefault top.apiserverAddress;
179 };
180
181 meta.buildDocsInSandbox = false;
182}