Add NodeLocal DNSCache platform component

This commit is contained in:
juvdiaz 2026-05-26 23:05:21 -06:00
parent 7b0b060a1c
commit 40662b2b74
3 changed files with 368 additions and 0 deletions

View File

@ -43,6 +43,7 @@ accidentally modify the cluster.
3. `bootstrap/platform`
- installs a minimal Calico deployment through the Tigera operator
- installs NodeLocal DNSCache for node-local DNS query caching
- installs OpenEBS
- creates `openebs-hostpath-retain`
- installs Argo CD
@ -230,6 +231,15 @@ settings without blocking existing pods during the first rollout. After reports
are clean, individual policies can be promoted to `Enforce` in
`bootstrap/platform/main.tf`.
## DNS Cache
`bootstrap/platform` installs NodeLocal DNSCache in `kube-system` with
`registry.k8s.io/dns/k8s-dns-node-cache`. The default listens on
`169.254.20.10` and the kube-dns service IP `10.96.0.10`, which keeps the
rollout compatible with the current kube-proxy iptables path without rewriting
kubelet DNS settings across the nodes. Override `nodelocal_dns` if the service
CIDR or upstream DNS servers change.
## Secrets
Use SOPS with age for secrets that need to live in Git. Start from

View File

@ -26,6 +26,57 @@ provider "helm" {
}
}
locals {
nodelocal_dns_corefile = <<EOT
${var.nodelocal_dns.cluster_domain}:53 {
errors
cache {
success 9984 30
denial 9984 5
}
reload
loop
bind ${var.nodelocal_dns.local_ip} ${var.nodelocal_dns.cluster_dns_ip}
forward . ${var.nodelocal_dns.cluster_dns_ip} {
force_tcp
}
prometheus :9253
health ${var.nodelocal_dns.local_ip}:8080
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind ${var.nodelocal_dns.local_ip} ${var.nodelocal_dns.cluster_dns_ip}
forward . ${var.nodelocal_dns.cluster_dns_ip} {
force_tcp
}
prometheus :9253
}
ip6.arpa:53 {
errors
cache 30
reload
loop
bind ${var.nodelocal_dns.local_ip} ${var.nodelocal_dns.cluster_dns_ip}
forward . ${var.nodelocal_dns.cluster_dns_ip} {
force_tcp
}
prometheus :9253
}
.:53 {
errors
cache 30
reload
loop
bind ${var.nodelocal_dns.local_ip} ${var.nodelocal_dns.cluster_dns_ip}
forward . ${join(" ", var.nodelocal_dns.upstream_dns_servers)}
prometheus :9253
}
EOT
}
resource "helm_release" "calico_crds" {
name = "calico-crds"
repository = var.calico.repository
@ -176,6 +227,293 @@ EOT
}
}
resource "kubernetes_manifest" "nodelocal_dns_service_account" {
for_each = var.nodelocal_dns.enabled ? { enabled = true } : {}
depends_on = [null_resource.calico_ready]
manifest = {
apiVersion = "v1"
kind = "ServiceAccount"
metadata = {
name = "node-local-dns"
namespace = "kube-system"
labels = {
"kubernetes.io/cluster-service" = "true"
"addonmanager.kubernetes.io/mode" = "Reconcile"
"app.kubernetes.io/managed-by" = "opentofu"
"app.kubernetes.io/part-of" = "nodelocal-dns"
"app.kubernetes.io/name" = "node-local-dns"
"homelab.dev/platform-component" = "nodelocal-dns"
"homelab.dev/platform-component-id" = "dns-cache"
}
}
}
}
resource "kubernetes_manifest" "nodelocal_dns_upstream_service" {
for_each = var.nodelocal_dns.enabled ? { enabled = true } : {}
depends_on = [null_resource.calico_ready]
manifest = {
apiVersion = "v1"
kind = "Service"
metadata = {
name = "kube-dns-upstream"
namespace = "kube-system"
labels = {
"k8s-app" = "kube-dns"
"kubernetes.io/cluster-service" = "true"
"addonmanager.kubernetes.io/mode" = "Reconcile"
"kubernetes.io/name" = "KubeDNSUpstream"
}
}
spec = {
ports = [
{
name = "dns"
port = 53
protocol = "UDP"
targetPort = 53
},
{
name = "dns-tcp"
port = 53
protocol = "TCP"
targetPort = 53
},
]
selector = {
"k8s-app" = "kube-dns"
}
}
}
}
resource "kubernetes_manifest" "nodelocal_dns_config_map" {
for_each = var.nodelocal_dns.enabled ? { enabled = true } : {}
depends_on = [null_resource.calico_ready]
manifest = {
apiVersion = "v1"
kind = "ConfigMap"
metadata = {
name = "node-local-dns"
namespace = "kube-system"
labels = {
"addonmanager.kubernetes.io/mode" = "Reconcile"
"app.kubernetes.io/managed-by" = "opentofu"
"app.kubernetes.io/name" = "node-local-dns"
"app.kubernetes.io/part-of" = "nodelocal-dns"
}
}
data = {
Corefile = local.nodelocal_dns_corefile
}
}
}
resource "kubernetes_manifest" "nodelocal_dns_daemonset" {
for_each = var.nodelocal_dns.enabled ? { enabled = true } : {}
depends_on = [
kubernetes_manifest.nodelocal_dns_service_account,
kubernetes_manifest.nodelocal_dns_upstream_service,
kubernetes_manifest.nodelocal_dns_config_map,
]
manifest = {
apiVersion = "apps/v1"
kind = "DaemonSet"
metadata = {
name = "node-local-dns"
namespace = "kube-system"
labels = {
"k8s-app" = "node-local-dns"
"kubernetes.io/cluster-service" = "true"
"addonmanager.kubernetes.io/mode" = "Reconcile"
}
}
spec = {
updateStrategy = {
rollingUpdate = {
maxUnavailable = "10%"
}
}
selector = {
matchLabels = {
"k8s-app" = "node-local-dns"
}
}
template = {
metadata = {
labels = {
"k8s-app" = "node-local-dns"
}
annotations = {
"prometheus.io/port" = "9253"
"prometheus.io/scrape" = "true"
}
}
spec = {
priorityClassName = "system-node-critical"
serviceAccountName = "node-local-dns"
hostNetwork = true
dnsPolicy = "Default"
nodeSelector = {
"kubernetes.io/os" = "linux"
}
tolerations = [
{
key = "CriticalAddonsOnly"
operator = "Exists"
},
{
effect = "NoExecute"
operator = "Exists"
},
{
effect = "NoSchedule"
operator = "Exists"
},
]
containers = [
{
name = "node-cache"
image = var.nodelocal_dns.image
resources = {
requests = {
cpu = "25m"
memory = "5Mi"
}
}
args = [
"-localip",
"${var.nodelocal_dns.local_ip},${var.nodelocal_dns.cluster_dns_ip}",
"-conf",
"/etc/Corefile",
"-upstreamsvc",
"kube-dns-upstream",
]
securityContext = {
capabilities = {
add = ["NET_ADMIN"]
}
}
ports = [
{
containerPort = 53
name = "dns"
protocol = "UDP"
},
{
containerPort = 53
name = "dns-tcp"
protocol = "TCP"
},
{
containerPort = 9253
name = "metrics"
protocol = "TCP"
},
]
livenessProbe = {
httpGet = {
host = var.nodelocal_dns.local_ip
path = "/health"
port = 8080
}
initialDelaySeconds = 60
timeoutSeconds = 5
}
volumeMounts = [
{
mountPath = "/run/xtables.lock"
name = "xtables-lock"
readOnly = false
},
{
mountPath = "/etc/coredns"
name = "config-volume"
},
{
mountPath = "/etc/kube-dns"
name = "kube-dns-config"
},
]
},
]
volumes = [
{
name = "xtables-lock"
hostPath = {
path = "/run/xtables.lock"
type = "FileOrCreate"
}
},
{
name = "kube-dns-config"
configMap = {
name = "kube-dns"
optional = true
}
},
{
name = "config-volume"
configMap = {
name = "node-local-dns"
items = [
{
key = "Corefile"
path = "Corefile.base"
},
]
}
},
]
}
}
}
}
}
resource "kubernetes_manifest" "nodelocal_dns_metrics_service" {
for_each = var.nodelocal_dns.enabled ? { enabled = true } : {}
depends_on = [kubernetes_manifest.nodelocal_dns_daemonset]
manifest = {
apiVersion = "v1"
kind = "Service"
metadata = {
name = "node-local-dns"
namespace = "kube-system"
annotations = {
"prometheus.io/port" = "9253"
"prometheus.io/scrape" = "true"
}
labels = {
"k8s-app" = "node-local-dns"
}
}
spec = {
clusterIP = "None"
ports = [
{
name = "metrics"
port = 9253
targetPort = 9253
},
]
selector = {
"k8s-app" = "node-local-dns"
}
}
}
}
resource "helm_release" "openebs" {
depends_on = [null_resource.calico_ready]
name = "openebs"

View File

@ -92,6 +92,26 @@ variable "kyverno" {
}
}
variable "nodelocal_dns" {
type = object({
enabled = bool
image = string
local_ip = string
cluster_dns_ip = string
cluster_domain = string
upstream_dns_servers = list(string)
})
default = {
enabled = true
image = "registry.k8s.io/dns/k8s-dns-node-cache:1.26.8"
local_ip = "169.254.20.10"
cluster_dns_ip = "10.96.0.10"
cluster_domain = "cluster.local"
upstream_dns_servers = ["1.1.1.1", "8.8.8.8"]
}
}
variable "observability" {
type = object({
namespace = string