Pi-hole
Purpose: DNS ad-blocker and network-wide ad blocking
Version: Latest (pihole/pihole:latest)
Namespace: pihole
Description
Pi-hole is a DNS sinkhole that blocks ads and trackers at the network level. It acts as a DNS server for your network, blocking requests to known ad-serving domains before they reach your devices.
Key features:
- Network-wide ad blocking
- DNS query logging and analytics
- Custom blocklists and allowlists
- Web-based admin dashboard
- Supports multiple devices simultaneously
Installation
Installed via internal Helm chart from charts/pi-hole/
Configuration
Configuration file: config/dev/applications/pi-hole-values.yaml
Key settings:
- LoadBalancer service for direct DNS and web access
- Persistent storage for configuration (1Gi)
- Resource limits: 200m CPU, 256Mi memory
- External traffic policy: Local (preserves client IPs)
Access
Web Admin Dashboard
| Service | URL | Port |
|---|---|---|
| Admin Panel | http://<LoadBalancer-IP>/admin | 80 |
DNS Service
| Service | Port | Protocol |
|---|---|---|
| DNS | 53 | TCP/UDP |
Configure your devices to use the LoadBalancer IP as their DNS server.
Credentials
Admin Password: Set in config/dev/applications/pi-hole-values.yaml
env:
FTLCONF_webserver_api_password: "your-password-here"
Architecture
Service Configuration
Pi-hole uses a LoadBalancer service (via MetalLB) to expose both DNS and web interface:
service:
type: LoadBalancer
externalTrafficPolicy: Local # Preserves client IPs for stats
The externalTrafficPolicy: Local setting ensures that client IP addresses are preserved in DNS query logs, providing accurate statistics about which devices are making queries.
Storage
- Storage Class: local-path
- Size: 1Gi
- Mount Path:
/etc/pihole
Ports
| Port | Protocol | Purpose |
|---|---|---|
| 53 | TCP/UDP | DNS queries |
| 80 | TCP | Web admin interface |
| 443 | TCP | HTTPS (self-signed) |
Environment Variables
| Variable | Description | Default |
|---|---|---|
TZ | Timezone for logs and stats | UTC |
FTLCONF_webserver_api_password | Admin dashboard password | (required) |
FTLCONF_dns_listeningMode | DNS listening mode | ALL |
Adding Custom Blocklists
- Access the admin dashboard at
http://<LoadBalancer-IP>/admin - Navigate to Group Management → Adlists
- Add new blocklist URLs
- Run Gravity Update to apply changes
Example Blocklists
https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
https://raw.githubusercontent.com/AdguardTeam/AdguardFilters/master/SpywareFilter/sections/servers.txt
Configuring Clients
Option 1: Manual DNS Configuration
Set DNS server on each device to the Pi-hole LoadBalancer IP:
DNS Server: <LoadBalancer-IP>
Option 2: DHCP Configuration
Configure your router's DHCP settings to distribute Pi-hole as the DNS server.
Option 3: Kubernetes Network
For pods within the cluster, create a ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns-custom
namespace: kube-system
data:
pihole.server: |
pihole.ssdk8s.xyz {
forward . <LoadBalancer-IP>
}
Monitoring
Key Metrics
- Total DNS queries
- Queries blocked (percentage)
- Top blocked domains
- Top clients by query count
- DNS cache utilization
Logs
# View pod logs
kubectl logs -n pihole -l app.kubernetes.io/name=pi-hole
# View FTL logs
kubectl exec -n pihole deployment/pi-hole -- tail -f /var/log/pihole/FTL.log
Troubleshooting
Pod Failing Liveness Probes
Issue: Pod restarts due to failed HTTP probes
Solution: Ensure probes are configured to check /admin path, not /
livenessProbe:
httpGet:
path: /admin
port: http
DNS Not Resolving
Check service status:
kubectl get svc -n pihole
kubectl get endpoints -n pihole
Test DNS resolution:
nslookup google.com <LoadBalancer-IP>
dig @<LoadBalancer-IP> google.com
High Memory Usage
Solution: Adjust resource limits in values file:
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
Client IPs Not Showing in Logs
Issue: All queries show same source IP
Solution: Ensure externalTrafficPolicy: Local is set:
kubectl get svc -n pihole -o yaml | grep externalTrafficPolicy
Should return: externalTrafficPolicy: Local
Reset Admin Password
kubectl exec -n pihole deployment/pi-hole -- pihole -a -p
Then set new password via the web interface.
Backup and Restore
Backup Configuration
# Backup PVC contents
kubectl run backup --rm -it --image=alpine --restart=Never -- \
tar czf - -C /mnt pihole > pihole-backup.tar.gz
Restore Configuration
- Stop the deployment:
kubectl scale deployment -n pihole pi-hole --replicas=0 - Restore PVC contents from backup
- Restart deployment:
kubectl scale deployment -n pihole pi-hole --replicas=1
Upgrading
Pi-hole auto-updates its components. To force an update:
- Access admin dashboard
- Go to Settings → Gravity
- Click Update Gravity
For chart upgrades:
helm upgrade pi-hole ./charts/pi-hole -f config/dev/applications/pi-hole-values.yaml -n pihole