1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 version = "1.14.10";
7 cfg = config.services.kubernetes.addons.dns;
8in {
9 options.services.kubernetes.addons.dns = {
10 enable = mkEnableOption "kubernetes dns addon";
11
12 clusterIp = mkOption {
13 description = "Dns addon clusterIP";
14
15 # this default is also what kubernetes users
16 default = (
17 concatStringsSep "." (
18 take 3 (splitString "." config.services.kubernetes.apiserver.serviceClusterIpRange
19 ))
20 ) + ".254";
21 type = types.str;
22 };
23
24 clusterDomain = mkOption {
25 description = "Dns cluster domain";
26 default = "cluster.local";
27 type = types.str;
28 };
29
30 kube-dns = mkOption {
31 description = "Docker image to seed for the kube-dns main container.";
32 type = types.attrs;
33 default = {
34 imageName = "k8s.gcr.io/k8s-dns-kube-dns-amd64";
35 imageDigest = "sha256:b99fc3eee2a9f052f7eb4cc00f15eb12fc405fa41019baa2d6b79847ae7284a8";
36 finalImageTag = version;
37 sha256 = "0x583znk9smqn0fix7ld8sm5jgaxhqhx3fq97b1wkqm7iwhvl3pj";
38 };
39 };
40
41 dnsmasq-nanny = mkOption {
42 description = "Docker image to seed for the kube-dns dnsmasq container.";
43 type = types.attrs;
44 default = {
45 imageName = "k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64";
46 imageDigest = "sha256:bbb2a290a568125b3b996028958eb773f33b5b87a6b37bf38a28f8b62dddb3c8";
47 finalImageTag = version;
48 sha256 = "1fihml7s2mfwgac51cbqpylkwbivc8nyhgi4vb820s83zvl8a6y1";
49 };
50 };
51
52 sidecar = mkOption {
53 description = "Docker image to seed for the kube-dns sidecar container.";
54 type = types.attrs;
55 default = {
56 imageName = "k8s.gcr.io/k8s-dns-sidecar-amd64";
57 imageDigest = "sha256:4f1ab957f87b94a5ec1edc26fae50da2175461f00afecf68940c4aa079bd08a4";
58 finalImageTag = version;
59 sha256 = "08l1bv5jgrhvjzpqpbinrkgvv52snc4fzyd8ya9v18ns2klyz7m0";
60 };
61 };
62 };
63
64 config = mkIf cfg.enable {
65 services.kubernetes.kubelet.seedDockerImages = with pkgs.dockerTools; [
66 (pullImage cfg.kube-dns)
67 (pullImage cfg.dnsmasq-nanny)
68 (pullImage cfg.sidecar)
69 ];
70
71 services.kubernetes.addonManager.addons = {
72 kubedns-deployment = {
73 apiVersion = "extensions/v1beta1";
74 kind = "Deployment";
75 metadata = {
76 labels = {
77 "addonmanager.kubernetes.io/mode" = "Reconcile";
78 "k8s-app" = "kube-dns";
79 "kubernetes.io/cluster-service" = "true";
80 };
81 name = "kube-dns";
82 namespace = "kube-system";
83 };
84 spec = {
85 selector.matchLabels."k8s-app" = "kube-dns";
86 strategy = {
87 rollingUpdate = {
88 maxSurge = "10%";
89 maxUnavailable = 0;
90 };
91 };
92 template = {
93 metadata = {
94 annotations."scheduler.alpha.kubernetes.io/critical-pod" = "";
95 labels.k8s-app = "kube-dns";
96 };
97 spec = {
98 priorityClassName = "system-cluster-critical";
99 containers = [
100 {
101 name = "kubedns";
102 image = with cfg.kube-dns; "${imageName}:${finalImageTag}";
103 resources = {
104 limits.memory = "170Mi";
105 requests = {
106 cpu = "100m";
107 memory = "70Mi";
108 };
109 };
110 livenessProbe = {
111 failureThreshold = 5;
112 httpGet = {
113 path = "/healthcheck/kubedns";
114 port = 10054;
115 scheme = "HTTP";
116 };
117 initialDelaySeconds = 60;
118 successThreshold = 1;
119 timeoutSeconds = 5;
120 };
121 readinessProbe = {
122 httpGet = {
123 path = "/readiness";
124 port = 8081;
125 scheme = "HTTP";
126 };
127 initialDelaySeconds = 3;
128 timeoutSeconds = 5;
129 };
130 args = [
131 "--domain=${cfg.clusterDomain}"
132 "--dns-port=10053"
133 "--config-dir=/kube-dns-config"
134 "--v=2"
135 ];
136 env = [
137 {
138 name = "PROMETHEUS_PORT";
139 value = "10055";
140 }
141 ];
142 ports = [
143 {
144 containerPort = 10053;
145 name = "dns-local";
146 protocol = "UDP";
147 }
148 {
149 containerPort = 10053;
150 name = "dns-tcp-local";
151 protocol = "TCP";
152 }
153 {
154 containerPort = 10055;
155 name = "metrics";
156 protocol = "TCP";
157 }
158 ];
159 volumeMounts = [
160 {
161 mountPath = "/kube-dns-config";
162 name = "kube-dns-config";
163 }
164 ];
165 }
166 {
167 name = "dnsmasq";
168 image = with cfg.dnsmasq-nanny; "${imageName}:${finalImageTag}";
169 livenessProbe = {
170 httpGet = {
171 path = "/healthcheck/dnsmasq";
172 port = 10054;
173 scheme = "HTTP";
174 };
175 initialDelaySeconds = 60;
176 timeoutSeconds = 5;
177 successThreshold = 1;
178 failureThreshold = 5;
179 };
180 args = [
181 "-v=2"
182 "-logtostderr"
183 "-configDir=/etc/k8s/dns/dnsmasq-nanny"
184 "-restartDnsmasq=true"
185 "--"
186 "-k"
187 "--cache-size=1000"
188 "--log-facility=-"
189 "--server=/${cfg.clusterDomain}/127.0.0.1#10053"
190 "--server=/in-addr.arpa/127.0.0.1#10053"
191 "--server=/ip6.arpa/127.0.0.1#10053"
192 ];
193 ports = [
194 {
195 containerPort = 53;
196 name = "dns";
197 protocol = "UDP";
198 }
199 {
200 containerPort = 53;
201 name = "dns-tcp";
202 protocol = "TCP";
203 }
204 ];
205 resources = {
206 requests = {
207 cpu = "150m";
208 memory = "20Mi";
209 };
210 };
211 volumeMounts = [
212 {
213 mountPath = "/etc/k8s/dns/dnsmasq-nanny";
214 name = "kube-dns-config";
215 }
216 ];
217 }
218 {
219 name = "sidecar";
220 image = with cfg.sidecar; "${imageName}:${finalImageTag}";
221 livenessProbe = {
222 httpGet = {
223 path = "/metrics";
224 port = 10054;
225 scheme = "HTTP";
226 };
227 initialDelaySeconds = 60;
228 timeoutSeconds = 5;
229 successThreshold = 1;
230 failureThreshold = 5;
231 };
232 args = [
233 "--v=2"
234 "--logtostderr"
235 "--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.${cfg.clusterDomain},5,A"
236 "--probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.${cfg.clusterDomain},5,A"
237 ];
238 ports = [
239 {
240 containerPort = 10054;
241 name = "metrics";
242 protocol = "TCP";
243 }
244 ];
245 resources = {
246 requests = {
247 cpu = "10m";
248 memory = "20Mi";
249 };
250 };
251 }
252 ];
253 dnsPolicy = "Default";
254 serviceAccountName = "kube-dns";
255 tolerations = [
256 {
257 key = "CriticalAddonsOnly";
258 operator = "Exists";
259 }
260 ];
261 volumes = [
262 {
263 configMap = {
264 name = "kube-dns";
265 optional = true;
266 };
267 name = "kube-dns-config";
268 }
269 ];
270 };
271 };
272 };
273 };
274
275 kubedns-svc = {
276 apiVersion = "v1";
277 kind = "Service";
278 metadata = {
279 labels = {
280 "addonmanager.kubernetes.io/mode" = "Reconcile";
281 "k8s-app" = "kube-dns";
282 "kubernetes.io/cluster-service" = "true";
283 "kubernetes.io/name" = "KubeDNS";
284 };
285 name = "kube-dns";
286 namespace = "kube-system";
287 };
288 spec = {
289 clusterIP = cfg.clusterIp;
290 ports = [
291 {name = "dns"; port = 53; protocol = "UDP";}
292 {name = "dns-tcp"; port = 53; protocol = "TCP";}
293 ];
294 selector.k8s-app = "kube-dns";
295 };
296 };
297
298 kubedns-sa = {
299 apiVersion = "v1";
300 kind = "ServiceAccount";
301 metadata = {
302 name = "kube-dns";
303 namespace = "kube-system";
304 labels = {
305 "kubernetes.io/cluster-service" = "true";
306 "addonmanager.kubernetes.io/mode" = "Reconcile";
307 };
308 };
309 };
310
311 kubedns-cm = {
312 apiVersion = "v1";
313 kind = "ConfigMap";
314 metadata = {
315 name = "kube-dns";
316 namespace = "kube-system";
317 labels = {
318 "addonmanager.kubernetes.io/mode" = "EnsureExists";
319 };
320 };
321 };
322 };
323
324 services.kubernetes.kubelet.clusterDns = mkDefault cfg.clusterIp;
325 };
326}