# Using pi-hole as your external-dns provider in Kubernetes


![Using pi-hole as your external-dns provider in Kubernetes](https://cdn.hashnode.com/res/hashnode/image/upload/v1714595272003/13ad7284-23a3-4d4f-a3ac-09f77482b524.png?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp align="center")

# **environment assumptions**

* A locally-running Kubernetes cluster
    
* Pi-Hole on the network configured as the primary DNS
    

# what is external-dns?

When you build an [**ingress**](https://kubernetes.io/docs/concepts/services-networking/ingress/) (which is essentially a layer-7 host and path-based load-balancer) in Kubernetes to bring web traffic to a cluster, you specify a `host` name. This creates a load-balancer entry in whatever load balancer you're using. If you're in public cloud, Kubernetes will call cloud load balancer APIs. In my home lab setup, I'm using [`metallb`](https://metallb.universe.tf/) for this purpose. The ingress below listens for requests to `openweb-ui.lan` and sends them to the `http` service (a web UI) called `openweb-ui`.

```basic
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: open-webui
  namespace: openweb-ui
spec:
  ingressClassName: nginx
  rules:
  - host: openweb-ui.lan
    http:
      paths:
      - backend:
          service:
            name: open-webui
            port:
              name: http
        path: /
        pathType: Prefixyaml
```

It reaches out to `metallb` to assign an IP address from a reserved pool. The address below, `192.168.126.50` was handed out by `metallb`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1714591746843/f279ef68-d3be-4d02-8a4e-10669c1cd0a9.png?auto=compress,format&format=webp align="left")

Now that that's in place, devices on my network need to know that this hostname resolves to the `ingress ip`. That's where [`external-dns`](https://github.com/kubernetes-sigs/external-dns) comes in. Typically, `external-dns` is leveraged to write DNS records to providers like Cloudflare, Route53, etc. However, it also supports writing DNS records to your locally-installed `Pi-Hole`!

# what is pi-hole?

It's no secret that tech workers are amongst the biggest users of ad-blocking software, and one of the major players in this space is the venerable [**Pi-Hole**](https://pi-hole.net/).

If you don't know what Pi-Hole is, it's a piece of software originally designed to run on a [**Raspberry Pi**](https://www.raspberrypi.com/) (although it runs anywhere now, even Docker and Kubernetes) that blocks ads at the DNS level. You configure the Pi-Hole to be your DNS provider. When an app or website calls out to a domain associated with the configured [**block list(s)**](https://github.com/topics/pihole-blocklists), Pi-Hole simply responds that the advertising domain is unresolvable, and content from the advertising domain is not shown. All the while, the useful, good, content you were looking for is displayed!

![image showing a list of network resources from Safari Web Inspector, showing an advertising domain not loaded.](https://cdn.hashnode.com/res/hashnode/image/upload/v1714590822512/15ae8897-d37a-4152-9844-0106c916b866.png?auto=compress,format&format=webp align="left")

Notice in the above image that `analytics.js` from `google-analytics.com` isn't loading, thanks to Pi-Hole!

However, the feature of Pi-Hole I'll be discussing in this article is `Local DNS`. We'll be using it to map a DNS record to the ingress IP on a homelab Kubernetes cluster.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1714592083142/e105a185-3b4b-4ad4-930b-2cc071425672.png?auto=compress,format&format=webp align="left")

# installing external-dns

The Helm chart is the best way to install external-dns.

## required information

Collect the following:

* The IP address of your `Pi-Hole` instance (referenced as `piholeipaddress`)
    
* The `admin` credentials for your `Pi-Hole` instance (referenced as `piholeadminpassword`)
    

## add and update repo

```basic
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm update/
```

# create a secret for pi-hole

In this step, we'll create a Kubernetes `Secret` for authenticating to the `Pi-Hole`.

```basic
kubectl create secret generic pihole-password \
--namespace external-dns \
--from-literal EXTERNAL_DNS_PIHOLE_PASSWORD={{piholeadminpassword}}
```

## create values.yaml

Next, create a `values.yaml` to pass configuration values to the Helm chart.

```basic
# https://github.com/kubernetes-sigs/external-dns/blob/master/charts/external-dns/README.md#values
provider:
  name: pihole
# https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/pihole.md#arguments
env: # configured your pi-hole password and ip address
  - name: EXTERNAL_DNS_PIHOLE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: pihole-password
        key: EXTERNAL_DNS_PIHOLE_PASSWORD
  - name: EXTERNAL_DNS_PIHOLE_SERVER
    # make sure NOT to put a trailing slash, as external-dns adds its own
    value: http://{{piholeipaddress}}
```

## install

```basic
helm upgrade --install external-dns external-dns/external-dns \
--namespace external-dns \
--create-namespace \
--values values.yaml
```

## make sure it's working

If you check the deployment logs for `external-dns` , you'll see that `external-dns` has been hard at work creating a DNS record for your `ingress`.

```basic
kubectl logs --namespace external-dns deployments/external-dns external-dns
```

```basic
time="2024-05-01T20:14:10Z" level=info msg="add openweb-ui.lan IN A -> 192.168.126.50"
time="2024-05-01T20:14:10Z" level=warning msg="Skipping unsupported endpoint openweb-ui.lan TXT \"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/openweb-ui/open-webui\""
time="2024-05-01T20:14:10Z" level=warning msg="Skipping unsupported endpoint a-openweb-ui.lan TXT \"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/openweb-ui/open-webui\""
time="2024-05-01T20:15:10Z" level=info msg="All records are already up to date"
```

That's it!

If you have trouble, again make sure you take out any trailing slashes on the `EXTERNAL_DNS_PIHOLE_SERVER` environment variable. And also make sure the IP is correct! Don't ask me how I spent like 20 minutes wondering why `external-dns` wouldn't connect.
