Build an ExternalDns with external Bind DNS(En)
Because I want to connect to internal application services within the Kubernetes cluster using FQDN, and I’ve already been using Linux Bind as the primary DNS for the testing environment, hope to meet my requirements under the following conditions:
- If we don’t want to set up a separate DNS server.
- External users can connect to containerized applications using FQDN.(ex. Web)
So I’ve found a well-established project: ExternalDNS. However, many articles primarily use CoreDNS for name resolution, but this approach is only suitable for internal cluster use, allowing internal services to find each other. ExternalDNS, on the other hand, is used to expose services externally, allowing access to Kubernetes cluster internal services through custom FQDNs. The ExternalDNS official website provides instructions for integration with various providers, and it’s actually not difficult. So, let’s get started!
1. What is ExternalDNS?
ExternalDNS allows you to connect external services to resources within a Kubernetes cluster using a single DNS, making it easier to access cluster services from the outside.
ExternalDNS supports registering domain names with various domain services like AWS, Linode, CoreDNS, Bind-DNS, and more. You can find the specific DNS provider integration you need on the respective provider pages in the official GitHub repository.
https://github.com/kubernetes-sigs/external-dns
To get details about external domain name support, check the provider directory for specific DNS providers.
2. Deployment
Just a heads-up, when working with the Bind provider, make sure to follow the RFC2316 rule. We’ll be using the following domain names :
- apps.test.example.poc: Used for internal application services within the Kubernetes.
- test.example.poc : General domain
P.S. It’s a good idea to have a load balancer, like MetalLB (I’ll explain more later)
# Generate certificates
[master]# tsig-keygen -a hmac-sha256 externaldns
key "externaldns" {
algorithm hmac-sha256;
secret "BL4uv5x5Pd0DWbioNS6BvqG2fWAM/F3ZQcyic2q+SwE=";
};
# Edit named.conf
key "externaldns" {
algorithm hmac-sha256;
secret "BL4uv5x5Pd0DWbioNS6BvqG2fWAM/F3ZQcyic2q+SwE=";
};
zone "test.example.poc" IN {
type master;
file "named.test.example.poc.zone";
allow-transfter {
key "externaldns";
};
update-policy {
grant externaldns zonesub ANY;
};
};
# Create namespace
[master]# kubectl create externaldns
# Create clusterrole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-dns
namespace: external-dns
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- pods
- nodes
verbs:
- get
- watch
- list
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- networking.istio.io
resources:
- gateways
- virtualservices
verbs:
- get
- watch
- list
# Create service account
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
namespace: external-dns
# Create rolebinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
namespace: external-dns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: external-dns
# Create deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
namespace: external-dns
spec:
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.7.6
args:
- --registry=txt
- --txt-prefix=external-dns-
- --txt-owner-id=k8s
- --provider=rfc2136
- --rfc2136-host=10.107.88.9
- --rfc2136-port=53
- --rfc2136-zone=test.example.poc
- --rfc2136-tsig-secret=BL4uv5x5Pd0DWbioNS6BvqG2fWAM/F3ZQcyic2q+SwE=
- --rfc2136-tsig-secret-alg=hmac-sha256
- --rfc2136-tsig-keyname=externaldns
- --rfc2136-tsig-axfr
- --source=service
- --source=ingress
- --domain-filter=apps.test.example.poc
- --interval=30s
- --log-level=debug
# Run all YAMLs
[master]# kubectl create -f clusterrole.yaml -n external-dns
[master]# kubectl create -f ac.yaml -n external-dns
[master]# kubectl create -f clusterrolebinding.yaml -n external-dns
[master]# kubectl create -f deployment.yaml -n external-dns
# Verify service/ingress
[master]# kubectl run nginx --image=nginx --port=80
[master]# kubectl expose pod nginx --port=80 --target-port=80 --type=LoadBalancer
[master]# kubectl get svc -n external-dns
[[master]# kubectl annotate service nginx "external-dns.alpha.kubernetes.io/hostname=nginx.apps.test.example.poc."
[master]# nslookup nginx.apps.test.example.poc 10.107.88.9
In summary, we’ve set up on-premises DNS services. ExternalDNS is a project that extends from Kube-DNS specifically for external DNS services, and it’s supported on many well-known platforms.
In a production environment, it’s advisable to decide on an FQDN solution based on the platform you’re using. This approach aligns better with the actual requirements of the environment. But for small-scale or lab use, ExternalDNS is still a great option.
in the future, I’ll explain how ExternalDNS actually works to everyone. :)