Files
fancy-dns/deploy/k8s/10-deployment.yaml
T
2026-09-27 11:34:26 +00:00

246 lines
6.7 KiB
YAML

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: fancy-dns
namespace: dns
labels:
app.kubernetes.io/name: fancy-dns
spec:
serviceName: fancy-dns
replicas: 2
podManagementPolicy: Parallel
selector:
matchLabels:
app.kubernetes.io/name: fancy-dns
template:
metadata:
labels:
app.kubernetes.io/name: fancy-dns
annotations:
# A config change is a SIGHUP, not a restart: the server re-reads the
# file and hot-swaps every component.
reloader.stakater.com/auto: "true"
spec:
# DNS on a non-privileged port needs NET_BIND_SERVICE on Linux, or
# hostNetwork. hostNetwork is used here so the node's port 53 is served
# directly and the load balancer does not add a hop.
hostNetwork: true
dnsPolicy: Default
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: fancy-dns
containers:
- name: fancy-dns
image: fancydns/fancy-dns:latest
imagePullPolicy: IfNotPresent
args:
- -config
- /etc/fancy-dns/config.yaml
ports:
- name: dns-udp
containerPort: 53
protocol: UDP
- name: dns-tcp
containerPort: 53
protocol: TCP
- name: dot
containerPort: 853
protocol: TCP
- name: doh
containerPort: 443
protocol: TCP
- name: admin
containerPort: 8080
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
# Liveness: the process is up. /api/healthz is unauthenticated on
# purpose, because a probe cannot carry an API key.
livenessProbe:
httpGet:
path: /api/healthz
port: admin
initialDelaySeconds: 5
periodSeconds: 20
# Readiness: the listener is actually bound, so the Service does not
# send traffic to a pod that is still binding.
readinessProbe:
httpGet:
path: /api/healthz
port: admin
initialDelaySeconds: 3
periodSeconds: 5
failureThreshold: 2
# Startup: binding :53 and fetching the first blocklist can take a
# while on a cold node, so give it room before the liveness probe
# starts killing it.
startupProbe:
httpGet:
path: /api/healthz
port: admin
periodSeconds: 3
failureThreshold: 30
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
# No CPU limit on purpose: a DNS server that gets throttled
# turns into dropped queries, which is worse than a noisy
# neighbour. The memory limit is the one that matters, because
# the cache is sized in entries.
memory: 1Gi
volumeMounts:
- name: config
mountPath: /etc/fancy-dns/config.yaml
subPath: config.yaml
readOnly: true
- name: zones
mountPath: /etc/fancy-dns/zones
readOnly: true
- name: tls
mountPath: /etc/fancy-dns/tls
readOnly: true
- name: data
mountPath: /var/lib/fancy-dns
- name: tmp
mountPath: /tmp
volumes:
- name: config
configMap:
name: fancy-dns-config
- name: zones
configMap:
name: fancy-dns-zones
optional: true
- name: tls
secret:
secretName: fancy-dns-tls
- name: data
emptyDir: {}
- name: tmp
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: fancy-dns
namespace: dns
labels:
app.kubernetes.io/name: fancy-dns
spec:
clusterIP: None
selector:
app.kubernetes.io/name: fancy-dns
ports:
- name: dns-udp
port: 53
targetPort: dns-udp
protocol: UDP
- name: dns-tcp
port: 53
targetPort: dns-tcp
protocol: TCP
- name: dot
port: 853
targetPort: dot
- name: doh
port: 443
targetPort: doh
- name: admin
port: 8080
targetPort: admin
---
# The admin console and the DoH endpoint share a port only if the ingress
# terminates TLS; when it does, this routes /api and /dns-query to the same
# backend. Kept separate from the Service above because a headless Service
# cannot front an Ingress.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fancy-dns
namespace: dns
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
spec:
rules:
- host: dns.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: fancy-dns
port:
name: admin
- path: /dns-query
pathType: Prefix
backend:
service:
name: fancy-dns
port:
name: doh
- path: /
pathType: Prefix
backend:
service:
name: fancy-dns
port:
name: admin
tls:
- hosts: [dns.example.com]
secretName: fancy-dns-tls
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: fancy-dns
namespace: dns
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: fancy-dns
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: fancy-dns
namespace: dns
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: fancy-dns
minReplicas: 2
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
# A DNS server that flaps is worse than one that is briefly oversized:
# every scale-down drops the local cache and the blocklist lease.
stabilizationWindowSeconds: 600