# External-mDNS
External-mDNS advertises exposed Kubernetes Services and Ingresses addresses on a
LAN using multicast DNS ([RFC 6762]).
It is based on and heavily inspired by
[External DNS].
## What It Does
External-mDNS makes Kubernetes resources discoverable on a local network via
multicast DNS without the need for a separate DNS server. It retrieves a list of
resources (Services and Ingresses) from Kubernetes and serves the record to local
clients via multicast DNS.
Hostnames associated with Ingress resources, or exposed services of type
LoadBalancer, will be advertised on the local network.
By default External-mDNS will advertise hostnames for exposed resources in all
namespaces. Use the `-namespace` flag to restrict advertisement to a single
namespace, or `-without-namespace=true` for all namespaces.
DNS records are advertised with the format `..local`.
In addition, hostnames for resources in the `-default-namespace` will also be
advertised with a short name of `.local`.
## Deploying External-mDNS
External-mDNS is configured using argument flags. Most flags can be replaced
with environment variables. For instance, `--record-ttl` could be replaced with
`EXTERNAL_MDNS_RECORD_TTL=60`, or `--namespace kube-system` could be replaced
with `EXTERNAL_MDNS_NAMESPACE=kube-system`.
### Manifest (without RBAC)
```yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-mdns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-mdns
template:
metadata:
labels:
app: external-mdns
spec:
securityContext:
runAsUser: 65534
runAsGroup: 65534
runAsNonRoot: true
hostNetwork: true
serviceAccountName: external-mdns
containers:
- name: external-mdns
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
image: blakec/external-mdns:latest
args:
- -source=ingress
- -source=service
```
### Manifest (with RBAC)
```yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-mdns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: external-mdns
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["list", "watch"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-mdns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-mdns
subjects:
- kind: ServiceAccount
name: external-mdns
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-mdns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-mdns
template:
metadata:
labels:
app: external-mdns
spec:
securityContext:
runAsUser: 65534
runAsGroup: 65534
runAsNonRoot: true
hostNetwork: true
serviceAccountName: external-mdns
containers:
- name: external-mdns
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
image: blakec/external-mdns:latest
args:
- -source=ingress
- -source=service
```
Deploy External-mDNS using `kubectl apply --filename external-mdns.yaml`.
Check that External-mDNS has created the desired DNS records for your advertised
services, and that it points to its load balancer's IP.
Test that the record is resolvable from the local LAN using the appropriate
command for your operating system.
#### BSD/macOS
```console
$ dns-sd -Q example.local a in
DATE: ---Sun 16 Aug 2020---
22:50:37.797 ...STARTING...
Timestamp A/R Flags if Name Type Class Rdata
22:50:37.959 Add 2 4 example.local. Addr IN 192.0.2.10
```
#### Linux
```console
$ getent hosts example.local
192.0.2.10 example.local
```
Or, resolve the hostname using Avahi.
```console
$ avahi-resolve-address -4 --name example.local
example.local 192.0.2.10
```
Note about Linux DNS lookups:
If `/etc/nsswitch.conf` is configured to use the `mdns4_minimal` module,
`libnss-mdns` will reject the request if the request has more than two labels.
Example: example.default.local is rejected.
In order to resolve hostnames that are published from non-default Kubernetes
namespaces, modify `/etc/nsswitch.conf` and replace `mdns4_minimal` with `mdns4`.
Also, create the file `/etc/mdns.allow` and insert the following contents.
```text
# /etc/mdns.allow
.local.
.local
```
Hostnames with more than two labels should now be resolvable.
```console
$ getent hosts example.default.local
192.0.2.10 example.default.local
```
[External DNS]: https://github.com/kubernetes-sigs/external-dns
[RFC 6762]: https://tools.ietf.org/html/rfc6762