PiHole stateFullSet manifests

This commit is contained in:
2025-12-22 10:23:26 +01:00
parent 4a274f4e41
commit a92339adcd
5 changed files with 603 additions and 0 deletions

257
Pihole/StatefulSet.yaml Normal file
View File

@@ -0,0 +1,257 @@
apiVersion: v1
kind: Secret
metadata:
name: pihole-dns-secret
labels:
project: pihole
data:
# Needs to be base64 encoded as stated here https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#secret-v1-core
# echo -n '<tokenHere>' | base64
FTLCONF_webserver_api_password:
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: pihole-dns-statefulset
labels:
project: pihole
spec:
replicas: 3
selector:
matchLabels:
pod-project: pihole
serviceName: pihole-statefulsets-webgui-service
minReadySeconds: 10
template:
metadata:
labels:
pod-project: pihole
project-ns-name: private-srvc
# pod-project: doh
spec:
terminationGracePeriodSeconds: 10
automountServiceAccountToken: false # Container doesn't need service account token
securityContext:
appArmorProfile:
type: RuntimeDefault
# runAsNonRoot: true
fsGroup: 1500
# runAsGroup: 1500
# runAsUser: 1500
containers:
- name: pihole-dns
image: pihole/pihole:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: pihole-statefulset-data
mountPath: /etc/pihole
- name: dnsmasq-extra-data
mountPath: /etc/dnsmasq.d
ports:
- name: dns-tcp
containerPort: 53
protocol: TCP
- name: dns-udp
containerPort: 53
protocol: UDP
- name: webgui-https
containerPort: 443
protocol: TCP
- name: webgui-http
containerPort: 80
protocol: TCP
env:
- name: TZ
value: Europe/Stockholm
- name: FTLCONF_dns_listeningMode
value: all
- name: FTLCONF_webserver_port
value: "80,443s"
- name: DNSMASQ_LISTENING
value: all
- name: PIHOLE_UID
value: "1500"
- name: PIHOLE_GID
value: "1500"
envFrom:
- secretRef:
name: pihole-dns-secret
startupProbe:
tcpSocket:
port: 53
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 60
livenessProbe:
exec:
command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
periodSeconds: 5
failureThreshold: 4
readinessProbe:
exec:
command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
periodSeconds: 10
failureThreshold: 6
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
# cpu: "550m"
# https://github.com/eko/pihole-exporter
- name: prom-exporter
image: ekofr/pihole-exporter:v1.2.0
imagePullPolicy: IfNotPresent
ports:
- name: prom-export
containerPort: 50934
protocol: TCP
env:
- name: PIHOLE_HOSTNAME
value: "127.0.0.1"
- name: PIHOLE_PASSWORD
value: "YOURPASSWORDHERE"
- name: PORT
value: "50934"
- name: cloudflare-1-1-1-1
image: visibilityspots/cloudflared:v2025.7.0
imagePullPolicy: IfNotPresent
ports:
- name: doh-unseiso-udp
containerPort: 5051
protocol: UDP
env:
- name: PORT
value: "5051"
- name: UPSTREAM1
value: https://1.1.1.1/dns-query
- name: UPSTREAM2
value: https://1.0.0.1/dns-query
- name: METRICS
value: "127.0.0.1:8081"
# startupProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# initialDelaySeconds: 6
# periodSeconds: 4
# failureThreshold: 6
# livenessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# readinessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
resources:
requests:
memory: "48Mi"
cpu: "100m"
# limits:
# memory: "96Mi"
# cpu: "150m"
- name: cloudflare-1-1-1-2
image: visibilityspots/cloudflared:v2025.7.0
imagePullPolicy: IfNotPresent
ports:
- name: doh-no-virus
containerPort: 5052
protocol: UDP
env:
- name: PORT
value: "5052"
- name: UPSTREAM1
value: https://1.1.1.2/dns-query
- name: UPSTREAM2
value: https://1.0.0.2/dns-query
- name: METRICS
value: "127.0.0.1:8082"
# startupProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# initialDelaySeconds: 6
# periodSeconds: 4
# failureThreshold: 6
# livenessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# readinessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
resources:
requests:
memory: "48Mi"
cpu: "100m"
# limits:
# memory: "96Mi"
# cpu: "150m"
- name: cloudflare-1-1-1-3
image: visibilityspots/cloudflared:v2025.7.0
imagePullPolicy: IfNotPresent
ports:
- name: doh-seiso-udp
containerPort: 5053
protocol: UDP
env:
- name: PORT
value: "5053"
- name: UPSTREAM1
value: https://1.1.1.3/dns-query
- name: UPSTREAM2
value: https://1.0.0.3/dns-query
- name: METRICS
value: "127.0.0.1:8083"
# startupProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# initialDelaySeconds: 6
# periodSeconds: 4
# failureThreshold: 6
# livenessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
# readinessProbe:
# exec:
# command: ["sh","-c","nslookup -timeout=2 google.com 127.0.0.1 >/dev/null"]
resources:
requests:
memory: "48Mi"
cpu: "100m"
# limits:
# memory: "96Mi"
# cpu: "150m"
volumes:
- name: dnsmasq-extra-data
persistentVolumeClaim:
claimName: dnsmasq-extra-data-pvc
volumeClaimTemplates:
- metadata:
name: pihole-statefulset-data
#
spec:
accessModes:
# - ReadOnlyMany
- ReadWriteOnce
# - ReadWriteMany
resources:
requests:
storage: 4Gi

145
Pihole/nebula.yaml Normal file
View File

@@ -0,0 +1,145 @@
apiVersion: v1
kind: Secret
metadata:
name: nebula-sync-secret
labels:
project: pihole
project: nebula-sync
data:
# https
# echo -n "something" | base64
PRIMARY:
REPLICAS:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nebula-sync-configmap
labels:
project: pihole
project: nebula-sync
data:
FULL_SYNC: "true"
CRON: "25 */3 * * *"
RUN_GRAVITY: "true"
TZ: Europe/Stockholm
CLIENT_SKIP_TLS_VERIFICATION: "true"
SYNC_GRAVITY_CLIENT: "true"
SYNC_CONFIG_DNS: "true"
SYNC_CONFIG_RESOLVER: "true"
SYNC_CONFIG_DATABASE: "true"
SYNC_CONFIG_MISC: "true"
SYNC_GRAVITY_GROUP: "true"
SYNC_GRAVITY_AD_LIST: "true"
SYNC_GRAVITY_DOMAIN_LIST: "true"
SYNC_GRAVITY_CLIENT: "true"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nebula-sync-deployment
labels:
project: pihole
project: nebula-sync
spec:
replicas: 1
selector:
matchLabels:
pod-project: nebula-sync
template:
metadata:
labels:
pod-project: nebula-sync
# pod-project: doh
spec:
automountServiceAccountToken: false # Container doesn't need service account token
securityContext:
appArmorProfile:
type: RuntimeDefault
runAsNonRoot: true
# fsGroup: 1500
runAsGroup: 1500
runAsUser: 1500
containers:
- name: nebula-sync
image: ghcr.io/lovelaze/nebula-sync
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
name: nebula-sync-configmap
- secretRef:
name: nebula-sync-secret
resources:
requests:
memory: "152Mi"
cpu: "100m"
limits:
memory: "384Mi"
# cpu: "550m"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: nebula-sync-netwrokpolicy
labels:
project: pihole
project: nebula-sync
spec:
podSelector:
matchLabels:
pod-project: nebula-sync
egress:
# Allow connecting to CoreDNS
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# - to:
# - namespaceSelector:
# matchLabels:
# kubernetes.io/metadata.name: <YourNameSpace>
# podSelector:
# matchLabels:
# pod-project: pihole
ports:
- protocol: TCP
port: 443
ingress:
# - from:
# - namespaceSelector:
# matchLabels:
# kubernetes.io/metadata.name: private-srvc
# podSelector:
# matchLabels:
# pod-project: pihole
# project-ns-name: private-srvc
policyTypes:
- Ingress
- Egress

94
Pihole/netPolicy.yaml Normal file
View File

@@ -0,0 +1,94 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: pihole-config-data-netwrokpolicy
labels:
project: pihole
spec:
podSelector:
matchLabels:
pod-project: pihole
egress:
# Allow all egress
# - {}
# Allow egress only to public networks
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
ingress:
# - from:
# - namespaceSelector:
# matchLabels:
# ns-name: <namespace>
# podSelector:
# matchLabels:
# podDomain: <podLabels>
# ports:
# - protocol: TCP
# port: 80
# - protocol: TCP
# port: 443
# - from:
# - namespaceSelector:
# matchLabels:
# ns-name: <nebulaNS>
# podSelector:
# matchLabels:
# pod-project: nebula-sync
# ports:
# - protocol: TCP
# port: 443
# - protocol: TCP
# port: 80
- from:
- ipBlock:
cidr: 192.168.0.0/16
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- from:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- from:
- ipBlock:
cidr: 172.16.0.0/12
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
policyTypes:
- Ingress
- Egress

16
Pihole/pvc.yaml Normal file
View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dnsmasq-extra-data-pvc
namespace: private-srvc
labels:
project: pihole
spec:
# https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes-1
accessModes:
# - ReadOnlyMany
# - ReadWriteOnce
- ReadWriteMany
resources:
requests:
storage: 32Mi

91
Pihole/service.yaml Normal file
View File

@@ -0,0 +1,91 @@
# WebGUI
apiVersion: v1
kind: Service
metadata:
name: pihole-statefulsets-webgui-service
labels:
project: pihole
spec:
selector:
pod-project: pihole
# This isn't used as Ingress is doing TLS termination
# type: LoadBalancer
type: ClusterIP
clusterIP: None
ports:
- name: pihole-webgui-https
protocol: TCP
port: 443 # <- port that will be exposed
targetPort: 443
- name: pihole-webgui-http
protocol: TCP
port: 80 # <- port that will be exposed
targetPort: 80
- name: pihole-dns-udp
protocol: UDP
port: 53 # <- port that will be exposed
targetPort: 53
- name: pihole-dns-tcp
protocol: TCP
port: 53 # <- port that will be exposed
targetPort: 53
# Then use these for connecting to individual pods
# podName.headlessServiceName.nameSpace.svc.cluster.local
# <pod-name>.<headless-service-name>.<namespace>.svc.cluster.local
---
# Main IP for DNS
apiVersion: v1
kind: Service
metadata:
name: pihole-dns-service
labels:
project: pihole
annotations:
metallb.io/loadBalancerIPs: 1.2.3.4
spec:
selector:
pod-project: pihole
# This isn't used as Ingress is doing TLS termination
type: LoadBalancer
# Preserve ips
externalTrafficPolicy: Local
# type: ClusterIP
ports:
- name: pihole-dns-udp
protocol: UDP
port: 53 # <- port that will be exposed
targetPort: 53
- name: pihole-dns-tcp
protocol: TCP
port: 53 # <- port that will be exposed
targetPort: 53
# Node exporter
---
apiVersion: v1
kind: Service
metadata:
name: pihole-svc-prom-exporter
labels:
project: pihole
spec:
clusterIP: None # headless
selector:
pod-project: pihole # matches your exporter pods
ports:
- name: ngx-metrics
port: 50934
targetPort: 50934