ddns-updater on Kubernetes
After years of enjoying a static IPv4 address for free, migrating to a new ISP required either paying a monthly fee for such a priviledge... or simply running a Dynamic DNS service to keep the relevant domains pointing to the correct IPv4 address as it updated.
DDNS Updater
The service of choice was the Lightweight universal DDNS Updater program, available for Docker at qmcgaw/ddns-updater and fairly simple to run in Kubernetes.
Create a ddns-updater directory and download the base manifest files:
$ curl -O https://raw.githubusercontent.com/qdm12/ddns-updater/master/k8s/base/deployment.yaml
$ curl -O https://raw.githubusercontent.com/qdm12/ddns-updater/master/k8s/base/secret-config.yaml
$ curl -O https://raw.githubusercontent.com/qdm12/ddns-updater/master/k8s/base/service.yaml
$ curl -O https://raw.githubusercontent.com/qdm12/ddns-updater/master/k8s/base/kustomization.yaml
Then edit secret-config.yaml as explained in the DDNS Updater's README
Configuration, following the example provided for the relevant DNS provider, e.g.
Porkbun:
The configuration can be added to the CONFIG variable in secret-config.yaml
| ddns-updater/secret-config.yaml | |
|---|---|
To make the service's web UI externally accessible, securely and resilient
to DNS records being out of date after the IPv4 address changes, add the
following ingress.yaml (based on
k8s/overlay/with-ingress-tls-cert-manager/ingress.yaml) to enable access through a
Cloudflare Tunnel
(like the one previously setup to access Home Assistant):
With all the above, the service can be started by applying the deployment:
$ kubectl apply -k .
namespace/ddns-updater created
secret/ddns-updater-config created
service/ddns-updater-svc created
deployment.apps/ddns-updater created
ingress.networking.k8s.io/ddns-updater-nginx created
Once the services have been running for a few minutes, the web UI will be accessible at https://ddns-updater.very-very-dark-gray.top/ for those users authorized to access it by the Cloudflare Tunnel policies.
!!! note the above does not specify a namespace so everything is in the
default namespace.
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/cm-acme-http-solver-zr4lm 1/1 Running 0 49m
pod/ddns-updater-5cbcfc865d-8jrqj 1/1 Running 0 49m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cm-acme-http-solver-drlkv NodePort 10.110.215.98 <none> 8089:32080/TCP 49m
service/ddns-updater-svc ClusterIP 10.104.110.181 <none> 80/TCP 49m
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 152d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ddns-updater 1/1 1 1 49m
NAME DESIRED CURRENT READY AGE
replicaset.apps/ddns-updater-5cbcfc865d 1 1 1 49m
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
cm-acme-http-solver-fqqw4 <none> ddns-updater.very-very-dark-gray.top 192.168.0.171 80 49m
ddns-updater-nginx nginx ddns-updater.very-very-dark-gray.top 192.168.0.171 80, 443 49m
(Why not) DDCLIENT
DDCLIENT seemd at first like the best option, but would not have worked in this case due to Issue #569: porkbun: Support Wildcard DNS entries.