Skip to content

External DNS with Kubernetes

This guide explains how to integrate Kubernetes External-DNS with the bnerd CloudAPI DNS service.

Overview

External-DNS automatically creates DNS records from Kubernetes Ingress and Service resources. When combined with the bnerd DNS API, your Kubernetes workloads can automatically register their DNS records.

Prerequisites

  • A Kubernetes cluster with kubectl configured
  • A verified domain in bnerd (see Domain Verification)
  • A DNS zone created for your domain: bnerd dns zones create example.com
  • An API token with DNS management permissions

Step 1: Create a Static Access Token

External-DNS needs API credentials to manage DNS records. Create a dedicated token for this purpose.

Store the token as a Kubernetes Secret:

kubectl create secret generic bnerd-dns-credentials \
  --namespace external-dns \
  --from-literal=token=YOUR_API_TOKEN \
  --from-literal=org-id=YOUR_ORG_ID

Step 2: Deploy External-DNS

Create the External-DNS deployment configured for the bnerd DNS provider (RFC2136/PowerDNS compatible):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: external-dns
spec:
  replicas: 1
  selector:
    matchLabels:
      app: external-dns
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      containers:
        - name: external-dns
          image: registry.k8s.io/external-dns/external-dns:v0.14.0
          args:
            - --source=ingress
            - --source=service
            - --provider=pdns
            - --pdns-server=https://api.bnerd.net
            - --pdns-api-key=$(BNERD_TOKEN)
            - --domain-filter=example.com
            - --txt-owner-id=my-cluster
            - --policy=sync
            - --interval=1m
          env:
            - name: BNERD_TOKEN
              valueFrom:
                secretKeyRef:
                  name: bnerd-dns-credentials
                  key: token

Domain filter

Set --domain-filter to your verified domain to prevent External-DNS from managing records outside your zone.

Step 3: Test with an Ingress

Create a test Ingress to verify External-DNS creates the DNS record:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-app
  annotations:
    external-dns.alpha.kubernetes.io/hostname: test.example.com
spec:
  rules:
    - host: test.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: test-app
                port:
                  number: 80

After applying, check that the record was created:

bnerd dns records list <zone-id>

Troubleshooting

Records not being created:

  1. Check External-DNS logs: kubectl logs -n external-dns -l app=external-dns
  2. Verify the API token is valid: bnerd whoami
  3. Ensure the domain filter matches your zone
  4. Check that the zone exists: bnerd dns zones list

Permission denied errors:

  • Verify the token has DNS management permissions
  • Check the org-id matches the zone's organization

Duplicate records:

  • Set a unique --txt-owner-id per cluster to prevent conflicts
  • Use --policy=sync for full reconciliation (creates and deletes)

Verifying with bnerd CLI

# List zones to find your zone ID
bnerd dns zones list

# List records in the zone
bnerd dns records list <zone-id>

# Check a specific record
bnerd dns zones get <zone-id> -o json | jq '.rrsets[] | select(.name == "test.example.com.")'