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}